# 内置硬件协议
# 概要
前面大概介绍了硬件设备接口
为了减轻开发者的负担,我们默认内置了几种常见硬件连接协议,主要用途是插件配置所需的设备搜索、连接的参数,向 uCode 注册,并获取连接后的实例,与设备实现通信。
如果内置的几种硬件协议无法满足需求,可以自定义硬件协议。
在插件中,需要注册插件所需的硬件协议,如:
// index.js
import { spRegister } from "./devices/sp-device";
import { WebsocketRegister } from "./devices/websocket-device";
const register = {
DeviceRegister: [
spRegister, // 串口连接协议注册方法
WebsocketRegister, // Websocket连接协议注册方法
],
BlockRegister: ExampleDeviceExtension, // 积木块注册方法
};
self.UCode.extensions.register(register); // 插件注册方法
对于硬件连接协议注册列表DeviceRegister
,其类型是
DeviceRegisterType (点击查看 API 文档)。
它可以是以下三个主要的注册方法之一:
DiscoverDeviceRegister (点击查看 API 文档) 通过扫描设备界面实现搜搜、连接
InputDeviceIdRegister (点击查看 API 文档) 输入设备 ID 或 IP 等界面实现设备搜索、连接
# 内置协议类型
以下是内置的几种硬件协议,如果符合需求的话,可以直接从 SDK 中导入使用:
内置协议 | 是否依赖 uCodeLink | 说明 |
---|---|---|
SerialPort 串口协议 | ✅ | 目前基于 node-serialport 实现。我们会计划增加 WebSerial (opens new window) |
BLE 蓝牙协议(4.0 以上) | ✅ | 目前 WebBle 暂未开放,后续会增加 |
WebSocket (未完成) | ❌ | 原生的 WebSocket 接口,注意在 Web 端的跨域和加密混用 等安全限制 |
WebTransport (未完成) | ✅ | WebTransport 是基于 UDP 但是是更上层的协议。 了解 WebTransport (opens new window) |
MDns | ✅ | 苹果的 开源 Bonjour 协议,目前这个只是用于发现协议 |
UDP/TCP | ✅ | 经典 Socket 通信 -- UDP/TCP 协议 |
# 串口协议
以串口为例,内置的硬件协议已经内置到 ucode-extension-common-sdk
里面,使用起来非常简单
import { CommonProtocols } from "@ubtech/ucode-extension-common-sdk";
const { SerialPortProtocol, getSerialPortDeviceRegister } = CommonProtocols.SerialPort;
SerialPortProtocol
是我们封装好的Protocol
类,直接继承该类的话,就可以获取所有串口的方法,具体的可以参照uCode Common SDK
硬件协议的部分
在代码里面,可以看到我们直接调用了 this.send
的方法,这个其实继承于 SerialPortProtocol
的 send
方法
say(data) {
this.send(Buffer.from(data));
}
getSerialPortDeviceRegister
则是我们封装好的,直接提供一个开箱即用的串口注册器
里面有很多可选参数,例如:
- 串口的波特率
- 串口 Buffer 缓冲 Size
- 是否要开启队列
- 发现设备的时候,是否要根据 vid 和 pid 过滤串口设备
- 自定义串口的名称
{
openOptions: {
baudRate: 115200, // 串口打开的波特率
bufferSize: 12 * 1024 * 1024, // 缓冲区大小
},
queueOptions: {
enable: true, // 数据发送是否启用队列
interval: 70, // 启用队列时数据发送的间隔
},
// 发现设备时过滤用的vid和pid,配置后将只显示和配置id一致的串口设备
filter: {
vid: "0403",
pid: "6001",
},
// 自定义显示串口设备名
customDeviceName: (data) => `myRobot_${data?.comName}`,
},
下面是完整的代码展示,你可以在脚手架或者内置插件模板,都可以找到
import { CommonProtocols } from "@ubtech/ucode-extension-common-sdk";
const { SerialPortProtocol, getSerialPortDeviceRegister } = CommonProtocols.SerialPort;
class DemoSerialPortProtocol extends SerialPortProtocol {
say(data) {
this.send(Buffer.from(data));
}
}
export const spRegister = getSerialPortDeviceRegister({
Protocol: DemoSerialPortProtocol,
// 以下配置均为可选配置
Options: {
openOptions: {
baudRate: 115200, // 串口打开的波特率
bufferSize: 12 * 1024 * 1024, // 缓冲区大小
},
queueOptions: {
enable: true, // 数据发送是否启用队列
interval: 70, // 启用队列时数据发送的间隔
},
// 发现设备时过滤用的vid和pid,配置后将只显示和配置id一致的串口设备
filter: {
vid: "0403",
pid: "6001",
},
// 自定义显示串口设备名
customDeviceName: (data) => `myRobot_${data?.comName}`,
},
});
# 完整的 串口 API 文档
最新的以 API 文档为主 SerialPort 串口 API 文档
# 蓝牙协议 (待完成)
# WebSocket 协议 (待完成)
# MDNS 协议 (待完成)
# UDP/TCP 协议
# 概要
uCode 内部封装了 UDP/TCP 协议的操作方法,并适配了 PC、Mobile 平台。API 参考 Node.js 的 UDP 写法。
我们内置了两个 UDP/TCP 设备“搜索+连接”注册方法,让插件可以向 uCode 注册需要用到的“搜索+连接”的方式及其参数:
getUDPDeviceRegister()
,基于 UDP 发现设备、基于 UDP 与设备通信。getTCPDeviceRegister()
,基于 UDP 发现设备、基于 TCP 与设备通信。
你可以根据需要使用相应的注册方法,也可以自己实现不同的“搜索+连接”方案的注册方法。
下面就前面提到的两个注册方法进行详细描述。
# 导入与参数说明
getUDPDeviceRegister():适用于 UDP 搜索 + UDP 通信 的设备
内置的 UDP 硬件协议注册方法,是基于 UDP 搜索与 UDP 连接通信类组合的。
import { CommonProtocols } from "@ubtech/ucode-extension-common-sdk"; const { getUDPDeviceRegister } = CommonProtocols.UDP; /** * UDP 搜索 + UDP 通信 */ export const udpRegister = getUDPDeviceRegister({ DeviceConnection: xx, Options: xxxx, // Discover: xxx, });
getUDPDeviceRegister 已经对部分参数封装,
入参
只需要设置DeviceConnection
和Options
,或设置Discover
替换内置的 UDP discover 类。返回值
类型为 DiscoverDeviceRegister (点击查看 API 文档) ,包含以下字段:type: 'discover'
属于“设备搜索”类型DeviceType
设置搜索类型、描述、搜索超时时长、当只有一个设备时自动连接等参数。当有多个硬件协议注册时,可以在界面中看到描述。DeviceConnection
设备连接类,用于建立硬件设备连接、收发消息、协议解析等Discover
设备搜索类,用于处理“搜索设备”的逻辑Options
设备搜索类、设备连接类所需的参数
DeviceConnection
参数可以直接使用或继承UDPDeviceConnection
,覆写父类方法实现你所需的业务逻辑。如果内置的注册方法与连接通信类都无法满足业务需求,可以进行自定义。
查看 UDPRegister 详情
UDPDeviceConnection
如下:import { CommonProtocols } from "@ubtech/ucode-extension-common-sdk"; const { UDPDeviceConnection } = CommonProtocols.UDP; class TestUDPDeviceConnection extends UDPDeviceConnection {}
Options
如下:type UDPRegisterOptions = { /** * UDP创建socket时构造函数的参数 */ udpConstructorOptions: UDPConstructorOptions | UDPSocketType; /** * 发消息来触发设备回应? */ sendMsgForDiscover?: UDPMsg; /** * 收到消息后,发送一条固定的消息回应? */ sendMsgForResponse?: UDPMsg; /** * 监听消息时,绑定的端口 */ bindPort?: number; /** * 监听消息时,绑定的地址 */ bindAddress?: string; /** * 发送消息时,发送数据的端口 */ sendPort?: number; /** * 发送消息时,发送数据的地址 */ sendAddress?: string; /** * 设置广播? */ isBroadcast?: boolean; /** * 设置 IP_TTL 选项 */ ttl?: number; /** * 设置或取消 IP_MULTICAST_LOOP 选项 */ multicastLoopback?: boolean; /** * 将套接字的默认传出多播接口设置为所选接口或返回系统接口选择 */ multicastInterface?: string; /** * 自定义设备名,可以从socket数据中加工出新名字 */ customDeviceName?: (deviceData: DiscoverDeviceData) => string; /** * 设置 IP_MULTICAST_TTL 选项 */ multicastTTL?: number; /** * 设置接收消息的缓存大小 */ recvBufferSize?: number; /** * 设置发送消息的缓存大小 */ sendBufferSize?: number; /** * 设置多播地址,在 addMembership 或 dropMembership 使用 */ multicastAddress?: string; /** * 扫描超时 */ scanTime?: number; /** * 队列参数,可以设置 队列 发送的 间隔 或者 数量 */ queueOptions?: QueueConstructorType; };
getTCPDeviceRegister(): 适用于 UDP 搜索 + TCP 通信 的设备
getTCPDeviceRegister
和getUDPDeviceRegister
参数大体上相同:Discover
基于 UDP,这里用的也是 UDPDiscover。DeviceConnection
可以用内置的,也可以继承,对某些方法进行覆写,或自定义,当然 Discover 也可以用别的,如串口、蓝牙等。Options
两者的主要差异之处。将 Discover 和 DeviceConnection 的 options 分开设置。
import { CommonProtocols } from "@ubtech/ucode-extension-common-sdk"; const { getTCPDeviceRegister } = CommonProtocols.TCP; const { UDPDiscover, getUDPDeviceType } = CommonProtocols.UDP; export const tcpRegister = getTCPDeviceRegister({ Discover: UDPDiscover, // 设置搜索器 DeviceConnection: xxx, // 设置通信器 Options: { // 设置搜索器、连接器用到的配置参数 discoverDeviceType: getUDPDeviceType({ scanTime: scanTimeTimeout }), // 搜索器类型(搜索、输入ID/IP、自行处理) discoverOptions: xxx, // UDP搜索类参数 connectionOptions: xxx, // TCP搜索类参数 }, });
查看 Connection 详情
discoverOptions
见上文的UDPRegisterOptions
。connectionOptions
如下:type ConnectionOptionsType = { /** * 创建TCP socket时,传给构造函数的参数 */ tcpConstructorOptions?: SocketConstructorOpts; /** * 队列参数,可以设置 队列 发送的 间隔 或者 数量 */ queueOptions?: QueueConstructorType; /** * 设置数据编码,也可以在write中设置 */ encoding?: BufferEncoding; /** * 是否开启KeepAlive功能 */ keepAlive?: { enable: boolean; initialDelay?: number; }; /** * 是否开启拥塞控制算法 */ noDelay?: boolean; /** * 设置inactive超时时长 */ timeout?: number; /** * 连接超时 */ connectTimeout?: number; };
如果使用内置的
TCPDeviceConnection
,需要实现抽象类一个方法getDeviceInfo
。这个方法参数来自于 Discover 类:当 Discover 搜索到设备时,会创建“设备对象”(不同的硬件设备,协议不同,“设备对象”也可能不同)。当用户点击“连接”按钮时,会将该“设备对象”传给 Connection 的 getDeviceInfo 方法。因此子类需要实现这个方法,解析“设备对象”中的端口和地址信息,属于具体的业务部分。
import { CommonProtocols } from "@ubtech/ucode-extension-common-sdk"; const { TCPClientConnection } = CommonProtocols.TCP; export class MyTCPClientConnection extends TCPClientConnection { /** * 实现抽象类获取设备信息的方法 * @param { {buffer: Buffer, port: number, address: string} } device discover传过来的设备对象 * @return Promise<SocketConnectOpts = { * port: number; * host?: string; * localAddress?: string; * localPort?: number; * hints?: number; * family?: number; * lookup?: LookupFunction; * onread?: OnReadOpts; * path?: string; * } TCP连接时用的设备信息 */ getDeviceInfo(device) { // 示例:device.buffer对象中包含port和address属性 const { buffer } = device; const data = JSON.parse(Buffer.from(buffer).toString()); console.log(data.port, data.address); return Promise.resolve({ port: data.port, host: data.address, }); } }
# 自定义
如果你想自定义 Discover 类,请遵循并实现接口IDeviceDiscover
。
如果你想自定义 Connection 类,请遵循并实现接口DeviceConnectionInterface
DeviceConnectionInterface API 文档
# uCodeLink 硬件连接助手
uCode v4.0 是基于 web 的,但是 web 天生有很多限制,因此为了提供一些额外的访问能力,我们增加了 uCodeLink
硬件连接助手,通过它可以访问 串口 或者 蓝牙等设备