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 _rxBuffer = []; int _startIndex = 0; void reset() { _rxBuffer.clear(); _startIndex = 0; } List ingest(Uint8List bytes) { if (bytes.isEmpty) { return const []; } _rxBuffer.addAll(bytes); final packets = []; 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; } }