diff --git a/android/src/main/java/com/xiarui/ch934x_serial/Ch934xSerialPlugin.java b/android/src/main/java/com/xiarui/ch934x_serial/Ch934xSerialPlugin.java index 07f3247..4eb9ce2 100644 --- a/android/src/main/java/com/xiarui/ch934x_serial/Ch934xSerialPlugin.java +++ b/android/src/main/java/com/xiarui/ch934x_serial/Ch934xSerialPlugin.java @@ -10,6 +10,8 @@ import android.content.IntentFilter; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbManager; import android.os.Build; +import android.os.Handler; +import android.os.Looper; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -22,7 +24,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import cn.wch.ch934xlib.CH934XManager; -import cn.wch.ch934xlib.callback.IDataCallback; import cn.wch.ch934xlib.callback.IModemStatus; import cn.wch.ch934xlib.callback.IUsbStateChange; import cn.wch.ch934xlib.chip.ChipType; @@ -74,9 +75,6 @@ public class Ch934xSerialPlugin implements FlutterPlugin, MethodCallHandler, Act /** 当前会话选中的串口索引(对应文档 5.1.1 中的 serialPortIndex)。 */ private int activeSerialNumber = -1; - /** 当前会话是否已注册了 IDataCallback,用于避免重复注册。 */ - private boolean dataCallbackRegistered = false; - /** 当前会话是否已注册了 IModemStatus,用于避免重复注册。 */ private boolean modemCallbackRegistered = false; @@ -153,7 +151,6 @@ public class Ch934xSerialPlugin implements FlutterPlugin, MethodCallHandler, Act } activeDevice = null; activeSerialNumber = -1; - dataCallbackRegistered = false; modemCallbackRegistered = false; exceptionCallbackEnabled = false; } @@ -371,7 +368,9 @@ public class Ch934xSerialPlugin implements FlutterPlugin, MethodCallHandler, Act } activeDevice = device; activeSerialNumber = serialPortIndex; - ensureDataCallback(); + // 注意:不注册 IDataCallback — SDK 在有回调注册时会通过回调 + // 投递数据并释放内部缓冲区,导致 readData() 返回空。 + // 通过 dataStream 轮询 readData() 拉取数据。 ensureModemCallback(); return true; } @@ -486,7 +485,6 @@ public class Ch934xSerialPlugin implements FlutterPlugin, MethodCallHandler, Act } activeDevice = null; activeSerialNumber = -1; - dataCallbackRegistered = false; modemCallbackRegistered = false; modemStatusCache = 0; return true; @@ -519,10 +517,13 @@ public class Ch934xSerialPlugin implements FlutterPlugin, MethodCallHandler, Act if (length == null || length <= 0) { return new byte[0]; } + // 可选参数:指定读哪个端口的缓冲区。不传则读 activeSerialNumber(向后兼容) + Integer portIndex = call.argument("serialPortIndex"); + int idx = (portIndex != null) ? portIndex : activeSerialNumber; try { // SDK 返回内部缓冲的所有数据,与文档 read 语义一致。 byte[] data = CH934XManager.getInstance() - .readData(activeDevice, activeSerialNumber); + .readData(activeDevice, idx); if (data == null || data.length == 0) { return new byte[0]; } @@ -682,25 +683,6 @@ public class Ch934xSerialPlugin implements FlutterPlugin, MethodCallHandler, Act return ports; } - /** 注册 IDataCallback 推送数据上抛(可选,目前仅用作 SDK 内部缓冲预热)。 */ - private void ensureDataCallback() { - if (dataCallbackRegistered || activeDevice == null) { - return; - } - try { - CH934XManager.getInstance().registerDataCallback(activeDevice, - new IDataCallback() { - @Override - public void onData(int serialNumber, byte[] buffer, int length) { - // 数据通过 readData 拉取即可,这里留空。 - } - }); - dataCallbackRegistered = true; - } catch (Throwable t) { - // 注册失败不影响主流程,readData 仍可工作。 - } - } - private void ensureModemCallback() { if (modemCallbackRegistered || activeDevice == null) { return; @@ -740,11 +722,15 @@ public class Ch934xSerialPlugin implements FlutterPlugin, MethodCallHandler, Act } } - /** 主动上抛异常给 Dart 侧。 */ + /** 主动上抛异常给 Dart 侧。若当前非主线程则自动切换到主线程再发送。 */ private void pushException(int type, String message, @Nullable String cause) { if (!exceptionCallbackEnabled || channel == null) { return; } + if (Looper.myLooper() != Looper.getMainLooper()) { + new Handler(Looper.getMainLooper()).post(() -> pushException(type, message, cause)); + return; + } Map payload = new HashMap<>(); payload.put("type", type); payload.put("message", message); diff --git a/lib/ch934x_serial.dart b/lib/ch934x_serial.dart index fe2d6c2..421d882 100644 --- a/lib/ch934x_serial.dart +++ b/lib/ch934x_serial.dart @@ -107,6 +107,29 @@ class Ch934xSerial { } } + /// 多端口并发轮询流:每周期轮询 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 // --------------------------------------------------------------------------- diff --git a/lib/ch934x_serial_method_channel.dart b/lib/ch934x_serial_method_channel.dart index 73d54f8..2de2715 100644 --- a/lib/ch934x_serial_method_channel.dart +++ b/lib/ch934x_serial_method_channel.dart @@ -124,14 +124,15 @@ class MethodChannelCh934xSerial extends Ch934xSerialPlatform { } @override - Future read(int length) async { + Future read(int length, {int? serialPortIndex}) async { if (length <= 0) { return Uint8List(0); } - final raw = await methodChannel.invokeMethod( - 'read', - {'length': length}, - ); + final args = {'length': length}; + if (serialPortIndex != null) { + args['serialPortIndex'] = serialPortIndex; + } + final raw = await methodChannel.invokeMethod('read', args); return raw ?? Uint8List(0); } diff --git a/lib/ch934x_serial_platform_interface.dart b/lib/ch934x_serial_platform_interface.dart index 1afccbf..949bf2a 100644 --- a/lib/ch934x_serial_platform_interface.dart +++ b/lib/ch934x_serial_platform_interface.dart @@ -75,7 +75,8 @@ abstract class Ch934xSerialPlatform extends PlatformInterface { // --------------------------------------------------------------------------- /// 从串口读取数据(对应 6.1.1 `UsbSerial.read`)。 - Future read(int length); + /// [serialPortIndex] 可选,指定读取哪个端口的缓冲区;不传则读上次 setActivePort 设置的端口。 + Future read(int length, {int? serialPortIndex}); /// 向串口写入数据(对应 6.2.1 `UsbSerial.write`)。 Future write(Uint8List data);