跳转到内容

高级通信

本页介绍高级 USB 通信方法、串口和网络套接字。有关基本读写操作,请参阅写入和读取

了解 USB 传输类型之间的差异将帮助您选择正确的方法并调试意外错误。

类型方法典型大小使用场景
中断device.write() / device.read()3–64 字节RGB 数据、小命令、键盘/鼠标输入
批量device.write() / device.read()64–1025 字节LCD 图像、固件更新、大型配置块
控制device.send_report() / device.get_report() / device.control_transfer()32–192 字节身份验证、HID 功能报告、设备配置

相同的 device.write()device.read() 函数用于中断和批量传输——USB 驱动程序根据端点和数据包大小确定传输类型。


发送 HID GET_INPUT_REPORT 控制传输。类似于 device.get_report(),但专门请求 Input 报告而不是 Feature 报告。当 get_report() 返回错误数据时(因为设备将其 Input 和 Feature 报告类型分开)使用此方法。

参数类型描述示例
DataArray1D 数组报告请求数据[0x01]
LengthInt预期报告大小(字节)64
返回值类型描述
DataArray1D 数组从设备接收的字节
var inputData = device.input_report([0x01], 64);

对特定 USB 端点执行直接批量或中断传输。与使用 device.set_endpoint() 选择端点的 device.write()device.read() 不同,这允许您通过地址定位任何端点。

  • 0x80 或更高值结尾的端点地址是 IN(设备 → 主机,读取)。
  • 低于 0x80 的端点地址是 OUT(主机 → 设备,写入)。
参数类型描述示例
EndpointHexUSB 端点地址0x81
DataArray1D 数组要发送的数据(OUT),或空数组(IN)[0x01, 0x02]
LengthInt传输大小(字节)64
TimeoutInt放弃前的毫秒数100
返回值类型描述
DataArray1D 数组接收的字节(IN 传输),或空
// 写入端点 0x01
device.bulk_transfer(0x01, [0x00, 0x01, 0x02], 3, 100);
// 从端点 0x81 读取
var response = device.bulk_transfer(0x81, [], 64, 100);
// 大型批量写入(例如 LCD 图像数据)
device.bulk_transfer(0x02, imageData, 1024, 500);

底层 USB 控制传输。用于身份验证握手、供应商特定协议以及 HID 方法不够用的情况。这是控制传输,而不是批量传输。

参数类型描述示例
RequestTypeHexUSB 请求类型位图(方向、类型、接收方)0xA1
RequestHex请求代码(特定于设备)0x01
ValueHex值字段0x0100
IndexInt接口或端点索引0x00
DataArray1D 数组要发送的数据(主机到设备),或空[]
LengthInt预期响应长度(设备到主机)192
TimeoutInt放弃前的毫秒数1000
返回值类型描述
DataArray1D 数组接收的字节(设备到主机传输)

常用 RequestType 值:

方向类型接收方使用场景
0x21主机 → 设备接口HID SET_REPORT
0xA1设备 → 主机接口HID GET_REPORT
0x80设备 → 主机标准设备描述符读取
0x00主机 → 设备标准设备标准命令
// 读取身份验证令牌(设备 → 主机,类,接口)
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
);
// 发送功能报告(主机 → 设备)
device.control_transfer(0x21, 0x09, 0x0300, 0, [0x03, 0x08, 0x32], 0, 500);

对于串口/COM 端口设备,导入串口模块并将插件的 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()当前端口名称string
serial.getBaudRate()当前波特率number
serial.getDeviceInfo()包含 VID、PID 等的端口信息object
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 功能。它使用预共享密钥(PSK)提供 DTLS 加密 UDP。

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 = 小端,1 = 大端)
dtls.hasEncryptedConnection()如果连接已建立则返回 true
dtls.CloseConnection()关闭连接
dtls.onConnectionEstablished(cb)连接成功时的回调
dtls.onConnectionClosed(cb)连接关闭时的回调
dtls.onConnectionError(cb)发生错误时的回调