Перейти к содержимому

Создание плагина

Теперь, когда мы выделили наши RGB-данные, можно приступать к созданию плагина.

Для начала откройте текстовый редактор и вставьте приведённый ниже текст.

export function Name() { return ""; }
export function VendorId() { return ; }
export function ProductId() { return ; }
export function Publisher() { return ""; }
export function Documentation(){ return "troubleshooting/brand"; }
export function Size() { return [1,1]; }
export function ControllableParameters() {
return [
{"property":"shutdownColor", "group":"lighting", "label":"Shutdown Color", "min":"0", "max":"360", "type":"color", "default":"009bde"},
{"property":"LightingMode", "group":"lighting", "label":"Lighting Mode", "type":"combobox", "values":["Canvas", "Forced"], "default":"Canvas"},
{"property":"forcedColor", "group":"lighting", "label":"Forced Color", "min":"0", "max":"360", "type":"color", "default":"009bde"},
];
}
export function Initialize() {
}
var vLedNames = [ "Led 1" ];
var vLedPositions = [ [0,0] ];
export function LedNames() {
}
export function LedPositions() {
}
export function Render() {
}
export function Shutdown() {
}
function hexToRgb(hex) {
let result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
let colors = [];
colors[0] = parseInt(result[1], 16);
colors[1] = parseInt(result[2], 16);
colors[2] = parseInt(result[3], 16);
return colors;
}
export function Validate(endpoint) {
return endpoint.interface === 0 && endpoint.usage === 0 && endpoint.usage_page === 0;
}
export function ImageUrl() {
return "";
}

Приведённый выше текст — базовая структура плагина устройства.

Начнём с заполнения полей в верхней части плагина информацией об устройстве.

Заполним поле name именем устройства.

Для поиска Vendor ID и Product ID необходимо сначала открыть меню настроек SignalRGB с помощью значка шестерёнки в нижнем левом углу.

Теперь перейдите на страницу «Информация об устройстве».

Нам нужны VendorID и ProductID для реализуемого устройства. В данном случае это Corsair Scimitar Pro. Vendor ID Scimitar — 0x1b1c, его Product ID — 0x1b3e.

Теперь, когда мы нашли Vendor ID и Product ID, заполним эти поля в плагине.

В поле Publisher можно указать своё имя!

На данный момент мы заполнили все поля, которые можем.

Вот наш пример для Scimitar Pro с заполненными полями.

Далее необходимо создать функцию для отправки цветовых данных на устройство. Начнём с простой функции:

function sendColors(shutdown = false)
{
let packet = [];
}

Теперь нужно начать заполнять пакет данными, используя данные из одного из помеченных RGB-пакетов.

  • ПРИМЕЧАНИЕ: Это устройство использует нулевое дополнение. Это означает, что все байты нужно сдвинуть на 1 позицию. Узнайте о нулевом дополнении здесь.

function sendColors(shutdown = false)
{
let packet = [];
packet[0] = 0x00;
packet[1] = 0x07;
packet[2] = 0x22;
packet[3] = 0x05;
packet[4] = 0x01;
}

Заполняем данные заголовка пакета, как показано выше. Останавливаемся на позиции 4, так как позиция 5 — первый байт RGB-данных.

Далее нужно создать систему заполнения цветов. Существует несколько способов её реализации, и метод зависит от структуры пакета устройства. Вот несколько различных примеров цветовых пакетов:

