Bỏ qua để đến nội dung

Giao tiếp nâng cao

Trang này đề cập đến các phương pháp giao tiếp USB nâng cao, giao diện serial và socket mạng. Để biết các lần đọc và ghi cơ bản, hãy xem Ghi và đọc.

Hiểu sự khác biệt giữa các loại truyền USB giúp bạn chọn đúng phương pháp và debug các lỗi không mong muốn.

LoạiPhương thứcKích thước thông thườngTrường hợp sử dụng
Interruptdevice.write() / device.read()3–64 byteDữ liệu RGB, lệnh nhỏ, nhập liệu bàn phím/chuột
Bulkdevice.write() / device.read()64–1025 byteHình ảnh LCD, cập nhật firmware, khối cấu hình lớn
Controldevice.send_report() / device.get_report() / device.control_transfer()32–192 byteXác thực, HID Feature Reports, cấu hình thiết bị

Các hàm device.write()device.read() giống nhau được sử dụng cho cả truyền Interrupt và Bulk — driver USB xác định loại dựa trên endpoint và kích thước packet.


Gửi HID GET_INPUT_REPORT Control Transfer. Tương tự device.get_report(), nhưng yêu cầu rõ ràng một Input Report thay vì Feature Report. Sử dụng cái này khi get_report() trả về dữ liệu sai vì thiết bị phân tách các loại Input và Feature Report của nó.

Tham sốKiểuMô tảVí dụ
DataArray1D ArrayDữ liệu yêu cầu báo cáo[0x01]
LengthIntKích thước báo cáo dự kiến tính bằng byte64
Trả vềKiểuMô tả
DataArray1D ArrayCác byte nhận được từ thiết bị
var inputData = device.input_report([0x01], 64);

Thực thi truyền Bulk hoặc Interrupt trực tiếp đến một endpoint USB cụ thể. Không giống như device.write()device.read(), sử dụng endpoint được chọn qua device.set_endpoint(), điều này cho phép bạn địa chỉ hóa bất kỳ endpoint nào qua địa chỉ của nó.

  • Các địa chỉ endpoint kết thúc bằng 0x80 hoặc cao hơn là IN (thiết bị → máy chủ, đọc).
  • Các địa chỉ endpoint dưới 0x80OUT (máy chủ → thiết bị, ghi).
Tham sốKiểuMô tảVí dụ
EndpointHexĐịa chỉ endpoint USB0x81
DataArray1D ArrayDữ liệu để gửi (OUT) hoặc mảng rỗng (IN)[0x01, 0x02]
LengthIntKích thước truyền tính bằng byte64
TimeoutIntMillisecond cho đến khi hủy100
Trả vềKiểuMô tả
DataArray1D ArrayCác byte nhận được (truyền IN), hoặc rỗng
// Ghi vào endpoint 0x01
device.bulk_transfer(0x01, [0x00, 0x01, 0x02], 3, 100);
// Đọc từ endpoint 0x81
var response = device.bulk_transfer(0x81, [], 64, 100);
// Bulk ghi lớn (ví dụ: dữ liệu hình ảnh LCD)
device.bulk_transfer(0x02, imageData, 1024, 500);

USB Control Transfer cấp thấp. Được sử dụng cho các handshake xác thực, giao thức dành riêng cho nhà sản xuất và các trường hợp khi các phương thức HID không đủ. Đây là Control Transfer, không phải Bulk Transfer.

Tham sốKiểuMô tảVí dụ
RequestTypeHexBitmap USB Request Type (hướng, loại, người nhận)0xA1
RequestHexMã yêu cầu (dành riêng cho thiết bị)0x01
ValueHexTrường giá trị0x0100
IndexIntChỉ số interface hoặc endpoint0x00
DataArray1D ArrayDữ liệu để gửi (Host→Thiết bị), hoặc rỗng[]
LengthIntĐộ dài phản hồi dự kiến (Thiết bị→Host)192
TimeoutIntMillisecond cho đến khi hủy1000
Trả vềKiểuMô tả
DataArray1D ArrayCác byte nhận được (truyền Thiết bị→Host)

Giá trị RequestType phổ biến:

Giá trịHướngLoạiNgười nhậnTrường hợp sử dụng
0x21Host → Thiết bịClassInterfaceHID SET_REPORT
0xA1Thiết bị → HostClassInterfaceHID GET_REPORT
0x80Thiết bị → HostStandardThiết bịĐọc descriptor
0x00Host → Thiết bịStandardThiết bịLệnh chuẩn
// Đọc token xác thực (Thiết bị → Host, Class, Interface)
var token = device.control_transfer(
0xA1, // Thiết bị→Host, Class, Interface
0x01, // GET_REPORT
0x0100, // Loại báo cáo (Feature) + Report ID
0x00, // Interface 0
[], // Không có dữ liệu đi
192, // Mong đợi 192 byte trả về
1000 // Timeout 1 giây
);
// Gửi Feature Report (Host → Thiết bị)
device.control_transfer(0x21, 0x09, 0x0300, 0, [0x03, 0x08, 0x32], 0, 500);

