ข้ามไปยังเนื้อหา

การสร้างปลั๊กอิน

เมื่อเราแยกข้อมูล 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 "";
}

ข้อความข้างต้นคือโครงร่างพื้นฐานของปลั๊กอินอุปกรณ์

เราจะเริ่มจากการกรอกฟิลด์ที่ส่วนบนของปลั๊กอินด้วยข้อมูลของอุปกรณ์

เราสามารถกรอกฟิลด์ชื่อด้วยชื่อของอุปกรณ์ได้

ในการค้นหา 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 ที่เราทำเครื่องหมายไว้

  • หมายเหตุ: อุปกรณ์นี้ใช้ zero padding ซึ่งหมายความว่าเราต้องเลื่อนไบต์ทั้งหมดขึ้นไป 1 ตำแหน่ง เรียนรู้เกี่ยวกับ zero padding ได้ที่นี่

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 เหมาะกับอุปกรณ์ที่ใช้แพ็กเก็ตแยกสำหรับ LED แต่ละดวง ฟังก์ชัน sendPacket เหมาะกับอุปกรณ์ที่ส่ง LED หลายดวงเรียงต่อกันภายในแพ็กเก็ตเดียว ฟังก์ชัน sendColors เหมาะกับอุปกรณ์ที่มี LED หลายดวงในแพ็กเก็ตเดียว แต่ไม่ได้เรียงต่อกันโดยตรง ในกรณีของเรา เราจะใช้ฟังก์ชัน 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 เนื่องจากดูเหมือนว่าเราสามารถควบคุม LED ของ DPI ได้ด้วย

เมื่อเราหา Zone ID ได้แล้ว เราต้องหาออฟเซ็ตสำหรับ zone_idx โซนแรกอยู่ที่ packet[4] และโซนที่สองอยู่ที่ packet[8] ซึ่งหมายความว่าต้องคูณ zone_idx ด้วย 4 ทุกครั้งเพื่อไปยัง LED ถัดไป เรายังต้องหาด้วยว่าจะเลื่อนข้อมูล 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 ไบต์

  • หมายเหตุ: อุปกรณ์นี้ใช้ zero padding ซึ่งหมายความว่าเราต้องกำหนดความยาวการเขียนให้ยาวกว่าที่แสดงในการดักจับของ 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 เรียบร้อยแล้ว เราต้องตั้งค่า LED และเลือกเอนด์พอยต์ของอุปกรณ์

ในการตั้งค่า LED เราต้องเพิ่มจำนวน LED ที่ถูกต้องลงใน vLedNames และ vLedPositions ในกรณีของเรา เราต้องเพิ่ม LED อีกสี่ดวงในแต่ละรายการ ดังที่แสดงด้านล่าง

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

ตอนนี้เรากำหนดการแมปพื้นฐานให้กับ LED ทั้งสี่ดวงนี้ไปก่อน เนื่องจากเรายังไม่ทราบว่า LED เหล่านี้อยู่ตำแหน่งใดบนอุปกรณ์จริงเมื่อเทียบกับการแมปภายใน SignalRGB

เมื่อเราแมป LED แล้ว เราต้องตั้งค่าขนาดของอุปกรณ์ ขนาดของอุปกรณ์ต้องใหญ่กว่า LED ที่อยู่ไกลที่สุดหนึ่งหน่วยในทั้งสองทิศทาง ในกรณีของเรา ขนาดต้องเป็น [5,1] เนื่องจาก LED ที่อยู่ไกลที่สุดอยู่ที่ [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]; }

สิ่งต่อไปที่เราต้องหาคือเอนด์พอยต์ของอุปกรณ์