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

การสื่อสารขั้นสูง

หน้านี้ครอบคลุมวิธีการสื่อสาร USB ขั้นสูง พอร์ตซีเรียล และซ็อกเก็ตเครือข่าย สำหรับการเขียนและอ่านข้อมูลพื้นฐาน โปรดดู การเขียนและการอ่าน

การเข้าใจความแตกต่างระหว่างประเภทการถ่ายโอน USB จะช่วยให้คุณเลือกวิธีที่เหมาะสมและดีบักข้อผิดพลาดที่ไม่คาดคิดได้

ประเภทเมธอดขนาดโดยทั่วไปกรณีการใช้งาน
Interruptdevice.write() / device.read()3–64 ไบต์ข้อมูล RGB, คำสั่งขนาดเล็ก, อินพุตคีย์บอร์ด/เมาส์
Bulkdevice.write() / device.read()64–1025 ไบต์ภาพ LCD, การอัปเดตเฟิร์มแวร์, บล็อกการตั้งค่าขนาดใหญ่
Controldevice.send_report() / device.get_report() / device.control_transfer()32–192 ไบต์การยืนยันตัวตน, HID feature report, การกำหนดค่าอุปกรณ์

ฟังก์ชัน device.write() และ device.read() เดียวกันนี้ใช้ได้ทั้งการถ่ายโอนแบบ interrupt และ bulk — ไดรเวอร์ USB จะกำหนดประเภทจากเอนด์พอยต์และขนาดแพ็กเก็ต


ส่งการถ่ายโอนแบบ control ประเภท HID GET_INPUT_REPORT คล้ายกับ device.get_report() แต่ร้องขอ Input report โดยเฉพาะแทนที่จะเป็น Feature report ใช้เมธอดนี้เมื่อ get_report() ส่งคืนข้อมูลที่ไม่ถูกต้อง เนื่องจากอุปกรณ์แยกประเภท Input report และ Feature report ออกจากกัน

พารามิเตอร์ชนิดคำอธิบายตัวอย่าง
DataArrayอาร์เรย์ 1 มิติข้อมูลคำขอ report[0x01]
LengthIntขนาด report ที่คาดหวังเป็นไบต์64
ค่าที่ส่งคืนชนิดคำอธิบาย
DataArrayอาร์เรย์ 1 มิติไบต์ที่ได้รับจากอุปกรณ์
var inputData = device.input_report([0x01], 64);

ทำการถ่ายโอนแบบ bulk หรือ interrupt โดยตรงไปยังเอนด์พอยต์ USB ที่ระบุ ต่างจาก device.write() และ device.read() ที่ใช้เอนด์พอยต์ที่เลือกไว้ด้วย device.set_endpoint() เมธอดนี้ให้คุณระบุเอนด์พอยต์ใดก็ได้ตามแอดเดรส

  • แอดเดรสเอนด์พอยต์ที่มีค่า 0x80 ขึ้นไปคือ IN (อุปกรณ์ → โฮสต์, อ่าน)
  • แอดเดรสเอนด์พอยต์ที่ต่ำกว่า 0x80 คือ OUT (โฮสต์ → อุปกรณ์, เขียน)
พารามิเตอร์ชนิดคำอธิบายตัวอย่าง
EndpointHexแอดเดรสเอนด์พอยต์ USB0x81
DataArrayอาร์เรย์ 1 มิติข้อมูลที่จะส่ง (OUT) หรืออาร์เรย์ว่าง (IN)[0x01, 0x02]
LengthIntขนาดการถ่ายโอนเป็นไบต์64
TimeoutIntจำนวนมิลลิวินาทีก่อนยกเลิก100
ค่าที่ส่งคืนชนิดคำอธิบาย
DataArrayอาร์เรย์ 1 มิติไบต์ที่ได้รับ (การถ่ายโอนแบบ IN) หรือว่างเปล่า
// Write to endpoint 0x01
device.bulk_transfer(0x01, [0x00, 0x01, 0x02], 3, 100);
// Read from endpoint 0x81
var response = device.bulk_transfer(0x81, [], 64, 100);
// Large bulk write (e.g. LCD image data)
device.bulk_transfer(0x02, imageData, 1024, 500);

