altera2015 / usbserial

Flutter Android USB Serial plugin
BSD 3-Clause "New" or "Revised" License
119 stars 83 forks source link

Listening for large messages of varying length #86

Closed pieterbergmans closed 10 months ago

pieterbergmans commented 1 year ago

This library has worked well for me thus far, so thanks for putting this together.

I'm new to USB communication but I thought I'd share how I got around listening for large messages of varying length. This may be obvious for most people but it wasn't for me. Hopefully this post will help others.

Here is some background on my use case. My flutter app sends commands to a device and then listens for responses. The responses are formatted with a two byte header with values of 1, 2; and a two byte footer with values of 3,4.

For my first attempt, I was using the terminated method like this:

_transaction = Transaction.terminated(
    _port!.inputStream!,
    Uint8List.fromList("\x03\x04".codeUnits),
);
_transaction!.stream.listen((data) {
     // do something with the data
}

For a while, this was working great until the messages from the device grew in size. After a while, I realized that the maxLength for the terminated method is 1024. So I then tried the magic header method but, after giving it a try, I realized this wouldn't work for me because the length of my messages continually varied in length. So, I scrapped using the Transaction class and decided to just listen to the data coming from the port, which looked like this:

port!.inputStream!.listen((data) {
  // do something with the data 
}

This was promising but I was limited to a message length of 2048 and my messages were slightly larger than that. To get around this, I decided to continually add the streaming data to a ByteBuilder until the header and footer were present. Then I performed the required logic and cleared the array. This is my final code:

Function eq = const ListEquality().equals;

var message = BytesBuilder();
port!.inputStream!.listen((data) {
   message.add(data);
   Uint8List byteData = message.toBytes();
   // Does the message have the required header + footer?
   if (eq(byteData.sublist(0, 2), [1, 2]) &&
        eq(byteData.sublist(byteData.length - 2, byteData.length), [3, 4])) {
          // do something with the data 
          // ....
          // finally, reset the message
          message = BytesBuilder();
    }
}

Hopefully this helps someone.

EParisot commented 10 months ago

Thank you very much for posting this !! It helped me realise there was a maxLen arg that is left default (1024)

This should be added so the user can decide the size based on its needs...

I do a PR now.

Thank again @pieterbergmans

altera2015 commented 10 months ago

Thanks guys