1
This commit is contained in:
198
.planning/codebase/ARCHITECTURE.md
Normal file
198
.planning/codebase/ARCHITECTURE.md
Normal file
@@ -0,0 +1,198 @@
|
||||
# Architecture
|
||||
|
||||
**Analysis Date:** 2026-04-16
|
||||
|
||||
## Pattern Overview
|
||||
|
||||
**Overall:** Flutter Platform Plugin (Federated Plugin Pattern)
|
||||
|
||||
This is an Android-only Flutter plugin that wraps the WCH CH34X UART library (`CH34XUARTDriver.jar`). It bridges Flutter/Dart code to native Android USB serial communication via `MethodChannel` and `EventChannel`.
|
||||
|
||||
**Key Characteristics:**
|
||||
- Static facade pattern for public API (`Ch34Manager`)
|
||||
- Platform interface pattern with token-based verification (`Ch34Platform`)
|
||||
- MethodChannel for command invocation, EventChannel for streaming callbacks
|
||||
- Single platform implementation (Android only, Kotlin/Java)
|
||||
- Singleton WCH UART manager on the native side
|
||||
|
||||
## Layers
|
||||
|
||||
### Dart Public API Layer
|
||||
- **Purpose:** Static facade providing the consumer-facing API
|
||||
- **Location:** `D:\code\new_git_code\flutter\ch34\lib\src\ch34_manager.dart`
|
||||
- **Contains:** Static methods delegating to `Ch34Platform.instance`
|
||||
- **Depends on:** `Ch34Platform`
|
||||
- **Used by:** Flutter app consuming the plugin
|
||||
|
||||
### Dart Platform Interface Layer
|
||||
- **Purpose:** Abstract interface defining all plugin methods with token verification
|
||||
- **Location:** `D:\code\new_git_code\flutter\ch34\lib\src\ch34_platform_interface.dart`
|
||||
- **Contains:** `abstract class Ch34Platform extends PlatformInterface` with 33 method signatures
|
||||
- **Depends on:** `plugin_platform_interface` package, `ch34_types.dart`
|
||||
- **Used by:** `MethodChannelCh34` for concrete implementation
|
||||
|
||||
### Dart MethodChannel Implementation Layer
|
||||
- **Purpose:** Bridges abstract platform interface to native Android via Flutter's platform channels
|
||||
- **Location:** `D:\code\new_git_code\flutter\ch34\lib\src\ch34_method_channel.dart`
|
||||
- **Contains:** `class MethodChannelCh34 extends Ch34Platform` with actual channel communication
|
||||
- **Channels:**
|
||||
- `MethodChannel('ch34')` - synchronous method calls
|
||||
- `EventChannel('ch34/data')` - serial data stream
|
||||
- `EventChannel('ch34/modem')` - modem status stream
|
||||
- `EventChannel('ch34/usb_state')` - USB hotplug events
|
||||
- **Depends on:** `dart:async`, `flutter/services.dart`
|
||||
- **Used by:** `Ch34Manager` (via `Ch34Platform.instance`)
|
||||
|
||||
### Dart Types Layer
|
||||
- **Purpose:** Shared data types and enums for the plugin
|
||||
- **Location:** `D:\code\new_git_code\flutter\ch34\lib\src\types\ch34_types.dart`
|
||||
- **Contains:**
|
||||
- Enums: `DataBits`, `StopBits`, `Parity`, `GpioDirection`, `GpioValue`, `SerialErrorType`
|
||||
- Data classes: `GpioStatus`, `SerialParameter`, `ModemStatus`, `UsbDeviceInfo`
|
||||
- Exception: `Ch34Exception` (defined in `ch34_method_channel.dart`)
|
||||
|
||||
### Android Native Layer
|
||||
- **Purpose:** Actual WCH UART library interaction, USB device management
|
||||
- **Location:** `D:\code\new_git_code\flutter\ch34\android\src\main\java\com\example\ch34\`
|
||||
- **Contains:**
|
||||
- `Ch34Plugin.java` - Main plugin entry point, MethodCallHandler
|
||||
- `Ch34DataStreamHandler.java` - Data EventChannel stream handler with WCH callback bridging
|
||||
- `Ch34ModemStreamHandler.java` - Modem status EventChannel stream handler
|
||||
- `Ch34UsbStateStreamHandler.java` - USB hotplug EventChannel with BroadcastReceiver
|
||||
- `Ch34TypeConverter.java` - Type conversion between Dart and WCH types
|
||||
- **Depends on:** `CH34XUARTDriver.jar` (bundled in `android/libs/`)
|
||||
- **Used by:** Dart MethodChannel layer
|
||||
|
||||
### Backward Compatibility Layer
|
||||
- **Location:** `D:\code\new_git_code\flutter\ch34\lib\ch34_platform_interface.dart`, `D:\code\new_git_code\flutter\ch34\lib\ch34_method_channel.dart`
|
||||
- **Purpose:** Re-exports from `src/` for consumers using old import paths
|
||||
|
||||
## Data Flow
|
||||
|
||||
### Device Discovery Flow
|
||||
1. Consumer calls `Ch34Manager.enumDevice()`
|
||||
2. Delegates to `Ch34Platform.instance.enumDevice()`
|
||||
3. `MethodChannelCh34.enumDevice()` invokes `methodChannel.invokeMethod('enumDevice')`
|
||||
4. `Ch34Plugin.enumDevice()` calls `WCHUARTManager.enumDevice()` on native side
|
||||
5. Native iterates devices, extracts VID/PID/serialCount/chipType
|
||||
6. Returns `List<Map>` through MethodChannel
|
||||
7. Dart side deserializes into `List<UsbDeviceInfo>`
|
||||
|
||||
### Data Read Flow (Callback Mode)
|
||||
1. Consumer calls `Ch34Manager.registerDataCallback(deviceName, serialNumber, onData)`
|
||||
2. `MethodChannelCh34` subscribes to `EventChannel('ch34/data')`
|
||||
3. Invokes `methodChannel.invokeMethod('registerDataCallback')`
|
||||
4. `Ch34Plugin` registers `Ch34DataStreamHandler.getWchCallback()` with `WCHUARTManager.registerDataCallback()`
|
||||
5. When data arrives, WCH triggers `IDataCallback.onData()`
|
||||
6. `Ch34DataStreamHandler` bridges data to EventChannel
|
||||
7. Dart receives via `StreamSubscription`, invokes user callback
|
||||
|
||||
### Data Write Flow
|
||||
1. Consumer calls `Ch34Manager.writeData(deviceName, serialNumber, data)`
|
||||
2. Delegates through platform interface to `MethodChannelCh34`
|
||||
3. `methodChannel.invokeMethod('writeData', {data: data, ...})`
|
||||
4. `Ch34Plugin.writeData()` calls `WCHUARTManager.writeData(device, serial, data, length, timeout)`
|
||||
5. Returns bytes written count
|
||||
|
||||
### USB Hotplug Event Flow
|
||||
1. `Ch34UsbStateStreamHandler` registers `BroadcastReceiver` for `ACTION_USB_DEVICE_ATTACHED/DETACHED`
|
||||
2. Android system sends broadcast on USB events
|
||||
3. BroadcastReceiver extracts `UsbDevice` and calls `notifyStateChanged()`
|
||||
4. EventChannel sends `{deviceName, connected}` to Dart
|
||||
5. `MethodChannelCh34` invokes `_usbStateCallback`
|
||||
|
||||
### Device Open Flow
|
||||
1. Consumer calls `Ch34Manager.openDevice(deviceName)`
|
||||
2. `Ch34Plugin.openDevice()` attempts `WCHUARTManager.openDevice(device)`
|
||||
3. If `NoPermissionException`, requests permission then retries after 2s delay
|
||||
4. On success, adds to `openedDevices` map and notifies `usbStateStreamHandler`
|
||||
|
||||
## State Management
|
||||
|
||||
**Native State:**
|
||||
- `WCHUARTManager` - Singleton instance, lazy-initialized in `ensureManagerInitialized()`
|
||||
- `openedDevices: Map<String, UsbDevice>` - tracks currently opened devices
|
||||
- Three `EventChannel.StreamHandler` instances - each manages its own `EventSink`
|
||||
|
||||
**Dart State:**
|
||||
- `Ch34Platform._instance` - Singleton platform instance
|
||||
- `MethodChannelCh34` maintains `_dataSubscription`, `_modemSubscription`, `_usbStateSubscription` - StreamSubscriptions for event channels
|
||||
- Callback references: `_dataCallback`, `_modemCallback`, `_usbStateCallback`
|
||||
|
||||
**State Cleanup:**
|
||||
- `Ch34Plugin.close()` calls `closeAllDevices()` to disconnect all and clear map
|
||||
- `Ch34UsbStateStreamHandler.onCancel()` unregisters BroadcastReceiver
|
||||
- `Ch34Manager.close()` triggers platform cleanup and cancels all subscriptions
|
||||
|
||||
## Key Abstractions
|
||||
|
||||
### Platform Interface (`Ch34Platform`)
|
||||
- **Purpose:** Abstract contract that decouples Flutter code from native implementation
|
||||
- **Example:** `D:\code\new_git_code\flutter\ch34\lib\src\ch34_platform_interface.dart`
|
||||
- **Pattern:** Token-based platform interface verification from `plugin_platform_interface` package
|
||||
- **Pattern:**
|
||||
```dart
|
||||
static final Object _token = Object();
|
||||
static Ch34Platform get instance { ... }
|
||||
static void registerDefaultInstance(Ch34Platform instance) {
|
||||
PlatformInterface.verifyToken(instance, _token);
|
||||
_instance = instance;
|
||||
}
|
||||
```
|
||||
|
||||
### Manager Facade (`Ch34Manager`)
|
||||
- **Purpose:** Static facade simplifying API usage for consumers
|
||||
- **Example:** `D:\code\new_git_code\flutter\ch34\lib\src\ch34_manager.dart`
|
||||
- **Pattern:** All static methods, all delegate to `Ch34Platform.instance`
|
||||
- **Pattern:**
|
||||
```dart
|
||||
static Future<List<UsbDeviceInfo>> enumDevice() {
|
||||
return Ch34Platform.instance.enumDevice();
|
||||
}
|
||||
```
|
||||
|
||||
### Type Converter (`Ch34TypeConverter`)
|
||||
- **Purpose:** Bridge between Dart enum indices and WCH native enum values
|
||||
- **Example:** `D:\code\new_git_code\flutter\ch34\android\src\main\java\com\example\ch34\Ch34TypeConverter.java`
|
||||
- **Pattern:** Static utility class with conversion methods for GPIO direction/value, serial error types
|
||||
|
||||
## Entry Points
|
||||
|
||||
### Dart Library Entry
|
||||
- **Location:** `D:\code\new_git_code\flutter\ch34\lib\ch34.dart`
|
||||
- **Triggers:** Consumer imports `package:ch34/ch34.dart`
|
||||
- **Responsibilities:** Exports `Ch34Manager`, `Ch34Platform`, all types, and `Ch34Exception`
|
||||
|
||||
### Plugin Initialization (Android)
|
||||
- **Location:** `D:\code\new_git_code\flutter\ch34\android\src\main\java\com\example\ch34\Ch34Plugin.java`
|
||||
- **Trigger:** Flutter engine attaches plugin via `onAttachedToEngine()`
|
||||
- **Responsibilities:** Creates MethodChannel, 3 EventChannels, sets MethodCallHandler
|
||||
- **Declaration:** `D:\code\new_git_code\flutter\ch34\android\build.gradle` + `pubspec.yaml` declares `package: com.example.ch34`, `pluginClass: Ch34Plugin`
|
||||
|
||||
### MethodChannel Dispatcher
|
||||
- **Location:** `D:\code\new_git_code\flutter\ch34\android\src\main\java\com\example\ch34\Ch34Plugin.java` line 80-187
|
||||
- **Trigger:** Dart invokes `methodChannel.invokeMethod()`
|
||||
- **Responsibilities:** Switch dispatch to 33 method handlers, error handling wrapper
|
||||
|
||||
## Error Handling
|
||||
|
||||
**Strategy:** Native exceptions caught and converted to MethodChannel error responses with error codes; Dart side uses null-coalescing defaults and `Ch34Exception` for explicit failures.
|
||||
|
||||
**Patterns:**
|
||||
- **Native:** Each method handler has try-catch, returns `result.error(ERROR_CODE, message, null)`
|
||||
- Error codes: `ENUM_DEVICE_FAILED`, `OPEN_DEVICE_FAILED`, `PERMISSION_DENIED`, `WRITE_DATA_FAILED`, etc.
|
||||
- **Dart:** Default fallbacks on null results (e.g., `result ?? false`, `result ?? Uint8List(0)`)
|
||||
- **Exception class:** `Ch34Exception` in `D:\code\new_git_code\flutter\ch34\lib\src\ch34_method_channel.dart` for throwing on Dart side
|
||||
- **Logging:** All errors logged via `Log.e(TAG, "...")` on Android native side
|
||||
|
||||
## Cross-Cutting Concerns
|
||||
|
||||
**Logging:** Android `android.util.Log` with per-class TAGs (`Ch34Plugin`, `Ch34DataStream`, `Ch34ModemStream`, `Ch34UsbStateStream`). Dart side uses `flutter/foundation.dart` `debugPrint()` for callback errors.
|
||||
|
||||
**Validation:** Device name resolution via `getDeviceOrThrow()` which searches `openedDevices` map first, then falls back to `manager.enumDevice()` lookup.
|
||||
|
||||
**Authentication/Permission:** USB permission flow handled in `openDevice()` - attempts open, if `NoPermissionException`, calls `manager.requestPermission()` then retries after 2-second delay.
|
||||
|
||||
---
|
||||
|
||||
*Architecture analysis: 2026-04-16*
|
||||
Reference in New Issue
Block a user