扩展库 / serial
serial
系统与硬件Windows 与 Linux 串口设备、独立内存回环。文本和二进制接口统一按字节计数,读取结果独立拥有,短读短写保留真实传输量。C 与 xlang 共用缓冲、锁和错误合同。
验收边界:Windows / Linux 回环、并发和分配失败已验证;Linux 另通过真实内核 PTY 的双向 I/O、超时、断线、配置及 C/xlang 对照。USB/物理串口、热拔插和驱动差异仍未验收,不能把 PTY 结果等同硬件发布认证。当前完整 AOT 门禁受编译器缺符号阻断。
快速开始
import serial
from serial import Serial
func main(...) as int
Serial port = serial.openLoopback(115200)
port.setTimeouts(1500, 1000)
assert port.write("你好") == 6
println(port.read(6))
Buffer bytes = Buffer()
assert bytes.appendByte(0) and bytes.appendByte(255)
assert port.writeBytes(bytes) == 2
Buffer result = port.readBytes(2)
assert result.byteAt(0) == 0 and result.byteAt(1) == 255
return 0
end连接 Windows 设备使用 serial.open("COM3", 115200),Linux 使用 serial.open("/dev/ttyUSB0", 115200) 或稳定的 /dev/serial/by-id/... 路径。程序必须有设备权限;对象自动释放句柄。Linux 打开时启用原始模式与内核支持的独占标志。
xlang API
| 入口 | 返回 / 约定 |
|---|---|
serial.open(string port, int baudrate = 9600) | Serial;默认 8 数据位、1 停止位、无校验。无效参数或含 NUL 的端口名抛 ValueError;设备失败抛 IOError。 |
serial.openLoopback(int baudrate = 9600) | Serial;创建独立的 4096 字节内存回环队列。 |
Serial(port, baudrate, databits, stopbits, parity) | 完整构造;5..8 数据位,1/2 停止位,校验为 0 无 / 1 奇 / 2 偶。含 NUL 的端口名抛 ValueError,设备打开失败抛相应异常。 |
valid / isOpen | bool;是否持有句柄,不是设备健康或拔线检测。 |
port / baudrate | string / int;创建时的设备名与波特率。 |
available | int;当前可读字节数,失败抛 IOError。并发下只是快照。 |
write(string data) | int;完整写入 UTF-8 字节,包括内嵌 NUL;返回实际写入数。 |
writeBytes(Buffer data) | int;实际写入二进制字节数,不修改或接管输入。 |
read(int maxLen = 1024) | string;将本次读取转成文本,maxLen 是字节数。 |
readBytes(int maxLen = 1024) | 独立拥有的 Buffer;负数抛 ValueError,0 不消费数据。 |
setTimeouts(int readMs, int writeMs) | 设备读写等待上限为 0..60000 毫秒;0 请求不等待,Windows 写入映射为最短 1ms 驱动超时。回环口始终立即收发。 |
flush() | 丢弃收发队列;不等待数据发送完成。失败抛 IOError。 |
构造和读写失败均会抛出异常。C 的 open、读写、available、flush 和 setTimeouts 以本次 XRT 错误为准;成功不保留上次失败的诊断。close、纯查询和错误读取不清掉待处理诊断。类中的 *Native 方法仅供包装层内部使用;XLang 应用使用上表的检查型方法,C 应用可直接使用公开 C API。
I/O 与拥有权约定
- 长度与返回值统一为字节数。
"你好"是 6 个 UTF-8 字节。 - 工厂函数与直接
Serial(...)构造均拒绝端口名中的内嵌 NUL,不会悄悄打开截断后的端口。 - 允许短读、短写和成功的零字节结果。回环满队列返回 0,不会丢数据后谎报成功。
- 单次真实设备 I/O 最多 65536 字节;更大的请求会被限制为一次有界操作。
- 读取结果不会被下一次读取、flush 或端口析构影响。C 调用方独立销毁结果缓冲。
- UTF-8 字符可以跨读取边界。处理协议帧、分块文本或二进制时,先用 Buffer 收齐数据。
- 每次操作内部加锁,但多个操作组成的事务不会自动加锁。请求与响应的对应关系由调用方管理。
- 真实设备使用同步 I/O,默认首字节读取等待约 50ms、写入超时 1000ms;可调用 setTimeouts 修改。Windows 写入零超时映射为 1ms,不能保证严格非阻塞;实际行为仍受驱动约束。
- 目前没有串口枚举、异步串口或硬件流控 API。
C 关闭句柄前,必须结束所有使用该句柄的操作。close(NULL) 安全;重复关闭、关闭后使用和并发关闭不属于有效调用。xlang 赋值或传参保留对象引用,不复制串口资源。
C API
公开头文件为 extlibs/serial/include/serial.h。编译 serial_native.c 并链接一份 XRT,无需链接 xlang 编译器。失败详情通过当前线程的 xrtGetError() 读取。
| 函数 | 合同 |
|---|---|
xserial_open(name, baudrate, databits, stopbits, parity) | 拥有型 void*;失败 NULL。数值参数为 int64_t。 |
xserial_close(handle) | 消费句柄,恰好关闭一次。 |
xserial_is_open(handle) | bool;NULL 为 false,不验证悬空指针。 |
xserial_set_timeouts(handle, readMs, writeMs) | bool;0..60000 毫秒。失败时保留原配置。 |
xserial_write(handle, const void* data, size_t size) | int64_t 实际字节数,失败 -1;只读借用输入。 |
xserial_write_text(handle, const char* text) | 按 C 字符串的 UTF-8 字节长度写入,失败 -1。 |
xserial_write_text_len(handle, const char* text, size_t size) | 显式长度的文本字节写入;允许内嵌 NUL,行为与 write 相同。 |
xserial_write_bytes(handle, void* data, size_t size) | xlang point 的精确 ABI 入口;行为与 write 相同。 |
xserial_read(handle, int64_t maxBytes) | 返回 void*,实际为拥有型 xbuffer*;用 xrtBufferDestroy 释放。NULL 只表示失败。 |
xserial_available(handle) | int64_t;失败 -1。 |
xserial_flush(handle) | bool;清空队列,失败 false。 |
xserial_get_baudrate(handle) | int64_t;NULL 为 0。 |
xserial_get_port(handle) | 借用字符串,保持到 close;NULL 返回空字符串。 |
xserial_error() | 借用当前线程错误文本,保持到错误槽变化;无错误为空字符串。 |
以返回值判断本次 C 操作,不要把之前的 last-error 当成新操作的失败。记录或处理错误后使用 XRT 清理接口;错误槽在线程之间隔离。
范例与验证
发行目录中,两份范例可以直接运行,13 行输出逐字一致:
xl run examples/extlibs/serial.xl
xl run examples/extlibs/serial_c.c设备范例 extlibs/serial/examples/device_c.c 可直接用 xl build 或 xl run;运行时需提供串口路径。Linux 门禁使用独立 PTY 核对请求与响应,Windows 无设备门禁只验证构建。
源码仓库根目录下的专用门禁:
powershell -NoProfile -ExecutionPolicy Bypass -File tools/check_extlib_serial.ps1 -SkipAot
powershell -NoProfile -ExecutionPolicy Bypass -File tools/check_extlib_serial.ps1
powershell -NoProfile -ExecutionPolicy Bypass -File tools/run_platform_extlibs.ps1 -Package serial- Windows 严格 GCC 与生成 C 原型核对、C/xlang 内存运行;完整 AOT 仍待编译器缺符号修复。
- Linux 以
-DNDEBUG编译运行 C 回环范例,确保读写操作不会随断言关闭而消失,并与 xlang 范例逐字核对。 - C 与 xlang 范例分别校验 2 字节剩余、4096 字节容量、满队列零写入和最终零剩余,避免两者同时打印错误值却通过对照。
- 满队列、空值、负长度、int64 极值、超长设备名、UTF-8 与内嵌零字节。
- 跨读取/析构的独立结果、对象别名与反复创建释放。
- 双线程写入、不同块大小的 64KiB 连续传输、当前线程错误隔离。
- 96 组分配位置测试,检查失败不消费队列以及存活内存、双重释放与越界计数。
- Linux 用
sh release/extlibs/serial/test/check.sh运行 ASan/UBSan 回环、故障注入及 PTY 设备测试;独立 GCC、直接xl build、直接xl run与 xlang 的设备范例分别发送 PING 并接收 PONG。
真实设备与热拔插尚未验证,不能以回环测试代替。分配故障注入在独立 C 进程执行,不改变正在运行的 xl.dll 宿主分配策略。