1
This commit is contained in:
491
lib/src/ch34_manager.dart
Normal file
491
lib/src/ch34_manager.dart
Normal file
@@ -0,0 +1,491 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'ch34_platform_interface.dart';
|
||||
import 'types/ch34_types.dart';
|
||||
|
||||
/// CH34X USB 转串口插件的管理器。
|
||||
///
|
||||
/// 提供静态方法访问所有 WCH WCHUARTManager API。
|
||||
/// 所有方法委托给 [Ch34Platform.instance] 实现。
|
||||
class Ch34Manager {
|
||||
Ch34Manager._();
|
||||
|
||||
/// ==================== 基础方法 ====================
|
||||
|
||||
/// 获取平台版本。
|
||||
///
|
||||
/// @return 平台版本字符串。
|
||||
static Future<String?> getPlatformVersion() {
|
||||
return Ch34Platform.instance.getPlatformVersion();
|
||||
}
|
||||
|
||||
/// ==================== 设备枚举与识别 ====================
|
||||
|
||||
/// 枚举当前所有可用的 USB 设备。
|
||||
///
|
||||
/// @return 可用 USB 设备列表。
|
||||
/// @throws Ch34Exception 如果枚举失败。
|
||||
static Future<List<UsbDeviceInfo>> enumDevice() {
|
||||
return Ch34Platform.instance.enumDevice();
|
||||
}
|
||||
|
||||
/// 获取该 UsbDevice 的芯片型号。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @return 芯片型号字符串,null 表示无法识别。
|
||||
static Future<String?> getChipType(String deviceName) {
|
||||
return Ch34Platform.instance.getChipType(deviceName);
|
||||
}
|
||||
|
||||
/// ==================== 设备打开与权限 ====================
|
||||
|
||||
/// 打开 USB 设备。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @return `true` 成功,`false` 失败。
|
||||
static Future<bool> openDevice(String deviceName) {
|
||||
return Ch34Platform.instance.openDevice(deviceName);
|
||||
}
|
||||
|
||||
/// 申请 USB 设备的权限。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @return `true` 已授权,`false` 被拒绝。
|
||||
static Future<bool> requestPermission(String deviceName) {
|
||||
return Ch34Platform.instance.requestPermission(deviceName);
|
||||
}
|
||||
|
||||
/// ==================== USB 状态监听 ====================
|
||||
|
||||
/// 注册 USB 设备插拔状态监听。
|
||||
///
|
||||
/// @param onStateChanged 状态变化回调。
|
||||
static void setUsbStateListener(
|
||||
void Function(String deviceName, bool connected) onStateChanged) {
|
||||
Ch34Platform.instance.setUsbStateListener(onStateChanged);
|
||||
}
|
||||
|
||||
/// 移除 USB 状态监听。
|
||||
static void removeUsbStateListener() {
|
||||
Ch34Platform.instance.removeUsbStateListener();
|
||||
}
|
||||
|
||||
/// ==================== 串口信息 ====================
|
||||
|
||||
/// 获取设备的串口数目。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @return 串口数目,-1 表示读取芯片型号失败。
|
||||
static Future<int> getSerialCount(String deviceName) {
|
||||
return Ch34Platform.instance.getSerialCount(deviceName);
|
||||
}
|
||||
|
||||
/// 获取串口波特率。
|
||||
///
|
||||
/// 实际仅针对 CH9114 系列有效,其他类型设备无需调用。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param serialNumber 串口号。
|
||||
/// @return 大于 0 表示串口波特率,小于 0 表示出错。
|
||||
static Future<int> getSerialBaud(String deviceName, int serialNumber) {
|
||||
return Ch34Platform.instance.getSerialBaud(deviceName, serialNumber);
|
||||
}
|
||||
|
||||
/// 获取芯片主频。
|
||||
///
|
||||
/// 实际仅针对 CH9114 系列有效,其他类型设备无需调用。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @return 芯片主频信息对象。
|
||||
static Future<ChipMasterFrequency> getChipMasterFrequency(String deviceName) {
|
||||
return Ch34Platform.instance.getChipMasterFrequency(deviceName);
|
||||
}
|
||||
|
||||
/// 打开或关闭串口。
|
||||
///
|
||||
/// 实际仅针对 CH9114 系列有效,其他类型设备无需调用。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param serialNumber 串口号。
|
||||
/// @param enable `true` 打开,`false` 关闭。
|
||||
/// @return `true` 设置成功,`false` 设置失败。
|
||||
static Future<bool> enableSerial(
|
||||
String deviceName,
|
||||
int serialNumber,
|
||||
bool enable,
|
||||
) {
|
||||
return Ch34Platform.instance.enableSerial(deviceName, serialNumber, enable);
|
||||
}
|
||||
|
||||
/// ==================== 串口参数设置 ====================
|
||||
|
||||
/// 设置串口参数。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param serialNumber 串口号(从 0 开始)。
|
||||
/// @param parameter 串口参数配置。
|
||||
/// @return `true` 设置成功,`false` 设置失败。
|
||||
static Future<bool> setSerialParameter(
|
||||
String deviceName,
|
||||
int serialNumber,
|
||||
SerialParameter parameter,
|
||||
) {
|
||||
return Ch34Platform.instance.setSerialParameter(
|
||||
deviceName,
|
||||
serialNumber,
|
||||
parameter,
|
||||
);
|
||||
}
|
||||
|
||||
/// ==================== 数据读写 ====================
|
||||
|
||||
/// 发送串口数据(同步发送)。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param serialNumber 串口号。
|
||||
/// @param data 要发送的数据。
|
||||
/// @param timeout 超时时间(毫秒),0 表示不超时。
|
||||
/// @return 实际发送的字节数。
|
||||
static Future<int> writeData(
|
||||
String deviceName,
|
||||
int serialNumber,
|
||||
Uint8List data, {
|
||||
int timeout = 0,
|
||||
}) {
|
||||
return Ch34Platform.instance.writeData(
|
||||
deviceName,
|
||||
serialNumber,
|
||||
data,
|
||||
timeout: timeout,
|
||||
);
|
||||
}
|
||||
|
||||
/// 发送串口数据(异步发送)。
|
||||
///
|
||||
/// 将数据加入缓存持续发送,不返回状态和结果。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param serialNumber 串口号。
|
||||
/// @param data 要发送的数据。
|
||||
static Future<void> asyncWriteData(
|
||||
String deviceName,
|
||||
int serialNumber,
|
||||
Uint8List data,
|
||||
) {
|
||||
return Ch34Platform.instance.asyncWriteData(
|
||||
deviceName,
|
||||
serialNumber,
|
||||
data,
|
||||
);
|
||||
}
|
||||
|
||||
/// 阻塞读取串口数据。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param serialNumber 串口号。
|
||||
/// @return 读取到的数据。
|
||||
static Future<Uint8List> readData(
|
||||
String deviceName,
|
||||
int serialNumber,
|
||||
) {
|
||||
return Ch34Platform.instance.readData(deviceName, serialNumber);
|
||||
}
|
||||
|
||||
/// 主动读取串口数据(带超时参数)。
|
||||
///
|
||||
/// 读取行为说明:
|
||||
/// - 当 vTime>0,vMin>0 时:阻塞直到读取到第一个字符后开始计时,
|
||||
/// 时间到或已读够 vMin 个字符则返回。
|
||||
/// - 当 vTime>0,vMin=0 时:读到数据立即返回,否则最多等待 vTime。
|
||||
/// - 当 vTime=0,vMin>0 时:一直阻塞直到读到 vMin 个字符后返回。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param serialNumber 串口号。
|
||||
/// @param vTime 等待时间(毫秒)。
|
||||
/// @param vMin 读取的最小字节数。
|
||||
/// @return 读取到的数据。
|
||||
static Future<Uint8List> readDataWithTimeout(
|
||||
String deviceName,
|
||||
int serialNumber,
|
||||
int vTime,
|
||||
int vMin,
|
||||
) {
|
||||
return Ch34Platform.instance.readDataWithTimeout(
|
||||
deviceName,
|
||||
serialNumber,
|
||||
vTime,
|
||||
vMin,
|
||||
);
|
||||
}
|
||||
|
||||
/// 注册串口数据回调。
|
||||
///
|
||||
/// 注册后数据自动推送,不需要主动调用 [readData]。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param serialNumber 串口号。
|
||||
/// @param onData 数据接收回调。
|
||||
static Future<void> registerDataCallback(
|
||||
String deviceName,
|
||||
int serialNumber,
|
||||
void Function(Uint8List data) onData,
|
||||
) {
|
||||
return Ch34Platform.instance.registerDataCallback(
|
||||
deviceName,
|
||||
serialNumber,
|
||||
onData,
|
||||
);
|
||||
}
|
||||
|
||||
/// 取消注册串口数据回调。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
static void removeDataCallback(String deviceName) {
|
||||
Ch34Platform.instance.removeDataCallback(deviceName);
|
||||
}
|
||||
|
||||
/// ==================== 连接状态 ====================
|
||||
|
||||
/// 判断 USB 设备是否已经连接。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @return `true` 已连接,`false` 未连接。
|
||||
static Future<bool> isConnected(String deviceName) {
|
||||
return Ch34Platform.instance.isConnected(deviceName);
|
||||
}
|
||||
|
||||
/// 获取当前已经打开的设备列表。
|
||||
///
|
||||
/// @return 已打开的设备名称列表。
|
||||
static Future<List<String>> getConnectedDevices() {
|
||||
return Ch34Platform.instance.getConnectedDevices();
|
||||
}
|
||||
|
||||
/// ==================== 断开与关闭 ====================
|
||||
|
||||
/// 断开 USB 设备的连接。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
static Future<void> disconnect(String deviceName) {
|
||||
return Ch34Platform.instance.disconnect(deviceName);
|
||||
}
|
||||
|
||||
/// 释放资源,关闭所有串口设备。
|
||||
static Future<void> close() {
|
||||
return Ch34Platform.instance.close();
|
||||
}
|
||||
|
||||
/// ==================== GPIO 功能 ====================
|
||||
|
||||
/// 查询设备是否支持 GPIO 功能。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @return `true` 支持,`false` 不支持。
|
||||
static Future<bool> isSupportGpio(String deviceName) {
|
||||
return Ch34Platform.instance.isSupportGpio(deviceName);
|
||||
}
|
||||
|
||||
/// 查询该 USB 设备的 GPIO 数目。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @return GPIO 数目。
|
||||
static Future<int> queryGpioCount(String deviceName) {
|
||||
return Ch34Platform.instance.queryGpioCount(deviceName);
|
||||
}
|
||||
|
||||
/// 查询该 USB 设备指定 GPIO 的状态。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param gpioIndex GPIO 编号(从 0 开始)。
|
||||
/// @return GPIO 状态。
|
||||
static Future<GpioStatus> queryGpioStatus(
|
||||
String deviceName,
|
||||
int gpioIndex,
|
||||
) {
|
||||
return Ch34Platform.instance.queryGpioStatus(deviceName, gpioIndex);
|
||||
}
|
||||
|
||||
/// 查询该 USB 设备的所有 GPIO 状态。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @return 全部 GPIO 状态列表。
|
||||
static Future<List<GpioStatus>> queryAllGpioStatus(String deviceName) {
|
||||
return Ch34Platform.instance.queryAllGpioStatus(deviceName);
|
||||
}
|
||||
|
||||
/// 使能指定 GPIO。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param gpioIndex GPIO 编号。
|
||||
/// @param enable `true` 使能,`false` 关闭。
|
||||
/// @param direction GPIO 方向。
|
||||
/// @return `true` 使能成功,`false` 使能失败。
|
||||
static Future<bool> enableGpio(
|
||||
String deviceName,
|
||||
int gpioIndex,
|
||||
bool enable,
|
||||
GpioDirection direction,
|
||||
) {
|
||||
return Ch34Platform.instance.enableGpio(
|
||||
deviceName,
|
||||
gpioIndex,
|
||||
enable,
|
||||
direction,
|
||||
);
|
||||
}
|
||||
|
||||
/// 设置指定 GPIO 的电平值。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param gpioIndex GPIO 编号。
|
||||
/// @param value GPIO 电平值。
|
||||
/// @return `true` 设置成功,`false` 设置失败。
|
||||
static Future<bool> setGpioVal(
|
||||
String deviceName,
|
||||
int gpioIndex,
|
||||
GpioValue value,
|
||||
) {
|
||||
return Ch34Platform.instance.setGpioVal(
|
||||
deviceName,
|
||||
gpioIndex,
|
||||
value,
|
||||
);
|
||||
}
|
||||
|
||||
/// 获取指定 GPIO 的电平值。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param gpioIndex GPIO 编号。
|
||||
/// @return GPIO 电平值。
|
||||
static Future<GpioValue> getGpioVal(
|
||||
String deviceName,
|
||||
int gpioIndex,
|
||||
) {
|
||||
return Ch34Platform.instance.getGpioVal(deviceName, gpioIndex);
|
||||
}
|
||||
|
||||
/// ==================== 信号控制 ====================
|
||||
|
||||
/// 设置 DTR 信号。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param serialNumber 串口号。
|
||||
/// @param valid 是否有效(低电平有效)。
|
||||
/// @return `true` 设置成功,`false` 设置失败。
|
||||
static Future<bool> setDtr(
|
||||
String deviceName,
|
||||
int serialNumber,
|
||||
bool valid,
|
||||
) {
|
||||
return Ch34Platform.instance.setDtr(deviceName, serialNumber, valid);
|
||||
}
|
||||
|
||||
/// 设置 RTS 信号。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param serialNumber 串口号。
|
||||
/// @param valid 是否有效(低电平有效)。
|
||||
/// @return `true` 设置成功,`false` 设置失败。
|
||||
static Future<bool> setRts(
|
||||
String deviceName,
|
||||
int serialNumber,
|
||||
bool valid,
|
||||
) {
|
||||
return Ch34Platform.instance.setRts(deviceName, serialNumber, valid);
|
||||
}
|
||||
|
||||
/// 设置 Break 信号。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param serialNumber 串口号。
|
||||
/// @param valid 是否有效(低电平有效)。
|
||||
/// @return `true` 设置成功,`false` 设置失败。
|
||||
static Future<bool> setBreakSignal(
|
||||
String deviceName,
|
||||
int serialNumber,
|
||||
bool valid,
|
||||
) {
|
||||
return Ch34Platform.instance.setBreakSignal(
|
||||
deviceName,
|
||||
serialNumber,
|
||||
valid,
|
||||
);
|
||||
}
|
||||
|
||||
/// ==================== Modem 状态回调 ====================
|
||||
|
||||
/// 注册 Modem 控制信号状态回调。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param onModemStatus Modem 状态变化回调。
|
||||
static Future<void> registerModemStatusCallback(
|
||||
String deviceName,
|
||||
void Function(ModemStatus status) onModemStatus,
|
||||
) {
|
||||
return Ch34Platform.instance.registerModemStatusCallback(
|
||||
deviceName,
|
||||
onModemStatus,
|
||||
);
|
||||
}
|
||||
|
||||
/// 移除 Modem 状态回调。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
static void removeModemStatusCallback(String deviceName) {
|
||||
Ch34Platform.instance.removeModemStatusCallback(deviceName);
|
||||
}
|
||||
|
||||
/// ==================== 错误查询 ====================
|
||||
|
||||
/// 查询串口错误状态。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param serialNumber 串口号。
|
||||
/// @param errorType 错误类型。
|
||||
/// @return 该种错误出现的次数。
|
||||
static Future<int> querySerialErrorCount(
|
||||
String deviceName,
|
||||
int serialNumber,
|
||||
SerialErrorType errorType,
|
||||
) {
|
||||
return Ch34Platform.instance.querySerialErrorCount(
|
||||
deviceName,
|
||||
serialNumber,
|
||||
errorType,
|
||||
);
|
||||
}
|
||||
|
||||
/// ==================== 全局配置 ====================
|
||||
|
||||
/// 设置读取超时时间。
|
||||
///
|
||||
/// 全局有效,应在 APP 初始化时调用。
|
||||
///
|
||||
/// @param timeout 超时时间(毫秒)。
|
||||
static Future<void> setReadTimeout(int timeout) {
|
||||
return Ch34Platform.instance.setReadTimeout(timeout);
|
||||
}
|
||||
|
||||
/// 添加自定义硬件 VID/PID。
|
||||
///
|
||||
/// @param vid 硬件 VID。
|
||||
/// @param pid 硬件 PID。
|
||||
/// @param chipType 芯片类型(必填,如 "CH340"、"CH9102")。
|
||||
static Future<void> addNewHardware(int vid, int pid, String chipType) {
|
||||
return Ch34Platform.instance.addNewHardware(vid, pid, chipType);
|
||||
}
|
||||
|
||||
/// 设置调试模式。
|
||||
///
|
||||
/// @param enabled `true` 开启,`false` 关闭。
|
||||
static Future<void> setDebug(bool enabled) {
|
||||
return Ch34Platform.instance.setDebug(enabled);
|
||||
}
|
||||
|
||||
/// 返回当前是否处于调试模式。
|
||||
///
|
||||
/// @return `true` 处于调试模式,`false` 不处于。
|
||||
static Future<bool> isDebugMode() {
|
||||
return Ch34Platform.instance.isDebugMode();
|
||||
}
|
||||
}
|
||||
589
lib/src/ch34_method_channel.dart
Normal file
589
lib/src/ch34_method_channel.dart
Normal file
@@ -0,0 +1,589 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'ch34_platform_interface.dart';
|
||||
import 'types/ch34_types.dart';
|
||||
|
||||
/// [Ch34Platform] 的 MethodChannel 实现。
|
||||
///
|
||||
/// 将平台接口方法映射到原生端 MethodChannel 调用,
|
||||
/// 使用 EventChannel 处理数据回调、Modem 状态和 USB 插拔事件。
|
||||
class MethodChannelCh34 extends Ch34Platform {
|
||||
/// 注册默认实例。
|
||||
static void registerDefault() {
|
||||
Ch34Platform.instance = MethodChannelCh34._();
|
||||
}
|
||||
|
||||
MethodChannelCh34._();
|
||||
|
||||
/// MethodChannel 名称。
|
||||
@visibleForTesting
|
||||
final methodChannel = const MethodChannel('ch34');
|
||||
|
||||
/// 数据 EventChannel 名称。
|
||||
@visibleForTesting
|
||||
final dataEventChannel = const EventChannel('ch34/data');
|
||||
|
||||
/// Modem 状态 EventChannel 名称。
|
||||
@visibleForTesting
|
||||
final modemEventChannel = const EventChannel('ch34/modem');
|
||||
|
||||
/// USB 状态 EventChannel 名称。
|
||||
@visibleForTesting
|
||||
final usbStateEventChannel = const EventChannel('ch34/usb_state');
|
||||
|
||||
// ==================== 事件流订阅 ====================
|
||||
|
||||
StreamSubscription? _dataSubscription;
|
||||
StreamSubscription? _modemSubscription;
|
||||
StreamSubscription? _usbStateSubscription;
|
||||
|
||||
void Function(String deviceName, bool connected)? _usbStateCallback;
|
||||
void Function(Uint8List data)? _dataCallback;
|
||||
void Function(ModemStatus status)? _modemCallback;
|
||||
|
||||
// ==================== 基础方法 ====================
|
||||
|
||||
@override
|
||||
Future<String?> getPlatformVersion() async {
|
||||
final version =
|
||||
await methodChannel.invokeMethod<String>('getPlatformVersion');
|
||||
return version;
|
||||
}
|
||||
|
||||
// ==================== 设备枚举与识别 ====================
|
||||
|
||||
@override
|
||||
Future<List<UsbDeviceInfo>> enumDevice() async {
|
||||
final result = await methodChannel.invokeMethod<List>('enumDevice');
|
||||
if (result == null) return [];
|
||||
return result
|
||||
.map((e) => UsbDeviceInfo.fromMap(e as Map<dynamic, dynamic>))
|
||||
.toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<String?> getChipType(String deviceName) async {
|
||||
return await methodChannel.invokeMethod<String>(
|
||||
'getChipType',
|
||||
{'deviceName': deviceName},
|
||||
);
|
||||
}
|
||||
|
||||
// ==================== 设备打开与权限 ====================
|
||||
|
||||
@override
|
||||
Future<bool> openDevice(String deviceName) async {
|
||||
final result = await methodChannel.invokeMethod<bool>(
|
||||
'openDevice',
|
||||
{'deviceName': deviceName},
|
||||
);
|
||||
return result ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> requestPermission(String deviceName) async {
|
||||
final result = await methodChannel.invokeMethod<bool>(
|
||||
'requestPermission',
|
||||
{'deviceName': deviceName},
|
||||
);
|
||||
return result ?? false;
|
||||
}
|
||||
|
||||
// ==================== USB 状态监听 ====================
|
||||
|
||||
@override
|
||||
void setUsbStateListener(
|
||||
void Function(String deviceName, bool connected) onStateChanged) {
|
||||
_usbStateCallback = onStateChanged;
|
||||
_usbStateSubscription?.cancel();
|
||||
_usbStateSubscription = usbStateEventChannel
|
||||
.receiveBroadcastStream()
|
||||
.listen(
|
||||
(event) {
|
||||
final map = event as Map<dynamic, dynamic>;
|
||||
final deviceName = map['deviceName'] as String;
|
||||
final connected = map['connected'] as bool;
|
||||
_usbStateCallback?.call(deviceName, connected);
|
||||
},
|
||||
onError: (error) {
|
||||
debugPrint('CH34 USB state error: $error');
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void removeUsbStateListener() {
|
||||
_usbStateSubscription?.cancel();
|
||||
_usbStateSubscription = null;
|
||||
_usbStateCallback = null;
|
||||
}
|
||||
|
||||
// ==================== 串口信息 ====================
|
||||
|
||||
@override
|
||||
Future<int> getSerialCount(String deviceName) async {
|
||||
final result = await methodChannel.invokeMethod<int>(
|
||||
'getSerialCount',
|
||||
{'deviceName': deviceName},
|
||||
);
|
||||
return result ?? -1;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> getSerialBaud(String deviceName, int serialNumber) async {
|
||||
final result = await methodChannel.invokeMethod<int>(
|
||||
'getSerialBaud',
|
||||
{
|
||||
'deviceName': deviceName,
|
||||
'serialNumber': serialNumber,
|
||||
},
|
||||
);
|
||||
return result ?? -1;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ChipMasterFrequency> getChipMasterFrequency(String deviceName) async {
|
||||
final result = await methodChannel.invokeMethod<Map>(
|
||||
'getChipMasterFrequency',
|
||||
{'deviceName': deviceName},
|
||||
);
|
||||
if (result == null) {
|
||||
throw const Ch34Exception('Failed to get chip master frequency');
|
||||
}
|
||||
return ChipMasterFrequency.fromMap(result);
|
||||
}
|
||||
|
||||
// ==================== 串口参数设置 ====================
|
||||
|
||||
@override
|
||||
Future<bool> enableSerial(
|
||||
String deviceName,
|
||||
int serialNumber,
|
||||
bool enable,
|
||||
) async {
|
||||
final result = await methodChannel.invokeMethod<bool>(
|
||||
'enableSerial',
|
||||
{
|
||||
'deviceName': deviceName,
|
||||
'serialNumber': serialNumber,
|
||||
'enable': enable,
|
||||
},
|
||||
);
|
||||
return result ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> setSerialParameter(
|
||||
String deviceName,
|
||||
int serialNumber,
|
||||
SerialParameter parameter,
|
||||
) async {
|
||||
final result = await methodChannel.invokeMethod<bool>(
|
||||
'setSerialParameter',
|
||||
{
|
||||
'deviceName': deviceName,
|
||||
'serialNumber': serialNumber,
|
||||
...parameter.toMap(),
|
||||
},
|
||||
);
|
||||
return result ?? false;
|
||||
}
|
||||
|
||||
// ==================== 数据读写 ====================
|
||||
|
||||
@override
|
||||
Future<int> writeData(
|
||||
String deviceName,
|
||||
int serialNumber,
|
||||
Uint8List data, {
|
||||
int timeout = 0,
|
||||
}) async {
|
||||
final result = await methodChannel.invokeMethod<int>(
|
||||
'writeData',
|
||||
{
|
||||
'deviceName': deviceName,
|
||||
'serialNumber': serialNumber,
|
||||
'data': data,
|
||||
'timeout': timeout,
|
||||
},
|
||||
);
|
||||
return result ?? 0;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> asyncWriteData(
|
||||
String deviceName,
|
||||
int serialNumber,
|
||||
Uint8List data,
|
||||
) async {
|
||||
await methodChannel.invokeMethod(
|
||||
'asyncWriteData',
|
||||
{
|
||||
'deviceName': deviceName,
|
||||
'serialNumber': serialNumber,
|
||||
'data': data,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Uint8List> readData(String deviceName, int serialNumber) async {
|
||||
final result = await methodChannel.invokeMethod<Uint8List>(
|
||||
'readData',
|
||||
{
|
||||
'deviceName': deviceName,
|
||||
'serialNumber': serialNumber,
|
||||
},
|
||||
);
|
||||
return result ?? Uint8List(0);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Uint8List> readDataWithTimeout(
|
||||
String deviceName,
|
||||
int serialNumber,
|
||||
int vTime,
|
||||
int vMin,
|
||||
) async {
|
||||
final result = await methodChannel.invokeMethod<Uint8List>(
|
||||
'readDataWithTimeout',
|
||||
{
|
||||
'deviceName': deviceName,
|
||||
'serialNumber': serialNumber,
|
||||
'vTime': vTime,
|
||||
'vMin': vMin,
|
||||
},
|
||||
);
|
||||
return result ?? Uint8List(0);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> registerDataCallback(
|
||||
String deviceName,
|
||||
int serialNumber,
|
||||
void Function(Uint8List data) onData,
|
||||
) async {
|
||||
_dataCallback = onData;
|
||||
await _cancelDataSubscription();
|
||||
_dataSubscription = dataEventChannel
|
||||
.receiveBroadcastStream({'deviceName': deviceName})
|
||||
.listen(
|
||||
(event) {
|
||||
if (event is Uint8List) {
|
||||
_dataCallback?.call(event);
|
||||
}
|
||||
},
|
||||
onError: (error) {
|
||||
debugPrint('CH34 data callback error: $error');
|
||||
},
|
||||
);
|
||||
await methodChannel.invokeMethod('registerDataCallback', {
|
||||
'deviceName': deviceName,
|
||||
'serialNumber': serialNumber,
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void removeDataCallback(String deviceName) {
|
||||
_cancelDataSubscription();
|
||||
methodChannel.invokeMethod('removeDataCallback', {
|
||||
'deviceName': deviceName,
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _cancelDataSubscription() async {
|
||||
await _dataSubscription?.cancel();
|
||||
_dataSubscription = null;
|
||||
_dataCallback = null;
|
||||
}
|
||||
|
||||
// ==================== 连接状态 ====================
|
||||
|
||||
@override
|
||||
Future<bool> isConnected(String deviceName) async {
|
||||
final result = await methodChannel.invokeMethod<bool>(
|
||||
'isConnected',
|
||||
{'deviceName': deviceName},
|
||||
);
|
||||
return result ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<String>> getConnectedDevices() async {
|
||||
final result = await methodChannel.invokeMethod<List>(
|
||||
'getConnectedDevices',
|
||||
);
|
||||
if (result == null) return [];
|
||||
return result.map((e) => e.toString()).toList();
|
||||
}
|
||||
|
||||
// ==================== 断开与关闭 ====================
|
||||
|
||||
@override
|
||||
Future<void> disconnect(String deviceName) async {
|
||||
await methodChannel.invokeMethod(
|
||||
'disconnect',
|
||||
{'deviceName': deviceName},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
// 清理所有订阅
|
||||
await _cancelDataSubscription();
|
||||
await _modemSubscription?.cancel();
|
||||
_modemSubscription = null;
|
||||
_modemCallback = null;
|
||||
_usbStateSubscription?.cancel();
|
||||
_usbStateSubscription = null;
|
||||
_usbStateCallback = null;
|
||||
|
||||
await methodChannel.invokeMethod('close');
|
||||
}
|
||||
|
||||
// ==================== GPIO 功能 ====================
|
||||
|
||||
@override
|
||||
Future<bool> isSupportGpio(String deviceName) async {
|
||||
final result = await methodChannel.invokeMethod<bool>(
|
||||
'isSupportGpio',
|
||||
{'deviceName': deviceName},
|
||||
);
|
||||
return result ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> queryGpioCount(String deviceName) async {
|
||||
final result = await methodChannel.invokeMethod<int>(
|
||||
'queryGpioCount',
|
||||
{'deviceName': deviceName},
|
||||
);
|
||||
return result ?? 0;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<GpioStatus> queryGpioStatus(String deviceName, int gpioIndex) async {
|
||||
final result = await methodChannel.invokeMethod<Map>(
|
||||
'queryGpioStatus',
|
||||
{
|
||||
'deviceName': deviceName,
|
||||
'gpioIndex': gpioIndex,
|
||||
},
|
||||
);
|
||||
if (result == null) {
|
||||
throw const Ch34Exception('Failed to query GPIO status');
|
||||
}
|
||||
return GpioStatus.fromMap(result);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<GpioStatus>> queryAllGpioStatus(String deviceName) async {
|
||||
final result = await methodChannel.invokeMethod<List>(
|
||||
'queryAllGpioStatus',
|
||||
{'deviceName': deviceName},
|
||||
);
|
||||
if (result == null) return [];
|
||||
return result
|
||||
.map((e) => GpioStatus.fromMap(e as Map<dynamic, dynamic>))
|
||||
.toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> enableGpio(
|
||||
String deviceName,
|
||||
int gpioIndex,
|
||||
bool enable,
|
||||
GpioDirection direction,
|
||||
) async {
|
||||
final result = await methodChannel.invokeMethod<bool>(
|
||||
'enableGpio',
|
||||
{
|
||||
'deviceName': deviceName,
|
||||
'gpioIndex': gpioIndex,
|
||||
'enable': enable,
|
||||
'direction': direction.index,
|
||||
},
|
||||
);
|
||||
return result ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> setGpioVal(
|
||||
String deviceName,
|
||||
int gpioIndex,
|
||||
GpioValue value,
|
||||
) async {
|
||||
final result = await methodChannel.invokeMethod<bool>(
|
||||
'setGpioVal',
|
||||
{
|
||||
'deviceName': deviceName,
|
||||
'gpioIndex': gpioIndex,
|
||||
'value': value.index,
|
||||
},
|
||||
);
|
||||
return result ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<GpioValue> getGpioVal(String deviceName, int gpioIndex) async {
|
||||
final result = await methodChannel.invokeMethod<int>(
|
||||
'getGpioVal',
|
||||
{
|
||||
'deviceName': deviceName,
|
||||
'gpioIndex': gpioIndex,
|
||||
},
|
||||
);
|
||||
if (result == null) {
|
||||
throw const Ch34Exception('Failed to get GPIO value');
|
||||
}
|
||||
return GpioValue.values[result];
|
||||
}
|
||||
|
||||
// ==================== 信号控制 ====================
|
||||
|
||||
@override
|
||||
Future<bool> setDtr(String deviceName, int serialNumber, bool valid) async {
|
||||
final result = await methodChannel.invokeMethod<bool>(
|
||||
'setDtr',
|
||||
{
|
||||
'deviceName': deviceName,
|
||||
'serialNumber': serialNumber,
|
||||
'valid': valid,
|
||||
},
|
||||
);
|
||||
return result ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> setRts(String deviceName, int serialNumber, bool valid) async {
|
||||
final result = await methodChannel.invokeMethod<bool>(
|
||||
'setRts',
|
||||
{
|
||||
'deviceName': deviceName,
|
||||
'serialNumber': serialNumber,
|
||||
'valid': valid,
|
||||
},
|
||||
);
|
||||
return result ?? false;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> setBreakSignal(
|
||||
String deviceName, int serialNumber, bool valid) async {
|
||||
final result = await methodChannel.invokeMethod<bool>(
|
||||
'setBreak',
|
||||
{
|
||||
'deviceName': deviceName,
|
||||
'serialNumber': serialNumber,
|
||||
'valid': valid,
|
||||
},
|
||||
);
|
||||
return result ?? false;
|
||||
}
|
||||
|
||||
// ==================== Modem 状态回调 ====================
|
||||
|
||||
@override
|
||||
Future<void> registerModemStatusCallback(
|
||||
String deviceName,
|
||||
void Function(ModemStatus status) onModemStatus,
|
||||
) async {
|
||||
_modemCallback = onModemStatus;
|
||||
await _modemSubscription?.cancel();
|
||||
_modemSubscription = modemEventChannel
|
||||
.receiveBroadcastStream({'deviceName': deviceName})
|
||||
.listen(
|
||||
(event) {
|
||||
final map = event as Map<dynamic, dynamic>;
|
||||
debugPrint('CH34 modem event received: $map');
|
||||
_modemCallback?.call(ModemStatus.fromMap(map));
|
||||
},
|
||||
onError: (error) {
|
||||
debugPrint('CH34 modem callback error: $error');
|
||||
},
|
||||
);
|
||||
await methodChannel.invokeMethod('registerModemStatusCallback', {
|
||||
'deviceName': deviceName,
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void removeModemStatusCallback(String deviceName) {
|
||||
_modemSubscription?.cancel();
|
||||
_modemSubscription = null;
|
||||
_modemCallback = null;
|
||||
methodChannel.invokeMethod('removeModemStatusCallback', {
|
||||
'deviceName': deviceName,
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== 错误查询 ====================
|
||||
|
||||
@override
|
||||
Future<int> querySerialErrorCount(
|
||||
String deviceName,
|
||||
int serialNumber,
|
||||
SerialErrorType errorType,
|
||||
) async {
|
||||
final result = await methodChannel.invokeMethod<int>(
|
||||
'querySerialErrorCount',
|
||||
{
|
||||
'deviceName': deviceName,
|
||||
'serialNumber': serialNumber,
|
||||
'errorType': errorType.toNativeString(),
|
||||
},
|
||||
);
|
||||
return result ?? 0;
|
||||
}
|
||||
|
||||
// ==================== 全局配置 ====================
|
||||
|
||||
@override
|
||||
Future<void> setReadTimeout(int timeout) async {
|
||||
await methodChannel.invokeMethod(
|
||||
'setReadTimeout',
|
||||
{'timeout': timeout},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> addNewHardware(int vid, int pid, String chipType) async {
|
||||
await methodChannel.invokeMethod(
|
||||
'addNewHardware',
|
||||
{
|
||||
'vid': vid,
|
||||
'pid': pid,
|
||||
'chipType': chipType,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> setDebug(bool enabled) async {
|
||||
await methodChannel.invokeMethod(
|
||||
'setDebug',
|
||||
{'enabled': enabled},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> isDebugMode() async {
|
||||
final result =
|
||||
await methodChannel.invokeMethod<bool>('isDebugMode');
|
||||
return result ?? false;
|
||||
}
|
||||
}
|
||||
|
||||
/// CH34 插件自定义异常。
|
||||
class Ch34Exception implements Exception {
|
||||
const Ch34Exception(this.message);
|
||||
|
||||
/// 异常描述。
|
||||
final String message;
|
||||
|
||||
@override
|
||||
String toString() => 'Ch34Exception: $message';
|
||||
}
|
||||
418
lib/src/ch34_platform_interface.dart
Normal file
418
lib/src/ch34_platform_interface.dart
Normal file
@@ -0,0 +1,418 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
|
||||
|
||||
import 'types/ch34_types.dart';
|
||||
|
||||
/// CH34X USB 转串口插件的抽象平台接口。
|
||||
///
|
||||
/// 定义所有 WCH WCHUARTManager API 的方法签名。
|
||||
/// 具体实现由 `MethodChannelCh34` 提供。
|
||||
abstract class Ch34Platform extends PlatformInterface {
|
||||
/// Constructs a Ch34Platform.
|
||||
Ch34Platform() : super(token: _token);
|
||||
|
||||
static final Object _token = Object();
|
||||
|
||||
static Ch34Platform? _instance;
|
||||
|
||||
/// The default instance of [Ch34Platform] to use.
|
||||
///
|
||||
/// Defaults to [MethodChannelCh34].
|
||||
/// 注意: 需要在应用初始化时调用 [Ch34Platform.registerDefaultInstance] 注册默认实例。
|
||||
static Ch34Platform get instance {
|
||||
if (_instance == null) {
|
||||
throw StateError(
|
||||
'Ch34Platform.instance has not been initialized. '
|
||||
'Ensure the plugin is properly registered.',
|
||||
);
|
||||
}
|
||||
return _instance!;
|
||||
}
|
||||
|
||||
/// 注册默认平台实例。
|
||||
///
|
||||
/// 通常在插件初始化时由 [MethodChannelCh34] 调用。
|
||||
static void registerDefaultInstance(Ch34Platform instance) {
|
||||
PlatformInterface.verifyToken(instance, _token);
|
||||
_instance = instance;
|
||||
}
|
||||
|
||||
/// Platform-specific implementations should set this with their own
|
||||
/// platform-specific class that extends [Ch34Platform] when they register
|
||||
/// themselves.
|
||||
static set instance(Ch34Platform instance) {
|
||||
PlatformInterface.verifyToken(instance, _token);
|
||||
_instance = instance;
|
||||
}
|
||||
|
||||
/// ==================== 基础方法 ====================
|
||||
|
||||
/// 获取平台版本。
|
||||
///
|
||||
/// @return 平台版本字符串。
|
||||
Future<String?> getPlatformVersion();
|
||||
|
||||
/// ==================== 设备枚举与识别 ====================
|
||||
|
||||
/// 枚举当前所有可用的 USB 设备。
|
||||
///
|
||||
/// 返回设备信息列表,包含 VID/PID、串口数量等。
|
||||
///
|
||||
/// @return 可用 USB 设备列表。
|
||||
/// @throws Ch34Exception 如果枚举失败。
|
||||
Future<List<UsbDeviceInfo>> enumDevice();
|
||||
|
||||
/// 获取该 UsbDevice 的芯片型号。
|
||||
///
|
||||
/// @param deviceName 设备名称(由 [enumDevice] 返回的 deviceName)。
|
||||
/// @return 芯片型号字符串。如果为 null,表示无法识别。
|
||||
Future<String?> getChipType(String deviceName);
|
||||
|
||||
/// ==================== 设备打开与权限 ====================
|
||||
|
||||
/// 打开 USB 设备。
|
||||
///
|
||||
/// 打开设备后可以进行串口通信。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @return `true` 成功,`false` 失败。
|
||||
Future<bool> openDevice(String deviceName);
|
||||
|
||||
/// 申请 USB 设备的权限。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @return `true` 已授权,`false` 被拒绝。
|
||||
Future<bool> requestPermission(String deviceName);
|
||||
|
||||
/// ==================== USB 状态监听 ====================
|
||||
|
||||
/// 注册 USB 设备插拔状态监听。
|
||||
///
|
||||
/// 通过 EventChannel 监听设备的连接和断开事件。
|
||||
///
|
||||
/// @param onStateChanged 状态变化回调,参数为设备名称和是否已连接。
|
||||
void setUsbStateListener(void Function(String deviceName, bool connected) onStateChanged);
|
||||
|
||||
/// 移除 USB 状态监听。
|
||||
void removeUsbStateListener();
|
||||
|
||||
/// ==================== 串口信息 ====================
|
||||
|
||||
/// 获取设备的串口数目。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @return 串口数目;如果为 -1,说明读取芯片型号失败。
|
||||
Future<int> getSerialCount(String deviceName);
|
||||
|
||||
/// 获取串口波特率。
|
||||
///
|
||||
/// 实际仅针对 CH9114 系列有效,其他类型设备无需调用。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param serialNumber 串口号。
|
||||
/// @return 大于 0 表示串口波特率,小于 0 表示出错。
|
||||
Future<int> getSerialBaud(String deviceName, int serialNumber);
|
||||
|
||||
/// 获取芯片主频。
|
||||
///
|
||||
/// 实际仅针对 CH9114 系列有效,其他类型设备无需调用。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @return 芯片主频信息对象。
|
||||
Future<ChipMasterFrequency> getChipMasterFrequency(String deviceName);
|
||||
|
||||
/// 打开或关闭串口。
|
||||
///
|
||||
/// 实际仅针对 CH9114 系列有效,其他类型设备无需调用。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param serialNumber 串口号。
|
||||
/// @param enable `true` 打开,`false` 关闭。
|
||||
/// @return `true` 设置成功,`false` 设置失败。
|
||||
/// @throws Ch34Exception 如果操作失败。
|
||||
Future<bool> enableSerial(String deviceName, int serialNumber, bool enable);
|
||||
|
||||
/// ==================== 串口参数设置 ====================
|
||||
|
||||
/// 设置串口参数。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param serialNumber 串口号(从 0 开始)。
|
||||
/// @param parameter 串口参数配置。
|
||||
/// @return `true` 设置成功,`false` 设置失败。
|
||||
/// @throws Ch34Exception 如果参数无效或设备未打开。
|
||||
Future<bool> setSerialParameter(
|
||||
String deviceName,
|
||||
int serialNumber,
|
||||
SerialParameter parameter,
|
||||
);
|
||||
|
||||
/// ==================== 数据读写 ====================
|
||||
|
||||
/// 发送串口数据(同步发送)。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param serialNumber 串口号。
|
||||
/// @param data 要发送的数据。
|
||||
/// @param timeout 超时时间(毫秒),0 表示不超时。
|
||||
/// @return 实际发送的字节数。
|
||||
/// @throws Ch34Exception 如果发送失败。
|
||||
Future<int> writeData(
|
||||
String deviceName,
|
||||
int serialNumber,
|
||||
Uint8List data, {
|
||||
int timeout = 0,
|
||||
});
|
||||
|
||||
/// 发送串口数据(异步发送)。
|
||||
///
|
||||
/// 将数据加入缓存持续发送,不返回状态和结果。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param serialNumber 串口号。
|
||||
/// @param data 要发送的数据。
|
||||
/// @throws Ch34Exception 如果发送失败。
|
||||
Future<void> asyncWriteData(
|
||||
String deviceName,
|
||||
int serialNumber,
|
||||
Uint8List data,
|
||||
);
|
||||
|
||||
/// 阻塞读取串口数据。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param serialNumber 串口号。
|
||||
/// @return 读取到的数据。
|
||||
/// @throws Ch34Exception 如果读取失败。
|
||||
Future<Uint8List> readData(String deviceName, int serialNumber);
|
||||
|
||||
/// 主动读取串口数据(带超时参数)。
|
||||
///
|
||||
/// 读取行为说明:
|
||||
/// - 当 vTime>0,vMin>0 时:读取将保持阻塞直到读取到第一个字符,
|
||||
/// 读到了第一个字符之后开始计时,此后若时间到了 vTime 或者时间未到
|
||||
/// 但已读够了 vMin 个字符则会返回。
|
||||
/// - 当 vTime>0,vMin=0 时:读取读到数据则立即返回,否则将为每个字符
|
||||
/// 最多等待 vTime 时间。
|
||||
/// - 当 vTime=0,vMin>0 时:读取一直阻塞,直到读到 vMin 个字符后立即返回。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param serialNumber 串口号。
|
||||
/// @param vTime 等待时间(毫秒)。
|
||||
/// @param vMin 读取的最小字节数。
|
||||
/// @return 读取到的数据。
|
||||
/// @throws Ch34Exception 如果读取失败。
|
||||
Future<Uint8List> readDataWithTimeout(
|
||||
String deviceName,
|
||||
int serialNumber,
|
||||
int vTime,
|
||||
int vMin,
|
||||
);
|
||||
|
||||
/// 注册串口数据回调。
|
||||
///
|
||||
/// 注册后数据会通过 EventChannel 自动推送,不需要主动调用 [readData]。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param serialNumber 串口号。
|
||||
/// @param onData 数据接收回调。
|
||||
/// @throws Ch34Exception 如果注册失败。
|
||||
Future<void> registerDataCallback(
|
||||
String deviceName,
|
||||
int serialNumber,
|
||||
void Function(Uint8List data) onData,
|
||||
);
|
||||
|
||||
/// 取消注册串口数据回调。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
void removeDataCallback(String deviceName);
|
||||
|
||||
/// ==================== 连接状态 ====================
|
||||
|
||||
/// 判断 USB 设备是否已经连接。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @return `true` 已连接,`false` 未连接。
|
||||
Future<bool> isConnected(String deviceName);
|
||||
|
||||
/// 获取当前已经打开的设备列表。
|
||||
///
|
||||
/// @return 已打开的设备名称列表。
|
||||
Future<List<String>> getConnectedDevices();
|
||||
|
||||
/// ==================== 断开与关闭 ====================
|
||||
|
||||
/// 断开 USB 设备的连接。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
Future<void> disconnect(String deviceName);
|
||||
|
||||
/// 释放资源,关闭所有的串口设备。
|
||||
Future<void> close();
|
||||
|
||||
/// ==================== GPIO 功能 ====================
|
||||
|
||||
/// 查询设备是否支持 GPIO 功能。
|
||||
///
|
||||
/// 应该在操作 GPIO 前调用。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @return `true` 支持,`false` 不支持。
|
||||
/// @throws Ch34Exception 如果查询失败。
|
||||
Future<bool> isSupportGpio(String deviceName);
|
||||
|
||||
/// 查询该 USB 设备的 GPIO 数目。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @return GPIO 数目。
|
||||
/// @throws Ch34Exception 如果查询失败。
|
||||
Future<int> queryGpioCount(String deviceName);
|
||||
|
||||
/// 查询该 USB 设备指定 GPIO 的状态。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param gpioIndex GPIO 编号(从 0 开始)。
|
||||
/// @return GPIO 状态。
|
||||
/// @throws Ch34Exception 如果查询失败。
|
||||
Future<GpioStatus> queryGpioStatus(String deviceName, int gpioIndex);
|
||||
|
||||
/// 查询该 USB 设备的所有 GPIO 状态。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @return 全部 GPIO 状态列表。
|
||||
/// @throws Ch34Exception 如果查询失败。
|
||||
Future<List<GpioStatus>> queryAllGpioStatus(String deviceName);
|
||||
|
||||
/// 使能指定 GPIO。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param gpioIndex GPIO 编号。
|
||||
/// @param enable `true` 使能,`false` 关闭。
|
||||
/// @param direction GPIO 方向。
|
||||
/// @return `true` 使能成功,`false` 使能失败。
|
||||
/// @throws Ch34Exception 如果操作失败。
|
||||
Future<bool> enableGpio(
|
||||
String deviceName,
|
||||
int gpioIndex,
|
||||
bool enable,
|
||||
GpioDirection direction,
|
||||
);
|
||||
|
||||
/// 设置指定 GPIO 的电平值。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param gpioIndex GPIO 编号。
|
||||
/// @param value GPIO 电平值。
|
||||
/// @return `true` 设置成功,`false` 设置失败。
|
||||
/// @throws Ch34Exception 如果操作失败。
|
||||
Future<bool> setGpioVal(
|
||||
String deviceName,
|
||||
int gpioIndex,
|
||||
GpioValue value,
|
||||
);
|
||||
|
||||
/// 获取指定 GPIO 的电平值。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param gpioIndex GPIO 编号。
|
||||
/// @return GPIO 电平值。
|
||||
/// @throws Ch34Exception 如果操作失败。
|
||||
Future<GpioValue> getGpioVal(String deviceName, int gpioIndex);
|
||||
|
||||
/// ==================== 信号控制 ====================
|
||||
|
||||
/// 设置 DTR 信号。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param serialNumber 串口号。
|
||||
/// @param valid 是否有效(低电平有效)。
|
||||
/// @return `true` 设置成功,`false` 设置失败。
|
||||
/// @throws Ch34Exception 如果操作失败。
|
||||
Future<bool> setDtr(String deviceName, int serialNumber, bool valid);
|
||||
|
||||
/// 设置 RTS 信号。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param serialNumber 串口号。
|
||||
/// @param valid 是否有效(低电平有效)。
|
||||
/// @return `true` 设置成功,`false` 设置失败。
|
||||
/// @throws Ch34Exception 如果操作失败。
|
||||
Future<bool> setRts(String deviceName, int serialNumber, bool valid);
|
||||
|
||||
/// 设置 Break 信号。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param serialNumber 串口号。
|
||||
/// @param valid 是否有效(低电平有效)。
|
||||
/// @return `true` 设置成功,`false` 设置失败。
|
||||
/// @throws Ch34Exception 如果操作失败。
|
||||
Future<bool> setBreakSignal(String deviceName, int serialNumber, bool valid);
|
||||
|
||||
/// ==================== Modem 状态回调 ====================
|
||||
|
||||
/// 注册 Modem 控制信号状态回调。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param onModemStatus Modem 状态变化回调。
|
||||
/// @throws Ch34Exception 如果注册失败。
|
||||
Future<void> registerModemStatusCallback(
|
||||
String deviceName,
|
||||
void Function(ModemStatus status) onModemStatus,
|
||||
);
|
||||
|
||||
/// 移除 Modem 状态回调。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
void removeModemStatusCallback(String deviceName);
|
||||
|
||||
/// ==================== 错误查询 ====================
|
||||
|
||||
/// 查询串口错误状态。
|
||||
///
|
||||
/// @param deviceName 设备名称。
|
||||
/// @param serialNumber 串口号。
|
||||
/// @param errorType 错误类型。
|
||||
/// @return 该种错误出现的次数。
|
||||
/// @throws Ch34Exception 如果查询失败。
|
||||
Future<int> querySerialErrorCount(
|
||||
String deviceName,
|
||||
int serialNumber,
|
||||
SerialErrorType errorType,
|
||||
);
|
||||
|
||||
/// ==================== 全局配置 ====================
|
||||
|
||||
/// 设置读取超时时间。
|
||||
///
|
||||
/// 默认为 0,使用 USBRequest 异步读取;
|
||||
/// 如果不为 0,使用同步传输,超时单位为毫秒。
|
||||
/// 全局有效,应在 APP 初始化时调用。
|
||||
///
|
||||
/// @param timeout 超时时间(毫秒)。
|
||||
Future<void> setReadTimeout(int timeout);
|
||||
|
||||
/// 添加自定义硬件 VID/PID 及芯片类型。
|
||||
///
|
||||
/// 当用户修改了硬件设备的 VID 和 PID 后,需要将修改后的值添加到库中。
|
||||
///
|
||||
/// @param vid 硬件 VID。
|
||||
/// @param pid 硬件 PID。
|
||||
/// @param chipType 芯片类型(必填,如 "CH340"、"CH9102")。
|
||||
Future<void> addNewHardware(int vid, int pid, String chipType);
|
||||
|
||||
/// 设置调试模式。
|
||||
///
|
||||
/// 开启调试模式会打印日志,默认关闭。
|
||||
/// 应在 APP 初始化时调用。
|
||||
///
|
||||
/// @param enabled `true` 开启,`false` 关闭。
|
||||
Future<void> setDebug(bool enabled);
|
||||
|
||||
/// 返回当前是否处于调试模式。
|
||||
///
|
||||
/// @return `true` 处于调试模式,`false` 不处于。
|
||||
Future<bool> isDebugMode();
|
||||
}
|
||||
359
lib/src/types/ch34_types.dart
Normal file
359
lib/src/types/ch34_types.dart
Normal file
@@ -0,0 +1,359 @@
|
||||
/// CH34X 插件的所有类型和枚举定义。
|
||||
///
|
||||
/// 对应 WCH WCHUARTManager API 文档中的参数类型。
|
||||
library ch34_types;
|
||||
|
||||
/// 数据位
|
||||
enum DataBits {
|
||||
bits5(5),
|
||||
bits6(6),
|
||||
bits7(7),
|
||||
bits8(8);
|
||||
|
||||
const DataBits(this.value);
|
||||
final int value;
|
||||
|
||||
static DataBits fromValue(int value) {
|
||||
return DataBits.values.firstWhere(
|
||||
(e) => e.value == value,
|
||||
orElse: () => DataBits.bits8,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 停止位
|
||||
enum StopBits {
|
||||
one(1),
|
||||
two(2);
|
||||
|
||||
const StopBits(this.value);
|
||||
final int value;
|
||||
|
||||
static StopBits fromValue(int value) {
|
||||
return StopBits.values.firstWhere(
|
||||
(e) => e.value == value,
|
||||
orElse: () => StopBits.one,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 校验位
|
||||
enum Parity {
|
||||
none(0),
|
||||
odd(1),
|
||||
even(2),
|
||||
mark(3),
|
||||
space(4);
|
||||
|
||||
const Parity(this.value);
|
||||
final int value;
|
||||
|
||||
static Parity fromValue(int value) {
|
||||
return Parity.values.firstWhere(
|
||||
(e) => e.value == value,
|
||||
orElse: () => Parity.none,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// GPIO 方向
|
||||
enum GpioDirection {
|
||||
inDir,
|
||||
outDir;
|
||||
}
|
||||
|
||||
/// GPIO 电平值
|
||||
enum GpioValue {
|
||||
low,
|
||||
high;
|
||||
}
|
||||
|
||||
/// GPIO 状态
|
||||
class GpioStatus {
|
||||
const GpioStatus({
|
||||
required this.index,
|
||||
required this.direction,
|
||||
required this.value,
|
||||
required this.enabled,
|
||||
});
|
||||
|
||||
factory GpioStatus.fromMap(Map<dynamic, dynamic> map) {
|
||||
return GpioStatus(
|
||||
index: map['index'] as int,
|
||||
direction:
|
||||
GpioDirection.values[map['direction'] as int? ?? 0],
|
||||
value: GpioValue.values[map['value'] as int? ?? 0],
|
||||
enabled: map['enabled'] as bool? ?? false,
|
||||
);
|
||||
}
|
||||
|
||||
/// GPIO 编号(从 0 开始)
|
||||
final int index;
|
||||
|
||||
/// 方向
|
||||
final GpioDirection direction;
|
||||
|
||||
/// 电平值
|
||||
final GpioValue value;
|
||||
|
||||
/// 是否已使能
|
||||
final bool enabled;
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'index': index,
|
||||
'direction': direction.index,
|
||||
'value': value.index,
|
||||
'enabled': enabled,
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'GpioStatus(index: $index, direction: $direction, '
|
||||
'value: $value, enabled: $enabled)';
|
||||
}
|
||||
}
|
||||
|
||||
/// 串口参数
|
||||
class SerialParameter {
|
||||
const SerialParameter({
|
||||
this.baud = 115200,
|
||||
this.dataBits = DataBits.bits8,
|
||||
this.stopBits = StopBits.one,
|
||||
this.parity = Parity.none,
|
||||
this.hardwareFlowControl = false,
|
||||
});
|
||||
|
||||
factory SerialParameter.fromMap(Map<dynamic, dynamic> map) {
|
||||
return SerialParameter(
|
||||
baud: map['baud'] as int? ?? 115200,
|
||||
dataBits: DataBits.fromValue(map['dataBits'] as int? ?? 8),
|
||||
stopBits: StopBits.fromValue(map['stopBits'] as int? ?? 1),
|
||||
parity: Parity.fromValue(map['parity'] as int? ?? 0),
|
||||
hardwareFlowControl: map['hardwareFlowControl'] as bool? ?? false,
|
||||
);
|
||||
}
|
||||
|
||||
/// 波特率
|
||||
final int baud;
|
||||
|
||||
/// 数据位
|
||||
final DataBits dataBits;
|
||||
|
||||
/// 停止位
|
||||
final StopBits stopBits;
|
||||
|
||||
/// 校验位
|
||||
final Parity parity;
|
||||
|
||||
/// 硬件流控
|
||||
final bool hardwareFlowControl;
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'baud': baud,
|
||||
'dataBits': dataBits.value,
|
||||
'stopBits': stopBits.value,
|
||||
'parity': parity.value,
|
||||
'hardwareFlowControl': hardwareFlowControl,
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SerialParameter(baud: $baud, dataBits: $dataBits, '
|
||||
'stopBits: $stopBits, parity: $parity, '
|
||||
'hardwareFlowControl: $hardwareFlowControl)';
|
||||
}
|
||||
|
||||
SerialParameter copyWith({
|
||||
int? baud,
|
||||
DataBits? dataBits,
|
||||
StopBits? stopBits,
|
||||
Parity? parity,
|
||||
bool? hardwareFlowControl,
|
||||
}) {
|
||||
return SerialParameter(
|
||||
baud: baud ?? this.baud,
|
||||
dataBits: dataBits ?? this.dataBits,
|
||||
stopBits: stopBits ?? this.stopBits,
|
||||
parity: parity ?? this.parity,
|
||||
hardwareFlowControl:
|
||||
hardwareFlowControl ?? this.hardwareFlowControl,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 芯片主频信息
|
||||
///
|
||||
/// 对应 WCH API 4.12 节 `getChipMasterFrequency` 返回值。
|
||||
class ChipMasterFrequency {
|
||||
const ChipMasterFrequency({
|
||||
required this.frequency,
|
||||
required this.switchEnable,
|
||||
required this.coStatus,
|
||||
});
|
||||
|
||||
factory ChipMasterFrequency.fromMap(Map<dynamic, dynamic> map) {
|
||||
return ChipMasterFrequency(
|
||||
frequency: map['frequency'] as int? ?? 0,
|
||||
switchEnable: map['switchEnable'] as bool? ?? false,
|
||||
coStatus: map['coStatus'] as int? ?? 0,
|
||||
);
|
||||
}
|
||||
|
||||
/// 芯片主频(Hz)
|
||||
final int frequency;
|
||||
|
||||
/// 是否允许切换主频
|
||||
final bool switchEnable;
|
||||
|
||||
/// 晶振状态
|
||||
final int coStatus;
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'frequency': frequency,
|
||||
'switchEnable': switchEnable,
|
||||
'coStatus': coStatus,
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ChipMasterFrequency(frequency: $frequency Hz, '
|
||||
'switchEnable: $switchEnable, coStatus: $coStatus)';
|
||||
}
|
||||
}
|
||||
|
||||
/// Modem 状态
|
||||
class ModemStatus {
|
||||
const ModemStatus({
|
||||
this.cts = false,
|
||||
this.dsr = false,
|
||||
this.ri = false,
|
||||
this.dcd = false,
|
||||
});
|
||||
|
||||
factory ModemStatus.fromMap(Map<dynamic, dynamic> map) {
|
||||
return ModemStatus(
|
||||
cts: map['cts'] as bool? ?? false,
|
||||
dsr: map['dsr'] as bool? ?? false,
|
||||
ri: map['ri'] as bool? ?? false,
|
||||
dcd: map['dcd'] as bool? ?? false,
|
||||
);
|
||||
}
|
||||
|
||||
/// Clear To Send
|
||||
final bool cts;
|
||||
|
||||
/// Data Set Ready
|
||||
final bool dsr;
|
||||
|
||||
/// Ring Indicator
|
||||
final bool ri;
|
||||
|
||||
/// Data Carrier Detect
|
||||
final bool dcd;
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'cts': cts,
|
||||
'dsr': dsr,
|
||||
'ri': ri,
|
||||
'dcd': dcd,
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'ModemStatus(CTS: $cts, DSR: $dsr, RI: $ri, DCD: $dcd)';
|
||||
}
|
||||
}
|
||||
|
||||
/// 串口错误类型
|
||||
///
|
||||
/// 对应 WCH 原生库的 `SerialErrorType` 枚举(仅包含 FRAME/PARITY/OVERRUN 三种)。
|
||||
enum SerialErrorType {
|
||||
framingError,
|
||||
parityError,
|
||||
overrunError;
|
||||
|
||||
/// 转换为原生端字符串标识。
|
||||
String toNativeString() {
|
||||
switch (this) {
|
||||
case SerialErrorType.framingError:
|
||||
return 'SerialErrorType.FramingError';
|
||||
case SerialErrorType.parityError:
|
||||
return 'SerialErrorType.ParityError';
|
||||
case SerialErrorType.overrunError:
|
||||
return 'SerialErrorType.OverrunError';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// USB 设备信息
|
||||
class UsbDeviceInfo {
|
||||
const UsbDeviceInfo({
|
||||
required this.deviceName,
|
||||
required this.productId,
|
||||
required this.vendorId,
|
||||
required this.serialCount,
|
||||
this.chipType,
|
||||
});
|
||||
|
||||
factory UsbDeviceInfo.fromMap(Map<dynamic, dynamic> map) {
|
||||
return UsbDeviceInfo(
|
||||
deviceName: map['deviceName'] as String,
|
||||
productId: map['productId'] as int,
|
||||
vendorId: map['vendorId'] as int,
|
||||
serialCount: map['serialCount'] as int? ?? 1,
|
||||
chipType: map['chipType'] as String?,
|
||||
);
|
||||
}
|
||||
|
||||
/// 设备名称
|
||||
final String deviceName;
|
||||
|
||||
/// 产品 ID
|
||||
final int productId;
|
||||
|
||||
/// 厂商 ID
|
||||
final int vendorId;
|
||||
|
||||
/// 串口数量
|
||||
final int serialCount;
|
||||
|
||||
/// 芯片型号(如果识别)
|
||||
final String? chipType;
|
||||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'deviceName': deviceName,
|
||||
'productId': productId,
|
||||
'vendorId': vendorId,
|
||||
'serialCount': serialCount,
|
||||
'chipType': chipType,
|
||||
};
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'UsbDeviceInfo(name: $deviceName, VID: 0x${vendorId.toRadixString(16).toUpperCase().padLeft(4, '0')}, '
|
||||
'PID: 0x${productId.toRadixString(16).toUpperCase().padLeft(4, '0')}, '
|
||||
'ports: $serialCount, chip: $chipType)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (identical(this, other)) return true;
|
||||
return other is UsbDeviceInfo &&
|
||||
other.deviceName == deviceName &&
|
||||
other.productId == productId &&
|
||||
other.vendorId == vendorId;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(deviceName, productId, vendorId);
|
||||
}
|
||||
Reference in New Issue
Block a user