Przejdź do głównej zawartości

Tworzenie wtyczki

Teraz, gdy wyizolowaliśmy nasze dane RGB, możemy zacząć tworzyć naszą wtyczkę.

Aby utworzyć wtyczkę, otwieramy edytor tekstu i wklejamy do niego poniższy tekst.

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 "";
}

Powyższy tekst to podstawowy szkielet wtyczki urządzenia.

Zaczynamy od wypełnienia pól na górze wtyczki informacjami o naszym urządzeniu.

Możemy wypełnić pole nazwy nazwą urządzenia.

Aby znaleźć ID dostawcy i ID produktu, musimy najpierw otworzyć menu ustawień SignalRGB za pomocą ikony koła zębatego w lewym dolnym rogu.

Teraz musimy przejść do strony informacji o urządzeniu.

Szukamy VendorID i ProductID dla urządzenia, które implementujemy. W tym przypadku jest to Corsair Scimitar Pro. ID dostawcy Scimitara to 0x1b1c, a ID produktu to 0x1b3e.

Teraz, gdy mamy ID dostawcy i produktu, możemy wypełnić te pola w wtyczce.

W polu Publisher możesz wpisać swoje własne imię!

Teraz wypełniliśmy wszystkie pola, które możemy w tej chwili wypełnić.

Oto nasz przykład dla Scimitar Pro z wypełnionymi polami.

Następnie musimy stworzyć funkcję wysyłania danych kolorów do naszego urządzenia. Zaczynamy od stworzenia prostej funkcji jak poniższa:

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

Następnie musimy zacząć wypełniać nasz pakiet danymi, co robimy używając danych z jednego z naszych oznaczonych pakietów RGB.

  • UWAGA: To urządzenie jest zero-paddingowane. Oznacza to, że musimy przesunąć wszystkie bajty o 1 pozycję w górę. Przeczytaj więcej o zero-paddingu.

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

Zaczynamy od wypełnienia danych nagłówka dla pakietu jak pokazano powyżej. Zatrzymujemy się na pozycji 4, ponieważ pozycja 5 jest naszym pierwszym bajtem danych związanych z RGB.

Następnie musimy stworzyć nasz system wypełniania kolorami. Jest kilka różnych sposobów, aby to zrobić. Używana metoda zależy od struktury pakietu urządzenia. Oto kilka różnych przykładów pakietów kolorów:

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);
}

Trzy powyższe przykłady są odpowiednie dla różnych struktur pakietów. Funkcja sendZone jest odpowiednia dla urządzeń używających oddzielnego pakietu dla każdej LED. Funkcja sendPacket jest bardziej odpowiednia dla urządzeń wysyłających wiele LED-ów kolejno w jednym pakiecie. Funkcja sendColors jest odpowiednia dla urządzeń z wieloma LED-ami w pakiecie, ale nie kolejno. W naszym przypadku używamy funkcji 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);
}

Aby poprawnie skonfigurować funkcję sendColors, musimy ustalić ID stref naszego urządzenia. Patrząc ponownie na nagranie pakietów, widzimy, że kolejność stref wydaje się być 2,4,5,1,3, jak pokazano poniżej. Zauważ, że dodaliśmy 5. strefę, ponieważ wydaje się, że możemy również adresować LED DPI.

Teraz, gdy ustaliliśmy nasze ID stref, musimy znaleźć przesunięcia dla naszego zone_idx. Nasza pierwsza strefa znajduje się na packet[4], a druga na packet[8]. Oznacza to, że nasz zone_idx musi być mnożony przez 4 za każdym razem, aby przejść do nowej LED. Musimy też określić, o ile pozycji przesunąć dane RGB. Ponieważ nasza pierwsza strefa znajduje się na packet[5], musimy przesunąć nasz pakiet tylko o 5 bajtów, jak widać poniżej.

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);
}

Teraz, gdy dodaliśmy wszystko, co musi być w naszym pakiecie, musimy określić długość pakietu. Aby znaleźć długość pakietu, wystarczy sprawdzić, jak długie są nasze dane z Wireshark. W naszym przykładzie widzimy, że dane mają w tym przypadku 64 bajty.

  • UWAGA: To urządzenie jest zero-paddingowane, co oznacza, że musimy uczynić długość zapisu o jeden dłuższą niż w nagraniu Wireshark.

Teraz, gdy znamy długość naszych danych, wystarczy ustawić długość device.write na 65 bajtów, jak pokazano poniżej.

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);
}

Teraz, gdy mamy skonfigurowany nasz pakiet RGB, musimy skonfigurować nasze LED-y i wybrać punkty końcowe naszego urządzenia.

Aby skonfigurować nasze LED-y, musimy dodać odpowiednią liczbę LED-ów do naszych vLedNames i vLedPositions. W naszym przypadku musimy dodać cztery LED-y do każdego, jak pokazano poniżej.

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

Na razie nadajemy tym czterem LED-om podstawowe przypisania, ponieważ jeszcze nie wiemy, gdzie fizycznie te LED-y znajdują się na urządzeniu w stosunku do ich przypisań w SignalRGB.

Teraz, gdy przypisaliśmy nasze LED-y, musimy ustawić rozmiar naszego urządzenia. Rozmiar naszego urządzenia musi być o jeden większy niż nasze najdalsze LED-y w obu kierunkach. W tym przypadku rozmiar powinien być [5,1], ponieważ nasza najdalej położona LED znajduje się na [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]; }

Następną rzeczą, którą musimy ustalić, jest punkt końcowy naszego urządzenia.