export 'src/models/models.dart'; import 'dart:async'; import 'dart:typed_data'; import 'ch934x_serial_method_channel.dart'; import 'ch934x_serial_platform_interface.dart'; import 'src/models/models.dart'; /// CH934X 插件的对外门面类。 /// /// 内部委托 [Ch934xSerialPlatform] 真正执行平台调用, /// 在 Android 上默认走 [MethodChannelCh934xSerial]。 /// /// 命名/语义与官方 Android SDK 文档保持一致;若希望 /// 监听串口数据流,可使用 [dataStream] 配合 [read]。 class Ch934xSerial { /// 使用默认平台实现构造。 Ch934xSerial() : _platform = Ch934xSerialPlatform.instance; /// 注入自定义平台实现,常用于单元测试。 Ch934xSerial.withPlatform(Ch934xSerialPlatform platform) : _platform = platform; final Ch934xSerialPlatform _platform; // --------------------------------------------------------------------------- // 设备查找 // --------------------------------------------------------------------------- /// 获取所有已连接的 CH934X 设备信息。 Future> getDeviceList() => _platform.getDeviceList(); /// 获取指定设备序列号;非 CH934X 设备时返回 null。 Future getSerialNumber(int deviceId) => _platform.getSerialNumber(deviceId); /// 获取指定设备类型,取值见 [Ch934xDeviceType]。 Future getDeviceType(int deviceId) => _platform.getDeviceType(deviceId); /// 获取指定设备的串口列表。 Future> getSerialPortList( int deviceId, { required int interfaceNumber, }) => _platform.getSerialPortList( deviceId, interfaceNumber: interfaceNumber, ); // --------------------------------------------------------------------------- // 设备打开 / 关闭 // --------------------------------------------------------------------------- /// 打开指定串口。 Future openPort(Ch934xPortTarget target) => _platform.openPort(target); /// 关闭当前会话最近一次打开的串口。 Future closePort() => _platform.closePort(); /// 切换当前活跃串口(同一 UsbDevice 内部的不同串口)。 /// /// CH934X 设备一次 `openPort` 之后所有串口已连接,后续 /// 读写只需切换 `serialPortIndex`,无需重新 open。 Future setActivePort(int serialPortIndex) => _platform.setActivePort(serialPortIndex); /// 主动申请指定设备的 USB 权限。 /// /// 正常情况下 `openPort` 内部会自动申请,本方法用于业务 /// 方希望提前引导用户授权的场景,例如在主界面"刷新设备 /// 列表"之后立刻弹一次授权请求。 Future requestUsbPermission(int deviceId) => _platform.requestUsbPermission(deviceId); // --------------------------------------------------------------------------- // 串口读写 // --------------------------------------------------------------------------- /// 阻塞式读取,直到拿到 [length] 字节或缓冲区被填满。 /// /// 返回值为实际读到的字节;若底层无数据或读取失败,返回空。 Future read(int length) => _platform.read(length); /// 写入数据,返回实际写入的字节数。 /// /// [serialPortIndex] 为空时沿用当前活跃串口;传入时直接写入指定端口, /// 不会改变当前活跃串口。 Future write(Uint8List data, {int? serialPortIndex}) => _platform.write(data, serialPortIndex: serialPortIndex); /// 构造一个持续从串口拉取数据的 `Stream`。 /// /// 内部以 [interval] 为周期反复调用 [read];当底层无数据 /// 时返回空缓冲区,消费者可据此判定是否需要结束订阅。 Stream dataStream({ int chunkSize = 1024, Duration interval = const Duration(milliseconds: 20), }) async* { if (chunkSize <= 0) { throw ArgumentError.value(chunkSize, 'chunkSize', '必须大于 0'); } while (true) { final chunk = await _platform.read(chunkSize); if (chunk.isNotEmpty) { yield chunk; } await Future.delayed(interval); } } /// 多端口并发轮询流:每周期轮询 8 个端口各一次,返回 (portIndex, data) 元组。 /// /// 各端口数据互不干扰,消费者端需要用每个端口独立的缓冲区拆分 \r\n 行。 /// 不传 [ports] 时默认轮询 0..7 全部端口。 Stream<(int, Uint8List)> portDataStream({ int chunkSize = 1024, Duration interval = const Duration(milliseconds: 25), List ports = const [0, 1, 2, 3, 4, 5, 6, 7], }) async* { if (chunkSize <= 0) { throw ArgumentError.value(chunkSize, 'chunkSize', '必须大于 0'); } while (true) { for (final port in ports) { final chunk = await _platform.read(chunkSize, serialPortIndex: port); if (chunk.isNotEmpty) { yield (port, chunk); } } await Future.delayed(interval); } } // --------------------------------------------------------------------------- // GPIO // --------------------------------------------------------------------------- /// 设置 GPIO 输出电平(0 或 1)。 Future setGpioOutput({required int gpioNumber, required int level}) => _platform.setGpioOutput(gpioNumber: gpioNumber, level: level); /// 读取 GPIO 输入电平;负值表示读取失败。 Future getGpioInput(int gpioNumber) => _platform.getGpioInput(gpioNumber); // --------------------------------------------------------------------------- // Modem // --------------------------------------------------------------------------- /// 设置 DTR / RTS 信号。 Future setModemControl({required int dtr, required int rts}) => _platform.setModemControl(dtr: dtr, rts: rts); /// 获取 Modem 状态位,可通过 [ModemStatus] 工具类解析。 Future getModemStatus() => _platform.getModemStatus(); // --------------------------------------------------------------------------- // 异常回调 // --------------------------------------------------------------------------- /// 注册异常回调(例如设备拔出)。 /// /// 返回一个 [StreamSubscription],可在外层 dispose 时取消。 Future> setExceptionCallback( void Function(Ch934xException exception) onException, ) async { final controller = StreamController(); final subscription = controller.stream.listen(onException); await _platform.setExceptionCallback(controller.add); return subscription; } // --------------------------------------------------------------------------- // 新增接口(文档补充的完整 SDK API) // --------------------------------------------------------------------------- /// 设置 Break 信号。 Future setBreak(bool valid) => _platform.setBreak(valid); /// 获取当前串口模式。 Future getCurrentMode() => _platform.getCurrentMode(); /// 获取 GPIO 数量。 Future getGpiocount(int deviceId) => _platform.getGpiocount(deviceId); /// 获取 GPIO 组数。 Future getGpiogroup(int deviceId) => _platform.getGpiogroup(deviceId); /// 使能 GPIO。 Future enableGpio({ required int chipType, required int gpioGroup, required int enable, }) => _platform.enableGpio( chipType: chipType, gpioGroup: gpioGroup, enable: enable, ); /// 设置 GPIO 方向。 Future setGpioDir({ required int gpioGroup, required int gpioNumber, required int dir, }) => _platform.setGpioDir( gpioGroup: gpioGroup, gpioNumber: gpioNumber, dir: dir, ); /// 从缓存查询 GPIO 方向。 Future queryGpioDirFromCache({ required int gpioGroup, required int gpioNumber, }) => _platform.queryGpioDirFromCache( gpioGroup: gpioGroup, gpioNumber: gpioNumber, ); /// 查询设备是否已打开。 Future isConnected(int deviceId) => _platform.isConnected(deviceId); /// 获取当前已打开的设备 ID 列表。 Future> getConnectedDevices() => _platform.getConnectedDevices(); /// 配置当前活跃串口的参数。 Future setSerialParameter({ required int baud, int dataBit = 8, int stopBit = 1, int parityBit = 0, bool flow = false, }) => _platform.setSerialParameter( baud: baud, dataBit: dataBit, stopBit: stopBit, parityBit: parityBit, flow: flow, ); }