การถ่ายโอนแบบ control ของ USB ระดับต่ำ ใช้สำหรับการแฮนด์เชกเพื่อยืนยันตัวตน โปรโตคอลเฉพาะของผู้ผลิต และกรณีที่เมธอด HID ไม่เพียงพอ นี่คือ การถ่ายโอนแบบ control ไม่ใช่การถ่ายโอนแบบ bulk

พารามิเตอร์ชนิดคำอธิบายตัวอย่าง
RequestTypeHexบิตแมปประเภทคำขอ USB (ทิศทาง, ประเภท, ผู้รับ)0xA1
RequestHexรหัสคำขอ (เฉพาะอุปกรณ์)0x01
ValueHexฟิลด์ค่า0x0100
IndexIntดัชนีอินเทอร์เฟซหรือเอนด์พอยต์0x00
DataArrayอาร์เรย์ 1 มิติข้อมูลที่จะส่ง (โฮสต์ไปยังอุปกรณ์) หรือว่างเปล่า[]
LengthIntความยาวการตอบกลับที่คาดหวัง (อุปกรณ์ไปยังโฮสต์)192
TimeoutIntจำนวนมิลลิวินาทีก่อนยกเลิก1000
ค่าที่ส่งคืนชนิดคำอธิบาย
DataArrayอาร์เรย์ 1 มิติไบต์ที่ได้รับ (การถ่ายโอนจากอุปกรณ์ไปยังโฮสต์)

ค่า RequestType ที่ใช้บ่อย:

ค่าทิศทางประเภทผู้รับกรณีการใช้งาน
0x21โฮสต์ → อุปกรณ์ClassInterfaceHID SET_REPORT
0xA1อุปกรณ์ → โฮสต์ClassInterfaceHID GET_REPORT
0x80อุปกรณ์ → โฮสต์StandardDeviceการอ่าน descriptor
0x00โฮสต์ → อุปกรณ์StandardDeviceคำสั่งมาตรฐาน
// Read authentication token (device → host, class, interface)
var token = device.control_transfer(
0xA1, // Device-to-host, class, interface
0x01, // GET_REPORT
0x0100, // Report type (Feature) + report ID
0x00, // Interface 0
[], // No outbound data
192, // Expect 192 bytes back
1000 // 1 second timeout
);
// Send a feature report (host → device)
device.control_transfer(0x21, 0x09, 0x0300, 0, [0x03, 0x08, 0x32], 0, 500);

สำหรับอุปกรณ์ที่ใช้พอร์ตซีเรียล/COM ให้นำเข้าโมดูล serial และตั้งค่า Type() ของปลั๊กอินเป็น "serial"

import { serial } from "@SignalRGB/serial";
export function Type() { return "serial"; }
serial.connect({
baudRate: 115200, // Default: 115200
parity: "None", // "None", "Even", "Odd", "Space", "Mark"
dataBits: 8, // 5, 6, 7, or 8
stopBits: "One" // "One", "OneAndHalf", "Two"
});
เมธอดคำอธิบายค่าที่ส่งคืน
serial.connect(options?)เปิดพอร์ตซีเรียลbool
serial.disconnect()ปิดพอร์ตซีเรียลvoid
serial.isConnected()ตรวจสอบสถานะการเชื่อมต่อbool
serial.write(data)ส่งข้อมูลจำนวนไบต์ที่เขียน
serial.read(maxBytes?, timeoutMs?)อ่านไบต์ที่มีอยู่ (ค่าเริ่มต้น: ทั้งหมด, หมดเวลา 1000ms)อาร์เรย์ไบต์
serial.readAll()อ่านไบต์ที่มีอยู่ทั้งหมดทันทีอาร์เรย์ไบต์
serial.availablePorts()แสดงรายการพอร์ต COM ที่มีอยู่อาร์เรย์
serial.getPortName()ชื่อพอร์ตปัจจุบันสตริง
serial.getBaudRate()baud rate ปัจจุบันตัวเลข
serial.getDeviceInfo()ข้อมูลพอร์ตพร้อม VID, PID ฯลฯอ็อบเจกต์
import { serial } from "@SignalRGB/serial";
export function Type() { return "serial"; }
export function Initialize() {
if (!serial.connect()) {
device.log("Failed to connect to serial port");
return;
}
device.log(`Connected on ${serial.getPortName()} at ${serial.getBaudRate()} baud`);
}
export function Render() {
serial.write([0xFF, ...RGBData]);
}
export function Shutdown() {
serial.disconnect();
}

