109 lines
2.1 KiB
TypeScript
109 lines
2.1 KiB
TypeScript
// 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);
|
|
}
|
|
}
|