meshcore-open/lib/services/usb_serial_frame_codec.dart
just_stuff_tm 4c7ee3b3b0 Enhance USB serial services with debug logging and reset functionality
- Introduced debug logging in USB serial services for better traceability.
- Added reset method to UsbSerialFrameDecoder to clear buffered data.
- Updated tests to verify the reset functionality of the decoder.
2026-03-05 02:25:46 -05:00

111 lines
2.9 KiB
Dart

import 'dart:typed_data';
const int usbSerialTxFrameStart = 0x3c;
const int usbSerialRxFrameStart = 0x3e;
const int usbSerialHeaderLength = 3;
const int usbSerialMaxPayloadLength = 172;
Uint8List wrapUsbSerialTxFrame(Uint8List payload) {
if (payload.length > usbSerialMaxPayloadLength) {
throw ArgumentError.value(
payload.length,
'payload.length',
'USB serial payload exceeds $usbSerialMaxPayloadLength bytes',
);
}
final packet = Uint8List(usbSerialHeaderLength + payload.length);
packet[0] = usbSerialTxFrameStart;
packet[1] = payload.length & 0xff;
packet[2] = (payload.length >> 8) & 0xff;
packet.setRange(usbSerialHeaderLength, packet.length, payload);
return packet;
}
class UsbSerialDecodedPacket {
const UsbSerialDecodedPacket({
required this.frameStart,
required this.payload,
});
final int frameStart;
final Uint8List payload;
bool get isRxFrame => frameStart == usbSerialRxFrameStart;
}
class UsbSerialFrameDecoder {
final List<int> _rxBuffer = <int>[];
int _startIndex = 0;
void reset() {
_rxBuffer.clear();
_startIndex = 0;
}
List<UsbSerialDecodedPacket> ingest(Uint8List bytes) {
if (bytes.isEmpty) {
return const <UsbSerialDecodedPacket>[];
}
_rxBuffer.addAll(bytes);
final packets = <UsbSerialDecodedPacket>[];
while (true) {
if (_startIndex >= _rxBuffer.length) {
_rxBuffer.clear();
_startIndex = 0;
return packets;
}
if (_rxBuffer[_startIndex] != usbSerialRxFrameStart &&
_rxBuffer[_startIndex] != usbSerialTxFrameStart) {
_startIndex++;
_compactBufferIfNeeded();
continue;
}
final availableLength = _rxBuffer.length - _startIndex;
if (availableLength < usbSerialHeaderLength) {
_compactBufferIfNeeded(force: true);
return packets;
}
final payloadLength =
_rxBuffer[_startIndex + 1] | (_rxBuffer[_startIndex + 2] << 8);
if (payloadLength > usbSerialMaxPayloadLength) {
_startIndex++;
_compactBufferIfNeeded();
continue;
}
final packetLength = usbSerialHeaderLength + payloadLength;
if (availableLength < packetLength) {
_compactBufferIfNeeded(force: true);
return packets;
}
final frameStart = _rxBuffer[_startIndex];
final payload = Uint8List.fromList(
_rxBuffer.sublist(
_startIndex + usbSerialHeaderLength,
_startIndex + packetLength,
),
);
_startIndex += packetLength;
_compactBufferIfNeeded();
packets.add(
UsbSerialDecodedPacket(frameStart: frameStart, payload: payload),
);
}
}
void _compactBufferIfNeeded({bool force = false}) {
if (_startIndex == 0) {
return;
}
if (!force && _startIndex < 1024 && _startIndex < (_rxBuffer.length ~/ 2)) {
return;
}
_rxBuffer.removeRange(0, _startIndex);
_startIndex = 0;
}
}