扩展库 / serial
serial
系统与硬件Windows 串口与独立内存回环。文本和二进制接口统一按字节计数,读取结果独立拥有,短读短写保留真实传输量。C 与 xlang 共用 XRT 管理的句柄、缓冲、锁和错误信息。
验收边界:2026-09-05 已验证 Windows / Linux 回环、并发、生命周期与分配失败;真实串口硬件尚未验收。Linux 当前只有回环,不能打开真实串口。本文说明当前源码,不代表此前下载包已经包含本轮更新。
快速开始
import serial
from serial import Serial
func main(...) as int
Serial port = serial.openLoopback(115200)
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),也接受 \\.\COM3。设备独占打开;程序必须有权限访问串口。对象自动释放句柄。
xlang API
| 入口 | 返回 / 约定 |
|---|---|
serial.open(string port, int baudrate = 9600) | Serial;默认 8 数据位、1 停止位、无校验。无效参数抛 ValueError;设备失败抛 IOError。 |
serial.openLoopback(int baudrate = 9600) | Serial;创建独立的 4096 字节内存回环队列。 |
Serial(port, baudrate, databits, stopbits, parity) | 完整 native 构造;5..8 数据位,1/2 停止位,校验为 0 无 / 1 奇 / 2 偶。失败句柄为空,必须先检查 valid;通常优先使用工厂函数。 |
valid / isOpen | bool;是否持有句柄,不是设备健康或拔线检测。 |
port / baudrate | string / int;创建时的设备名与波特率。 |
available | int;当前可读字节数,失败抛 IOError。并发下只是快照。 |
write(string data) | int;实际写入 UTF-8 字节数。 |
writeBytes(Buffer data) | int;实际写入二进制字节数,不修改或接管输入。 |
read(int maxLen = 1024) | string;将本次读取转成文本,maxLen 是字节数。 |
readBytes(int maxLen = 1024) | 独立拥有的 Buffer;负数抛 ValueError,0 不消费数据。 |
flush() | 丢弃收发队列;不等待数据发送完成。失败抛 IOError。 |
读写方法在失败时抛出异常。类中的 *Native 是声明层入口,保留原始 C 返回码;应用通常应使用上表的检查型方法。直接 native 构造失败需检查 valid。
I/O 与拥有权约定
- 长度与返回值统一为字节数。
"你好"是 6 个 UTF-8 字节。 - 允许短读、短写和成功的零字节结果。回环满队列返回 0,不会丢数据后谎报成功。
- 单次真实设备 I/O 最多 65536 字节;更大的请求会被限制为一次有界操作。
- 读取结果不会被下一次读取、flush 或端口析构影响。C 调用方独立销毁结果缓冲。
- UTF-8 字符可以跨读取边界。处理协议帧、分块文本或二进制时,先用 Buffer 收齐数据。
- 每次操作内部加锁,但多个操作组成的事务不会自动加锁。请求与响应的对应关系由调用方管理。
- 真实设备使用同步 I/O,当前固定首字节读取等待约 50ms、写入超时 1000ms;实际行为仍受驱动约束。
- 目前没有串口枚举、异步串口、可配置超时或硬件流控 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_write(handle, const void* data, size_t size) | int64_t 实际字节数,失败 -1;只读借用输入。 |
xserial_write_text(handle, const char* text) | 按 C 字符串的 UTF-8 字节长度写入,失败 -1。 |
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 清理接口;错误槽在线程之间隔离。
范例与验证
发行目录中,两份范例可以直接运行,12 行输出逐字一致:
xl run examples/extlibs/serial.xl
xl run examples/extlibs/serial_c.c源码仓库 demo6 目录下的专用门禁:
powershell -NoProfile -ExecutionPolicy Bypass -File tools/check_extlib_serial.ps1
powershell -NoProfile -ExecutionPolicy Bypass -File tools/run_platform_extlibs.ps1 -Package serial- 严格 GCC 与生成 C 原型核对,C/xlang 内存运行,xlang 和 C 可执行文件。
- 满队列、空值、负长度、int64 极值、超长设备名、UTF-8 与内嵌零字节。
- 跨读取/析构的独立结果、对象别名与反复创建释放。
- 双线程写入、不同块大小的 64KiB 连续传输、当前线程错误隔离。
- 96 组分配位置测试,检查失败不消费队列以及存活内存、双重释放与越界计数。
- Linux 回环也通过 AddressSanitizer / UndefinedBehaviorSanitizer 检查;这不是 Linux 设备支持声明。
真实设备与热拔插尚未验证,不能以回环测试代替。分配故障注入在独立 C 进程执行,不改变正在运行的 xl.dll 宿主分配策略。