สำหรับอุปกรณ์ที่เชื่อมต่อผ่านเครือข่าย ให้นำเข้าโมดูล TCP หรือ UDP และตั้งค่า Type() เป็น "network" ทั้งสองโมดูลใช้รูปแบบคอลแบ็กที่อิงตามอีเวนต์

import { tcp } from "@SignalRGB/tcp";
import { udp } from "@SignalRGB/udp";
export function Type() { return "network"; }
import { tcp } from "@SignalRGB/tcp";
let socket;
export function Initialize() {
socket = tcp.createSocket();
socket.on("connected", () => {
device.log("Connected");
socket.send([0x01, 0x02, 0x03]);
});
socket.on("message", (data) => {
device.log(`Received: ${data}`);
});
socket.on("error", (err) => {
device.log(`Error: ${err}`);
});
socket.connect("192.168.1.100", 8080);
}
export function Render() {
if (socket.state === socket.ConnectedState) {
socket.send(RGBData);
}
}
export function Shutdown() {
socket.close();
}

เมธอด TCP:

เมธอดคำอธิบาย
tcp.createSocket()สร้างซ็อกเก็ต TCP ใหม่
socket.connect(address, port)เชื่อมต่อกับโฮสต์
socket.send(data)ส่งสตริงหรืออาร์เรย์ไบต์
socket.bind(port)ผูกกับพอร์ตในเครื่อง
socket.close()ปิดซ็อกเก็ต
socket.on(event, callback)ลงทะเบียนตัวจัดการอีเวนต์

อีเวนต์ TCP: "connected", "disconnected", "message", "error"


import { udp } from "@SignalRGB/udp";
let socket;
export function Initialize() {
socket = udp.createSocket();
socket.on("message", (data) => {
device.log(`Received: ${data}`);
});
socket.connect("192.168.1.100", 21324);
}
export function Render() {
socket.send(RGBData);
}
export function Shutdown() {
socket.close();
}

เมธอด UDP:

เมธอดคำอธิบาย
udp.createSocket()สร้างซ็อกเก็ต UDP ใหม่
socket.connect(address, port)ตั้งค่าปลายทางการส่งเริ่มต้น
socket.send(data)ส่งไปยังแอดเดรสที่เชื่อมต่อไว้
socket.write(data, address, port)ส่งไปยังแอดเดรสที่ระบุโดยไม่ต้องเรียก connect() ก่อน
socket.bind(port)ผูกกับพอร์ตในเครื่องเพื่อรับข้อมูล
socket.close()ปิดซ็อกเก็ต
socket.on(event, callback)ลงทะเบียนตัวจัดการอีเวนต์

อีเวนต์ UDP: "connected", "disconnected", "message", "error"


สำหรับอุปกรณ์ที่ต้องการการสื่อสารแบบเข้ารหัส (เช่น Philips Hue) ให้ใช้ฟีเจอร์ dtls ซึ่งให้บริการ UDP ที่เข้ารหัสด้วย DTLS โดยใช้ Pre-Shared Key (PSK)

export function Initialize() {
device.addFeature("dtls");
dtls.onConnectionEstablished(() => { device.log("DTLS connected"); });
dtls.onConnectionClosed(() => { device.log("DTLS closed"); });
dtls.onConnectionError(() => { device.log("DTLS error"); });
dtls.createConnection("192.168.1.50", 2100, authIdentity, authKey);
}
export function Render() {
if (dtls.hasEncryptedConnection()) {
dtls.send(RGBData);
}
}
export function Shutdown() {
dtls.CloseConnection();
}

เมธอด DTLS:

เมธอดคำอธิบาย
dtls.createConnection(host, port, identity, key)เปิดการเชื่อมต่อแบบเข้ารหัสโดยใช้ PSK
dtls.send(data, endianness?)ส่งข้อมูลที่เข้ารหัส (0 = little-endian, 1 = big-endian)
dtls.hasEncryptedConnection()ส่งคืน true หากสร้างการเชื่อมต่อแล้ว
dtls.CloseConnection()ปิดการเชื่อมต่อ
dtls.onConnectionEstablished(cb)คอลแบ็กเมื่อเชื่อมต่อสำเร็จ
dtls.onConnectionClosed(cb)คอลแบ็กเมื่อการเชื่อมต่อปิดลง
dtls.onConnectionError(cb)คอลแบ็กเมื่อเกิดข้อผิดพลาด