Đối với các thiết bị có cổng serial/COM, hãy import module Serial và đặt Type() của plugin thành "serial".

import { serial } from "@SignalRGB/serial";
export function Type() { return "serial"; }
serial.connect({
baudRate: 115200, // Mặc định: 115200
parity: "None", // "None", "Even", "Odd", "Space", "Mark"
dataBits: 8, // 5, 6, 7 hoặc 8
stopBits: "One" // "One", "OneAndHalf", "Two"
});
Phương thứcMô tảTrả về
serial.connect(options?)Mở cổng serialbool
serial.disconnect()Đóng cổng serialvoid
serial.isConnected()Kiểm tra trạng thái kết nốibool
serial.write(data)Gửi dữ liệuByte đã gửi
serial.read(maxBytes?, timeoutMs?)Đọc các byte có sẵn (mặc định: tất cả, timeout 1000 ms)Mảng byte
serial.readAll()Đọc ngay tất cả các byte có sẵnMảng byte
serial.availablePorts()Liệt kê các cổng COM có sẵnMảng
serial.getPortName()Tên cổng hiện tạistring
serial.getBaudRate()Baud rate hiện tạinumber
serial.getDeviceInfo()Thông tin cổng với VID, PID, v.v.object
import { serial } from "@SignalRGB/serial";
export function Type() { return "serial"; }
export function Initialize() {
if (!serial.connect()) {
device.log("Verbindung zum seriellen Port fehlgeschlagen");
return;
}
device.log(`Verbunden auf ${serial.getPortName()} mit ${serial.getBaudRate()} Baud`);
}
export function Render() {
serial.write([0xFF, ...RGBData]);
}
export function Shutdown() {
serial.disconnect();
}

Đối với các thiết bị hỗ trợ mạng, hãy import module TCP hoặc UDP và đặt Type() thành "network". Cả hai module đều sử dụng mô hình callback dựa trên sự kiện.

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("Verbunden");
socket.send([0x01, 0x02, 0x03]);
});
socket.on("message", (data) => {
device.log(`Empfangen: ${data}`);
});
socket.on("error", (err) => {
device.log(`Fehler: ${err}`);
});
socket.connect("192.168.1.100", 8080);
}
export function Render() {
if (socket.state === socket.ConnectedState) {
socket.send(RGBData);
}
}
export function Shutdown() {
socket.close();
}

Phương thức TCP:

Phương thứcMô tả
tcp.createSocket()Tạo TCP socket mới
socket.connect(address, port)Kết nối đến host
socket.send(data)Gửi chuỗi hoặc mảng byte
socket.bind(port)Liên kết với cổng cục bộ
socket.close()Đóng socket
socket.on(event, callback)Đăng ký handler sự kiện

Sự kiện TCP: "connected", "disconnected", "message", "error"


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

Phương thức UDP:

Phương thứcMô tả
udp.createSocket()Tạo UDP socket mới
socket.connect(address, port)Đặt đích gửi mặc định
socket.send(data)Gửi đến địa chỉ đã kết nối
socket.write(data, address, port)Gửi đến địa chỉ cụ thể mà không cần gọi connect() trước
socket.bind(port)Liên kết với cổng cục bộ để nhận
socket.close()Đóng socket
socket.on(event, callback)Đăng ký handler sự kiện

Sự kiện UDP: "connected", "disconnected", "message", "error"


Đối với các thiết bị yêu cầu giao tiếp được mã hóa (ví dụ: Philips Hue), hãy sử dụng tính năng dtls. Nó cung cấp UDP được mã hóa DTLS với Pre-Shared Key (PSK).

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

Phương thức DTLS:

Phương thứcMô tả
dtls.createConnection(host, port, identity, key)Mở kết nối được mã hóa với PSK
dtls.send(data, endianness?)Gửi dữ liệu được mã hóa (0 = Little-Endian, 1 = Big-Endian)
dtls.hasEncryptedConnection()Trả về true nếu kết nối tồn tại
dtls.CloseConnection()Đóng kết nối
dtls.onConnectionEstablished(cb)Callback khi kết nối thành công
dtls.onConnectionClosed(cb)Callback khi kết nối đóng
dtls.onConnectionError(cb)Callback khi có lỗi