jpnurmi / libserialport.dart

Serial Port for Dart
https://pub.dev/packages/libserialport
GNU Lesser General Public License v3.0
86 stars 34 forks source link

How to reset serial port when there is an error? #42

Open LiveRock opened 3 years ago

LiveRock commented 3 years ago

When there is an misconfiguration e.g. like DTR setting, etc, the connecting the serial port will result in error. I can change the configuration within the app but I cannot use the libserialport again because the previous error has corrupted the port.

How I reset the serial port without restarting the app again?

k10dev commented 3 years ago

The best way to handle this is to catch the Exception then close the existing reader and serial port connection(s). This would close the corrupted port(s), then go through the port initialization process again.

LiveRock commented 3 years ago

The problem is there are no Exception raised when DTR is not configured correctly. It is wait/hang indefinitely.

final reader = SerialPortReader(port, timeout: 2000);
      reader.port.drain();
      reader.port.flush();
      print("readSerialPort just before reader.stream.listen((data)\n");
      reader.stream.listen((data) {
// Reads stuff
}, onDone: () async {
        //>BLUE DONE!
        print('done!');
reader.port.drain();
        reader.port.flush();
        reader.port.close();
        serialConfig.dispose();
          completer.completeError(ArgumentError("Empty Data! Please check meter"));
        } else {
          completer.complete(resultString);
        }
        //port.dispose();
      }, onError: (e) {
reader.close();
        reader.port.drain();
        reader.port.flush();
        reader.port.close();
        serialConfig.dispose();
        reader.port.dispose();
      }, cancelOnError: true);
    }
} 
k10dev commented 3 years ago

Would you be able to send a handshake message to the peripheral to acknowledge the connection? Basically, test the connection with a given configuration first and if it's timed out after a certain interval, then you know it can't be connected with that configuration. Using the stream.timeout() would let you detect the timed out condition.

final reader = SerialPortReader(port);

try {
  port.flush();
  final handshake = Uint8List.fromList('handshake_message'.codeUnits);
  final result = port.write(handshake);
  if (handshake.length != result) {
    // Handle write error
    return false;
  }

  final timeout = const Duration(seconds: 2);

  // Listen for only one response and timeout after 2 seconds
  await for (Uint8List value in reader.stream.timeout(timeout)) {
    final response = String.fromCharCodes(value);

    // Verify the `value` with the expected handshake response.
    // If it's matched, then the connection is valid.
    // ...
  }
} finally {
  port.close();
  reader.close();
}
LiveRock commented 3 years ago

should be await for (Uint8List value in reader.stream.timeout(timeout)) {

?

LiveRock commented 3 years ago

I am getting old data in the serial stream/pipe. Using MacOS. Despite flush() and drain(), I am getting it. Any pointers?

k10dev commented 3 years ago

Assuming you're using a single port for both write and read operations, and the old data is the data from the write operation? I'm not sure if this would help, but try to add a timeout to the write to use the sp_blocking_write() in addition to sp_drain(). Maybe something like this,

final reader = SerialPortReader(port);

try {
  port.flush();
  final handshake = Uint8List.fromList('handshake_message'.codeUnits);
  final result = port.write(handshake, timeout: const Duration(milliseconds: 500).inMilliseconds);
  port.write.drain();      
  if (SerialPort.lastError?.errorCode != 0) { // SP_OK
     // Handle write error
     return false;
  }
  if (handshake.length != result) {
     // Handle write error
     return false;
   }

  final timeout = const Duration(seconds: 2);

  // Listen for only one response and timeout after 2 seconds
  await for (Uint8List value in reader.stream.timeout(timeout)) {
    final response = String.fromCharCodes(value);

    // Verify the `value` with the expected handshake response.
    // If it's matched, then the connection is valid.
    // ...
  }
} finally {
  port.close();
  reader.close();
}

You might want to consult the C libserialport's documentation for how the write and read operations work on Unix-like systems vs Windows, https://sigrok.org/api/libserialport/unstable/index.html