Open bruno-embtech opened 9 months ago
Hi,
Dart wise I don't see mistakes in your code. Flutter wise, I need to understand where and when are you calling your sendFrameWriteSingleRegister
method.
You can use Provider to notify your widget on any change of the modbus register. Here an example:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:modbus_client/modbus_client.dart';
import 'package:modbus_client_serial/modbus_client_serial.dart';
var _modbusClientSerialRtu = ModbusClientSerialRtu(portName: "COM2", unitId: 1);
class ModbusRegisterModel extends ChangeNotifier {
int? registerId;
dynamic registerValue;
void update(int registerId, dynamic registerValue) {
this.registerId = registerId;
this.registerValue = registerValue;
notifyListeners();
}
}
void sendFrameWriteSingleRegister(
ModbusRegisterModel model, int addr, int register, int data) async {
// Create ModbusInt16Register
var _reg = ModbusInt16Register(
name: "Registrador $register",
address: register,
type: ModbusElementType.holdingRegister,
onUpdate: (self) {
print("Register updated!");
model.update(self.address, self.value);
},
offset: 0,
);
// Send Modbus frame
try {
await _modbusClientSerialRtu.send(_reg.getWriteRequest(data));
} catch (err) {
// Handle the error appropriately
print("Error sending Modbus frame: $err");
}
}
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Modbus Demo',
theme: ThemeData.dark(),
home: Scaffold(
appBar: AppBar(title: const Text('Modbus Demo')),
body: const Center(child: ModbusElementWidget())),
);
}
}
class ModbusElementWidget extends StatelessWidget {
const ModbusElementWidget({super.key});
@override
Widget build(BuildContext context) {
// Capture model changes
return ChangeNotifierProvider<ModbusRegisterModel>(
// Create the model
create: (_) => ModbusRegisterModel(),
builder: (context, child) {
// Here we are watching at this model (getting notified on its changes)
var model = context.watch<ModbusRegisterModel>();
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("Register ${model.registerId} : ${model.registerValue}"),
const Divider(),
ElevatedButton.icon(
onPressed: () {
// NOTE: you might get the register attributes from somewhere!
sendFrameWriteSingleRegister(model, 400001, 400001, 123);
},
icon: const Icon(Icons.send),
label: const Text("Send"),
)
],
);
});
}
}
Hi, thank you for the response.
I was already doing something similar and tested your code, but I encountered the same result. I apologize for the poor description in my previous message, as I forgot to mention a few things:
Here's where I call the function:
TextButton(
child: Text('Click me'),
onPressed: () async {
try {
await _modbus.modbusclient.sendFrameWriteSingleRegister(
0x0001,
0x0041,
(!ModbusController.instance.reles[0]).toInt(),
);
// Update UI based on success
} catch (err) {
// Handle errors gracefully
}
},
),
The problem arises when the result code is requestTimeout
, specifically when the slave board is disconnected.
Here's a visual representation of the issue (using your code as an example, but I'm facing the same problem in my own code):
Aside from this particular situation, everything works flawlessly. The package is indeed easy to use, great work!
I'm trying with the example app I wrote here and I do not get any freezing even if request is timing out because server is not connected. I'm using the app under Windows. On which device are you running your test?
I'm currently running this code on an embedded Linux board, but I also tested it on an x86 Linux system and encountered the same results. This leads me to suspect a potential issue with Linux systems in general. Here's what happens:
This the log :
flutter: FINE: 2024-01-17 08:29:54.371865 - Opening serial port /dev/ttyUSB0...
flutter: FINE: 2024-01-17 08:29:57.383015 - Request completed with code: requestTimeout
flutter: FINE: 2024-01-17 08:30:02.242950 - Request completed with code: requestTimeout
flutter: FINE: 2024-01-17 08:30:21.850988 - Request completed with code: requestTimeout
flutter: FINE: 2024-01-17 08:30:25.983892 - Request completed with code: requestTimeout
I tried also with serial port not responding and I don't have UI getting stuck
I see. Have you tried running your code on a Linux device?
Perhaps the issue is with mine installation.
no, I didn't
Hi there,
I've been investigating the reported issue further and identified the root cause. It seems to be specific to Linux devices, based on both my limited testing with other platforms and your confirmation that it works on your Windows machine.
The problem lies in the libserialport
package, which is wrapped by flutter_libserialport
. Within the read()
function, there are two conditional branches based on the timeout parameter:
@override
Uint8List read(int bytes, {int timeout = -1}) {
return Util.read(bytes, (ffi.Pointer<ffi.Uint8> ptr) {
if (timeout < 0) {
return dylib.sp_nonblocking_read(_port, ptr.cast(), bytes);
} else {
return dylib.sp_blocking_read(_port, ptr.cast(), bytes, timeout);
}
});
}
The problem arises because of the timeout of your package doesn't support a timeout of -1, intended for non-blocking behavior. Consequently, the read()
function always falls back to blocking mode, leading to the observed issue.
Here's what I suggest:
Enable -1 timeout for Linux: Modify your package to allow setting the timeout to -1 . This would enable the desired non-blocking behavior when needed.
Document the limitation: Clearly explain this platform-specific limitation on the package's pub.dev page. This would raise awareness among developers and suggest potential workarounds.
Additional thoughts:
I hope this information helps diagnose and resolve the issue!
Edit:
Actually you can set to -1 using Duration(miliseconds:-1)
Nice catch!
I did a quick check and current reading implementation uses that timeout. Strange is that the high level modbus reading is marked as async.
I will try a different approach by using serial read with -1 as timeout
While implementing the fix I've discovered this issue in libserialport: https://github.com/jpnurmi/libserialport.dart/issues/83 I was simply moving all the serialPort!.read(....) to the below method, but it throws exception
Uint8List _serialRead(int byteCount, int timeout_ms) {
List<int> rxData = [];
var stopWatch = Stopwatch()..start();
while (stopWatch.elapsedMilliseconds < timeout_ms) {
var data = _serialPort!.read(byteCount - rxData.length);
rxData.addAll(data);
if (byteCount <= rxData.length) {
break;
}
}
return Uint8List.fromList(rxData);
}
Hello, I'm attempting to create an abstraction of this package for use in my application, but I'm encountering issues with asynchronous execution. The UI freezes while the function is running. I'm still learning Flutter and Dart, and I've successfully implemented simple async tasks in the past.
Here's a snippet of the function:
I'd appreciate any suggestions or examples to address the UI freezing issue.