feat: 实现SerialProvider

- SerialProvider用于为串口连接提供context
This commit is contained in:
2025-12-24 15:01:38 +08:00
parent 00bd397986
commit b841b2641c
6 changed files with 255 additions and 1 deletions

View File

@ -0,0 +1,108 @@
// src/lib/serial/serial.service.ts
// Web Serial API implementation
// Requires: @types/w3c-web-serial
/**
* 内部IO资源
*/
let reader: ReadableStreamDefaultReader<Uint8Array> | null = null;
let writer: WritableStreamDefaultWriter<Uint8Array> | null = null;
let isOpen = false;
/**
* 判断当前环境是否支持Web Serial API
*/
export function isWebSerialSupported(): boolean {
return typeof navigator !== 'undefined' && 'serial' in navigator;
}
/**
* 请求用户选择串口设备
*/
export async function requestPort(
filters?: SerialPortRequestOptions['filters']
): Promise<SerialPort | null> {
if (!isWebSerialSupported()) {
throw new Error('Web Serial API is not supported in this environment.');
}
const port = await navigator.serial.requestPort(
filters ? { filters } : undefined
);
return port ?? null;
}
/**
* 打开串口
*/
export async function openPort(
port: SerialPort,
options: SerialOptions
): Promise<void> {
if (isOpen) {
// 串口已经打开,直接返回
return;
}
await port.open(options);
isOpen = true;
// 初始化reader和writer
reader = port.readable?.getReader() ?? null;
writer = port.writable?.getWriter() ?? null;
}
/**
* 关闭串口
*/
export async function closePort(port: SerialPort) {
if (!isOpen) {
// 串口未打开,直接返回
return;
}
await reader?.cancel();
reader?.releaseLock();
await writer?.close();
writer?.releaseLock();
reader = null;
writer = null;
isOpen = false;
await port.close();
}
/**
* 向串口写入数据
*/
export async function write(data: Uint8Array): Promise<void> {
if (!writer) {
throw new Error('Serial port is not writable.');
}
await writer.write(data);
}
/**
* 开始读取串口数据循环
*/
export async function startReadLoop(
onData: (chunk: Uint8Array) => void,
onError?: (err: unknown) => void
): Promise<void> {
if (!reader) {
throw new Error('Serial port is not readable.');
}
try {
while (true) {
const { value, done } = await reader.read();
if (done) break;
if (value) onData(value);
}
} catch (err) {
onError?.(err);
}
}