flutter_libserialport write OK but read unhandled exception - flutter

I'm trying to implement a simple at cmd application.
I modified the flutter_libserialport example.
https://pub.dev/packages/flutter_libserialport
simply,
replace the floatButton action to my own reTest() function
floatingActionButton: FloatingActionButton(
child: Icon(Icons.refresh),
// onPressed: initPorts,
onPressed: rwTest,
),
and my rwTest below,
Future<void> rwTest() async {
for (var p in availablePorts) {
if (p == 'COM115') {
print(p);
List<int> d = [65, 84, 13];
Uint8List bytes = Uint8List.fromList(d);
SerialPort port = SerialPort(p);
SerialPortReader reader = SerialPortReader(port, timeout: 10000);
try {
port.openReadWrite();
print(port.write(bytes));
await reader.stream.listen((data) {
print('received : $data');
});
port.close();
} on SerialPortError catch (_, err) {
if (port.isOpen) {
port.close();
print('serial port error');
}
}
}
}
}
my device is shown as COM115 so I put the fixed value.
and the "write" operation was success
but when I use "reader.stream.listen()"
SerialPortError occurs as below
flutter: COM115
flutter: 3
[ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: SerialPortError: ÀÛ¾÷À» ¿Ï·áÇß½À´Ï´Ù., errno = 0
I guess the usage of "listen" was wrong, but I don't know how to fix it.
anyone can help me to fix it?

You just need to remove the port.close() in try{} ... and I think you should also set the timeout = 1,
Also, it is better to set a configuration before using the port
Note: you can just access the port through name, without looping over all the available ports.
Future<void> rwTest() async {
List<int> d = [65, 84, 13];
Uint8List bytes = Uint8List.fromList(d);
SerialPort port = SerialPort('COM115');
// configuration
final configu = SerialPortConfig();
configu.baudRate = 9600;
configu.bits = 8;
configu.parity = 0;
port.config = configu;
SerialPortReader reader = SerialPortReader(port, timeout: 10);
try {
port.openReadWrite();
print(port.write(bytes));
await reader.stream.listen((data) {
print('received : $data');
});
} on SerialPortError catch (_, err) {
if (port.isOpen) {
port.close();
print('serial port error');
}
}
}

The serial port need to open as far as the communication is active to send and receive data
Remove the port close method call
try {
port.openReadWrite();
print(port.write(bytes));
await reader.stream.listen((data) {
print('received : $data');
});
//port.close(); --> remove this line
}
On exit close the reader stream and then close the port

Related

Making FTP client with socket in Flutter

i'm making an FTP connection with sockets.
Everything works without TLS but when i start PASV in TLS mode, i can connect to data socket but i can't listen nothing.
Could someone help me to understand where i'm wrong?
This is the code i'm using:
String? pasvIP;
int? pasvPort;
RawSocket rawsock = await RawSocket.connect(ftpHost!, int.parse(port));
StreamSubscription<RawSocketEvent> rwlisten = rawsock.listen((event) {
if (event == RawSocketEvent.read) {
Uint8List? buffer = rawsock.read();
String result = String.fromCharCodes(buffer!);
print(' ${result}');
}
});
rawsock.write(Utf8Codec().encode('AUTH TLS\r\n'));
rawsock = await RawSecureSocket.secure(
rawsock,
onBadCertificate: (certificate) => true,
subscription: rwlisten,
);
rwlisten = rawsock.listen((event) {
if (event == RawSocketEvent.read) {
Uint8List? buffer = rawsock.read();
String result = String.fromCharCodes(buffer!);
print('${result}');
if (result.startsWith('227')) {
final startIndex = result.indexOf('(');
final endIndex = result.indexOf(')');
String ipPasv = result.substring(startIndex + 1, endIndex);
List ipPasvList = ipPasv.split(',');
pasvIP =
'${ipPasvList[0]}.${ipPasvList[1]}.${ipPasvList[2]}.${ipPasvList[3]}';
pasvPort =
(int.parse(ipPasvList[4]) * 256 + int.parse(ipPasvList[5]));
}
}
});
rawsock.write(Utf8Codec().encode('PBSZ 0\r\n'));
rawsock.write(Utf8Codec().encode('PROT P\r\n'));
rawsock.write(Utf8Codec().encode('USER ${username}\r\n'));
rawsock.write(
Utf8Codec().encode('PASS ${activeUser!.decrypt(password!)}\r\n'));
rawsock.write(Utf8Codec().encode('PASV\r\n'));
SecureSocket sockData = await SecureSocket.connect(
pasvIP!,
pasvPort!,
onBadCertificate: (certificate) => true,
);
sockData.listen(
(data) { // <-- NO DATA HERE
final serverResponse = String.fromCharCodes(data);
print('$serverResponse');
},
onError: (error) {
print(error);
sockData.destroy();
},
onDone: () {
print('Server left.');
sockData.destroy();
},
);
rawsock.write(Utf8Codec().encode('LIST\r\n'));
rawsock.write(Utf8Codec().encode('QUIT\r\n'));
Thanks
Marco

How can I get multiple messages from dart isolate?

How can I get multiple messages from dart isolate?
I'm trying to create an excel file and want to do some operation on that file in an isolate. Before doing an operation on that file, I want to return an message to main isolate, that excel file is created.
Here is function goes in isolate :
foo(String filePath){
// create excel file
var bytes = File(filePath).readAsBytesSync();
var excel = Excel.decodeBytes(bytes);
//HERE I WANT TO SEND THE MESSAGE THAT CREATING EXCEL FILE IS DONE
// some operatoin on excel file
var result = doSomeOperation(excel);
return result;
}
Main isolate code :
var result = await compute(foo, filePath);
What should I do to get creating file message before the actual result comes?
For excel, I'm using excel: ^2.0.0-null-safety-3 package.
Compute only returns one result. If you want to pass multiple 'events' back to the main isolate then you need to use the full Isolate logic (with sendPort and receivePort).
For example, the following code runs in an isolate, and downloads a file while emitting float values to represent progress, potentially a String to indicate log messages and then a bool to indicate success or failure upon completion.
Future<void> isolateDownload(
DownloadRequest request) async {
final sendPort = request.sendPort;
if (sendPort != null) {
var success = false;
var errorMessage = '';
var url = Uri.parse('a_url_based_on_request');
IOSink? out;
try {
http.StreamedResponse response =
await http.Client().send(http.Request('GET', url));
if (response.statusCode == 200) {
var filePath =
join(request.destinationDirPath, '${request.fileName}.ZIP');
var contentLength = response.contentLength;
var bytesLoadedUpdateInterval = (contentLength ?? 0) / 50;
var bytesLoaded = 0;
var bytesLoadedAtLastUpdate = 0;
out = File(filePath).openWrite();
await response.stream.forEach((chunk) {
out?.add(chunk);
bytesLoaded += chunk.length;
// update if enough bytes have passed since last update
if (contentLength != null &&
bytesLoaded - bytesLoadedAtLastUpdate >
bytesLoadedUpdateInterval) {
sendPort.send(bytesLoaded / contentLength);
bytesLoadedAtLastUpdate = bytesLoaded;
}
});
success = true;
if (contentLength != null) {
sendPort.send(1.0); // send 100% downloaded message
}
} else {
errorMessage =
'Download of ${request.fileName} '
'received response ${response.statusCode} - ${response.reasonPhrase}';
}
} catch (e) {
errorMessage = 'Download of ${request.chartType}:${request.chartName} '
'received error $e';
} finally {
await out?.flush();
await out?.close();
if (errorMessage.isNotEmpty) {
sendPort.send(errorMessage);
}
sendPort.send(success);
}
}
}
The code that spawns the isolate then simply checks for the type of the message passed to it to determine the action.
Future<bool> _downloadInBackground(
DownloadRequest request) async {
var receivePort = ReceivePort();
request.sendPort = receivePort.sendPort;
var isDone = Completer();
var success = false;
receivePort.listen((message) {
if (message is double) {
showUpdate(message);
}
if (message is String) {
log.fine(message); // log error messages
}
if (message is bool) {
success = message; // end with success or failure
receivePort.close();
}
}, onDone: () => isDone.complete()); // wraps up
await Isolate.spawn(isolateDownload, request);
await isDone.future;
return success;
}

reconnect with server each 5 seconds by dart

i try to reconnect with the server , the connection established very well and it work every 5 sec very well also , but when i put a condiotn to control the conection it not working and still get new conection added , new connection added
how can i implement this by dart
var nbmer = 0;
var channel;
Timer? timer;
connect() {
Socket.connect(IP, PORT).then((Socket sock) async {
channel = sock;
sock.write('hello world'
);
});
}
try {
if (nbmer == 0) {
timer = Timer.periodic(Duration(seconds: 5), (Timer t) => connect());
}
} catch (e) {
print(e.toString());
}
nbmer += 1;
You should put your condition in the connect() function, because Timer.periodic will be periodically executed and not check your condition (if (nbmer == 0)).
Solution
Your code should look something like this:
var nbmer = 0;
var channel;
Timer? timer;
connect() {
if (nbmer == 0) {
nbmer += 1;
Socket.connect(IP, PORT).then((Socket sock) async {
channel = sock;
sock.write('hello world');
});
}
}
try {
timer = Timer.periodic(Duration(seconds: 5), (Timer t) => connect());
} catch(e) {
print(e.toString());
}

Subscribing to BLE notifications with flutter_reactive_ble throws error?

I'm pretty new to Dart and know nothing about Swift. Trying to use the flutter_reactive_ble package to manage the BT side of an app I'm building. So far things are going smooth up to the point where attempting to enable notifications fails and crashes the app.
The problem occurs when trying to call subscribeToCharacteristic method like this:
class MeshProxyRx extends ReactiveState<Uint8List> {
MeshProxyRx(this._ble);
final FlutterReactiveBle _ble;
final _stateStreamController = StreamController<Uint8List>.broadcast();
StreamSubscription _meshProxyDataOut;
Uint8List rxDataBuffer;
#override
Stream<Uint8List> get state => _stateStreamController.stream;
startNotification(_proxyDevice) {
print('Notification Start');
final characteristic = QualifiedCharacteristic(
serviceId: serviceUuid,
characteristicId: characteristicUuid,
deviceId: _proxyDevice);
_meshProxyDataOut =
_ble.subscribeToCharacteristic(characteristic).listen((data) {
rxDataBuffer.addAll(data);
_stateStreamController.add(rxDataBuffer);
// code to handle incoming data
// ProxyNodeNotify(nodeAddress: [0x18, 0x28]);
print(data);
}, onError: (dynamic error) {
// code to handle errors
print('Start Notification returns Error: $error');
});
}
Future<void> closeStream() async {
await _stateStreamController.close();
}
Future<void> closeSubscription() async {
_meshProxyDataOut?.cancel();
}
}
The error that throws is:
flutter: REACTIVE_BLE: Start connecting to device with arguments (deviceId: 5523499D-8846-A794-F350-1B5E258859F3, servicesWithCharacteristicsToDiscover: null, timeout: null)
flutter: REACTIVE_BLE: Received ConnectionStateUpdate(deviceId: 5523499D-8846-A794-F350-1B5E258859F3, connectionState: DeviceConnectionState.connected, failure: null)
flutter: Notification Start
flutter: REACTIVE_BLE: Start subscribing to notifications for QualifiedCharacteristic(characteristicId: 2ade, serviceId: 1828, deviceId: 5523499D-8846-A794-F350-1B5E258859F3)
Assertion failed: file flutter_reactive_ble/PluginController.swift, line 103
Assertion failed: file flutter_reactive_ble/PluginController.swift, line 103
* thread #1, queue = 'com.apple.main-thread', stop reason = Assertion failed
frame #0: 0x00000001a9cb8e08 libswiftCore.dylib`_swift_runtime_on_report
libswiftCore.dylib`_swift_runtime_on_report:
-> 0x1a9cb8e08 <+0>: ret
libswiftCore.dylib`_swift_reportToDebugger:
0x1a9cb8e0c <+0>: b 0x1a9cb8e08 ; _swift_runtime_on_report
libswiftCore.dylib`_swift_shouldReportFatalErrorsToDebugger:
0x1a9cb8e10 <+0>: adrp x8, 346593
0x1a9cb8e14 <+4>: ldrb w0, [x8, #0x7c8]
Target 0: (Runner) stopped.
Lost connection to device.
For reference the assert that fails is the guard let sink = conntext.characteristicValueUpdateSink line in the swift code block:
onCharacteristicValueUpdate: papply(weak: self) {
context, central, characteristic, value, error in
guard let sink = context.characteristicValueUpdateSink
else { assert(false); return }
let message = CharacteristicValueInfo.with {
$0.characteristic = CharacteristicAddress.with {
$0.characteristicUuid = Uuid.with { $0.data = characteristic.id.data }
$0.serviceUuid = Uuid.with { $0.data = characteristic.serviceID.data }
$0.deviceID = characteristic.peripheralID.uuidString
}
if let value = value {
$0.value = value
}
if let error = error {
$0.failure = GenericFailure.with {
$0.code = Int32(CharacteristicValueUpdateFailure.unknown.rawValue)
$0.message = "\(error)"
}
}
}
sink.add(.success(message))
}
The assert is doing what it is supposed to do but I cannot figure out what I'm not doing right in the way I set up and make the call to subscribeToCharacteristic. I suspect it may be the way the Stream is set up and not getting passed down properly to the swift code since the assert seems to be guarding against a null Sink? But I really don't have enough experience.
Help is greatly appreciated!!

How to use Dart socket onError as inline function?

I have dart socket that gets very long data. Lucky the third party add '\r\n' end of the data, so I can close when I find last data has '\r\n'.
In weeks I am trying to get long data due server problem. Before I used to waiting endlessly to server closes the connection (sometime took me 10 to 12 min)
Now seems everything works but a small problem. I used to get onError and onDone using void function. But I am using aqueduct so I need to return long data after I receive from server as a response.
In my below full code its keep printing "Server_Error". If I comment below data seems everything works. But my problem is that I need to return error data as well.
onError: () {
print("Server_Error");
},
onDone: () {
_socket.destroy();
},
cancelOnError: true);
If I comment above part I can print the long data.
My question is that, based on my scenario how to use Dart socket onError as inline function?
import 'dart:io';
import 'dart:convert';
import 'dart:typed_data';
Socket _socket;
String _reply;
String _testValue = "";
main() async {
String _queryA = “QueryLongData”;
await Socket.connect("192.168.22.120”, 3000).then((Socket sock) {
_socket = sock;
_socket.write('$_queryA\r\n');
_socket.listen((data) {
final List<int> byteArray = data;
_reply = String.fromCharCodes(byteArray);
int dataLen = _reply.length;
int carriageReturnPosition = dataLen - 2;
int newLinePosition = dataLen - 1;
_testValue = _testValue + _reply;
if (_reply.substring(carriageReturnPosition, newLinePosition) == '\r' &&
_reply.substring(newLinePosition, dataLen) == '\n') {
_socket.close();
print("Data: $_testValue"); // means return data
}
}, onError: () {
print("Server_Error");
},
onDone: () {
_socket.destroy();
},
cancelOnError: true);
}).catchError((e) {
print("Server_Error");
});
if(_socket.done == true) {
print("Exiting...");
exit(0);
}
}
<!-- language: dart -->
String _queryA = "QueryLongData";
Socket.connect("192.168.22.120", 3000).then((Socket sock) {
_socket = sock;
_socket.write("$_queryA\r\n");
_socket.listen((data) {
final List<int> byteArray = data;
_reply = String.fromCharCodes(byteArray);
int dataLen = _reply.length;
int carriageReturnPosition = dataLen - 2;
int newLinePosition = dataLen - 1;
_testValue = _testValue + _reply;
if (_reply.substring(carriageReturnPosition, newLinePosition) == "\r" &&
_reply.substring(newLinePosition, dataLen) == "\n") {
_socket.close();
print("Data: $_testValue"); // means return data
}
}, onError: () => print("Server_Error"),
onDone: () => _socket.destroy(),
cancelOnError: true);
}).catchError((e) => print("Server_Error"));
if( ( await _socket.done enter code here) == true) {
print("Exiting...");
exit(0);
}