function sendZone(zone, shutdown = false)
{
let packet = [];
packet[0] = LongMessage;
packet[1] = ConnectionMode;
packet[2] = RGBFeatureID;
packet[3] = 0x30;
packet[4] = zone;
packet[5] = 0x01;
var iX = vLedPositions[zone][0];
var iY = vLedPositions[zone][1];
var color;
if(shutdown)
{
color = hexToRgb(shutdownColor);
}
else if (LightingMode == "Forced")
{
color = hexToRgb(forcedColor);
}
else
{
color = device.color(iX, iY);
}
packet[6] = color[0];
packet[7] = color[1];
packet[8] = color[2];
packet[9] = 0x02;
device.write(packet, 120);
}
function SendPacket(shutdown = false)
{
let packet = [];
packet[0] = 0x00;
packet[1] = 0x00;
packet[2] = 0x1F;
packet[3] = 0x00;
packet[4] = 0x00;
packet[5] = 0x00;
packet[6] = 0x41;
packet[7] = 0x0F;
packet[8] = 0x03;
packet[13] = 0x13;
for(let iIdx = 0; iIdx < vLedPositions.length; iIdx++)
{
let iPxX = vLedPositions[iIdx][0];
let iPxY = vLedPositions[iIdx][1];
var color;
if(shutdown)
{
color = hexToRgb(shutdownColor);
}
else if (LightingMode === "Forced")
{
color = hexToRgb(forcedColor);
}
else
{
color = device.color(iPxX, iPxY);
}
let iLedIdx = (iIdx*3) + 14;
packet[iLedIdx] = color[0];
packet[iLedIdx+1] = color[1];
packet[iLedIdx+2] = color[2];
}
device.write(packet, 120);
}
function sendColors(shutdown = false){
let packet = [];
packet[0x00] = 0x00;
packet[0x01] = 0x08;
packet[0x02] = 0x12;
packet[0x03] = 0x05;
packet[0x04] = 0x01;
let zoneId = [1, 2, 3, 4, 5];
for(let zone_idx = 0; zone_idx < vLedPositions.length; zone_idx++) {
let iX = vLedPositions[zone_idx][0];
let iY = vLedPositions[zone_idx][1];
var col;
if(shutdown){
col = hexToRgb(shutdownColor);
}else if (LightingMode === "Forced") {
col = hexToRgb(forcedColor);
}else{
col = device.color(iX, iY);
}
packet[(zone_idx * 4) + 2] = zoneId[zone_idx];
packet[(zone_idx * 4) + 3] = col[0];
packet[(zone_idx * 4) + 4] = col[1];
packet[(zone_idx * 4) + 5] = col[2];
}
device.write(packet, 120);
}

Три приведённых выше примера подходят для разных структур пакетов. Функция sendZone хороша для устройств, использующих отдельный пакет для каждого светодиода. Функция SendPacket больше подходит для устройств, отправляющих несколько светодиодов подряд в одном пакете. Функция sendColors подходит для устройств с несколькими светодиодами в пакете, но не идущими подряд. В нашем случае мы будем использовать функцию sendColors.

function sendColors(shutdown = false)
{
let packet = [];
packet[0] = 0x00;
packet[1] = 0x07;
packet[2] = 0x22;
packet[3] = 0x05;
packet[4] = 0x01;
let zoneId = [2, 4, 5, 1, 3];
for(let zone_idx = 0; zone_idx < vLedPositions.length; zone_idx++) {
let iX = vLedPositions[zone_idx][0];
let iY = vLedPositions[zone_idx][1];
var col;
if(shutdown){
col = hexToRgb(shutdownColor);
}else if (LightingMode === "Forced") {
col = hexToRgb(forcedColor);
}else{
col = device.color(iX, iY);
}
packet[(zone_idx * 1) + 2] = zoneId[zone_idx];
packet[(zone_idx * 1) + 3] = col[0];
packet[(zone_idx * 1) + 4] = col[1];
packet[(zone_idx * 1) + 5] = col[2];
}
packet[21] = 0xff;
packet[22] = 0xff;
packet[23] = 0xff;
device.write(packet, 120);
}

Для правильной настройки функции sendColors необходимо выяснить Zone ID устройства. Снова глядя на захват пакетов, видим, что порядок зон — 2, 4, 5, 1, 3, как показано ниже. Заметим, что мы добавили 5-ю зону: похоже, мы также можем адресовать светодиод DPI.

Определив Zone ID, необходимо выяснить смещения для zone_idx. Первая зона находится в packet[4], вторая — в packet[8]. Это означает, что zone_idx нужно умножать на 4 при каждом переходе к новому светодиоду. Также нужно выяснить смещение RGB-данных. Поскольку первая зона находится в packet[5], просто нужно сместить пакет на 5 байт, как показано ниже.

function sendColors(shutdown = false)
{
let packet = [];
packet[0] = 0x00;
packet[1] = 0x07;
packet[2] = 0x22;
packet[3] = 0x05;
packet[4] = 0x01;
let zoneId = [2, 4, 5, 1, 3];
for(let zone_idx = 0; zone_idx < vLedPositions.length; zone_idx++) {
let iX = vLedPositions[zone_idx][0];
let iY = vLedPositions[zone_idx][1];
var col;
if(shutdown){
col = hexToRgb(shutdownColor);
}else if (LightingMode === "Forced") {
col = hexToRgb(forcedColor);
}else{
col = device.color(iX, iY);
}
packet[(zone_idx * 4) + 5] = zoneId[zone_idx];
packet[(zone_idx * 4) + 6] = col[0];
packet[(zone_idx * 4) + 7] = col[1];
packet[(zone_idx * 4) + 8] = col[2];
}
device.write(packet, 120);
}

Добавив всё необходимое в пакет, нужно найти его длину. Просто посмотрите на длину данных в Wireshark. В нашем примере длина данных — 64 байта.

  • ПРИМЕЧАНИЕ: Это устройство использует нулевое дополнение, поэтому длина записи должна быть на единицу больше, чем в захвате Wireshark.

Зная длину данных, устанавливаем длину device.write в 65 байт, как показано ниже.

function sendColors(shutdown = false)
{
let packet = [];
packet[0] = 0x00;
packet[1] = 0x07;
packet[2] = 0x22;
packet[3] = 0x05;
packet[4] = 0x01;
let zoneId = [2, 4, 5, 1, 3];
for(let zone_idx = 0; zone_idx < vLedPositions.length; zone_idx++) {
let iX = vLedPositions[zone_idx][0];
let iY = vLedPositions[zone_idx][1];
var col;
if(shutdown){
col = hexToRgb(shutdownColor);
}else if (LightingMode === "Forced") {
col = hexToRgb(forcedColor);
}else{
col = device.color(iX, iY);
}
packet[(zone_idx * 4) + 5] = zoneId[zone_idx];
packet[(zone_idx * 4) + 6] = col[0];
packet[(zone_idx * 4) + 7] = col[1];
packet[(zone_idx * 4) + 8] = col[2];
}
device.write(packet, 65);
}

Теперь, когда RGB-пакет настроен, нужно настроить светодиоды и выбрать конечные точки устройства.

Для настройки светодиодов необходимо добавить правильное количество светодиодов в vLedNames и vLedPositions. В нашем случае нужно добавить ещё четыре светодиода к каждому, как показано ниже.

var vLedNames = [ "Led 1", "Led 2", "Led 3", "Led 4", "Led 5" ];
var vLedPositions = [ [0,0], [1,0], [2,0], [3,0], [4,0] ];

На данный момент даём этим четырём светодиодам базовые привязки, так как не знаем, где эти светодиоды физически расположены на устройстве относительно их позиций в SignalRGB.

Теперь, когда светодиоды нанесены на карту, нужно установить размер устройства. Размер устройства должен быть на единицу больше дальнейшего светодиода в обоих направлениях. В нашем случае размер должен быть [5,1], так как дальнейший светодиод находится в [4,0].

export function Name() { return "Corsair Scimitar Pro"; }
export function VendorId() { return 0x1b1c; }
export function ProductId() { return 0x1B3E; }
export function Publisher() { return "WhirlwindFX"; }
export function Documentation(){ return "troubleshooting/corsair"; }
export function Size() { return [5,1]; }

Следующее — выяснить конечную точку устройства.