Open MANOJKUMAR26 opened 1 month ago
Did you re-create a same device name SerialPort? It shoude be single-instance mode.
I see you use port = SerialPort(selectedDevice.portName, openNow: false,BaudRate:9600, ReadIntervalTimeout: 1, ReadTotalTimeoutConstant: 2);
every time.
And do you know the info of SetCommState error
?
Hello @FengChendian , Thanks for your response.
Actually in my scenario, the same device can be connected to different COM ports, Now I tried creating singleton class for serial port and called the same in the method like below: class SerialPortSingleton { static final SerialPortSingleton _instance = SerialPortSingleton._internal(); SerialPort? port;
factory SerialPortSingleton() { return _instance; }
SerialPortSingleton._internal();
void initialize(String portName) { if (port == null) { port = SerialPort(portName, openNow: false, BaudRate: 9600, ReadIntervalTimeout: 1, ReadTotalTimeoutConstant: 2); } }
void openPort() { if (port != null && !port!.isOpened) { port!.open(); } }
void closePort() { if (port != null && port!.isOpened) { port!.close(); } } }
And in the method I am calling as below: if (ports.isNotEmpty) { SerialPortSingleton().initialize(selectedDevice.portName); SerialPortSingleton().openPort(); print(SerialPortSingleton().port?.isOpened);
For closing port: SerialPortSingleton().port?.close();
But like I said first time when I started the reading it showed perfectly. After stopping the port and starting again, I am still getting the same error as below:
flutter: [Port Name: COM5, FriendlyName: USB-SERIAL CH340 (COM5)]
flutter: [COM5]
Another exception was thrown: Exception: SetCommState error
flutter: [Port Name: COM5, FriendlyName: USB-SERIAL CH340 (COM5)]
flutter: [COM5]
Another exception was thrown: Exception: Open port failed, error is 5
I don't have much info on these errors.
Hello @FengChendian , Thanks for your response.
Actually in my scenario, the same device can be connected to different COM ports, Now I tried creating singleton class for serial port and called the same in the method like below: class SerialPortSingleton { static final SerialPortSingleton _instance = SerialPortSingleton._internal(); SerialPort? port;
factory SerialPortSingleton() { return _instance; }
SerialPortSingleton._internal();
void initialize(String portName) { if (port == null) { port = SerialPort(portName, openNow: false, BaudRate: 9600, ReadIntervalTimeout: 1, ReadTotalTimeoutConstant: 2); } }
void openPort() { if (port != null && !port!.isOpened) { port!.open(); } }
void closePort() { if (port != null && port!.isOpened) { port!.close(); } } }
And in the method I am calling as below: if (ports.isNotEmpty) { SerialPortSingleton().initialize(selectedDevice.portName); SerialPortSingleton().openPort(); print(SerialPortSingleton().port?.isOpened);
For closing port: SerialPortSingleton().port?.close();
But like I said first time when I started the reading it showed perfectly. After stopping the port and starting again, I am still getting the same error as below: flutter: [Port Name: COM5, FriendlyName: USB-SERIAL CH340 (COM5)] flutter: [COM5] Another exception was thrown: Exception: SetCommState error flutter: [Port Name: COM5, FriendlyName: USB-SERIAL CH340 (COM5)] flutter: [COM5] Another exception was thrown: Exception: Open port failed, error is 5
I don't have much info on these errors.
Do you use port.close()
before you re-open it? Error code 5 means that Access is denied. It happened when your serial port is occupied (not closed in last instance). If you stop port by plugging USB, the port will not be closed properly in dart.
Hello @FengChendian , I have made sure (checked during debug mode also) to close the port before I try to re-open but still I am getting this error. Like you said If I remove the usb plug and insert the plug again, it works but keeping it inserted always and trying to close and open the port programmatically is causing the problem. Can you help me to fix this issue please?
I tested it. And I think it's due to the basic dependency ( win32
package) is too older to implement CloseHandler
Function. I will try to update it to the latest version. You can try it again.
In example folder, you can see
void _send() async {
if (!port.isOpened) {
port.open();
}
port.writeBytesFromString("AT", includeZeroTerminator: false);
print(await port.readBytesUntil(Uint8List.fromList("T".codeUnits)));
port.close();
}
I use this code to test close and re-open. And it worked perfectly with latest win32 5.7.2
. But not worked on win32 5.0.5
.
Please test serial port win32 1.4.0
version. If bug exists in the new version, please give me feedback.
Hello @FengChendian , Even after upgrading to 1.4.2 version, I am facing the same issue. First time it opens the ports and reads properly. During the call of port.close function I can see in the debug mode that isOpened is changing to false. But still second time when i tried to open and read the port, getting "_Exception (Exception: SetCommState error)"
The below is where exactly I am facing the issue:
Can you please help me out with this?
Hello @FengChendian , Even after upgrading to 1.4.2 version, I am facing the same issue. First time it opens the ports and reads properly. During the call of port.close function I can see in the debug mode that isOpened is changing to false. But still second time when i tried to open and read the port, getting "_Exception (Exception: SetCommState error)"
The below is where exactly I am facing the issue:
Can you please help me out with this?
Um... It's really strange.
I see readData
function is in your call stack. Are you still reading when port is closed? I mean that you use readOnListen
and has a stream. The library doesn't cancel stream when port is closed. Maybe a uncanceled readOnListen
stream can cause setCommState
error in some specific platform, I guess.
Can you disable all read/write functions and re-test it?
Or please give me a mini whole example project which can reproduce the bug. Although maybe this bug doesn't occur on my pc...
By the way, what is your windows version and flutter version?
Hello @FengChendian , Below is my flutter and dart version -
Sharing you the example code repository which is causing the error. https://github.com/MANOJKUMAR26/serial_win_32_sample_project/tree/test
Can you please check and suggest if I am going wrong somewhere.
The bug should be fixed in version 2.1.3. Thanks for @halildurmus.
@MANOJKUMAR26 By the way, do you use code working with Virtual Serial Port ? In my pc, this bug occurs only if I test it on Virtual Port.
Here is the bug fixed test:
I change some your codes for read function. Because:
_cache.putIfAbsent
. But I can not open port when use your singleton class. So I remove it and test without external sigleton.import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:sample_project/SerialPortSingleton.dart';
import 'package:serial_port_win32/serial_port_win32.dart';
import 'package:sample_project/main.dart';
import 'package:english_words/english_words.dart';
import 'package:timer_builder/timer_builder.dart';
import 'package:intl/intl.dart';
import 'package:flutter/services.dart';
import 'package:oktoast/oktoast.dart';
class ReadingScreen extends StatefulWidget {
const ReadingScreen({Key? key}) : super(key: key);
@override
ReadingPage createState() => ReadingPage();
}
class ReadingPage extends State<ReadingScreen> {
var ports = <String>[];
late String data = '0.0';
bool light = true;
bool startReadingFlag = false;
String startTime = '';
String endTime = '';
String userName = '';
late int startDate;
final sendData = Uint8List.fromList(List.filled(4, 1, growable: false));
SerialPort? serialSingle;
@override
void initState() {
super.initState();
}
void _getPortsAndClose() {
serialSingle?.close();
showToast('Readings stopped successfully',
duration: Duration(seconds: 3),
position: const ToastPosition(align: Alignment.topRight),
backgroundColor: Colors.green);
}
void _getPortsAndOpen() {
final List<PortInfo> portInfoLists = SerialPort.getPortsWithFullMessages();
ports = SerialPort.getAvailablePorts();
String datacopy = '';
print(portInfoLists);
print(ports);
if (ports.isNotEmpty) {
// Initialising the port name here
serialSingle ??= SerialPort('COM1', openNow: false);
serialSingle?.open();
print(serialSingle?.isOpened);
String incomingData = '';
String completeData = '';
// while (port.isOpened) {
// incomingData = '';
serialSingle?.readBytes(8, timeout: Duration(seconds: 10)).then((value) {
print('check vlaue ${utf8.decode(value)}');
// if (utf8.decode(value) != '+' && utf8.decode(value) != ',') {
incomingData += utf8.decode(value);
print('check incoming data ${incomingData.length}');
if (incomingData.length > 50) {
String trimmedData = incomingData.substring(35);
incomingData = trimmedData;
}
List<String> parts = incomingData.split(',');
print('check parts $parts');
final regex = RegExp(
r'[+-]\d+(?:\.\d+)?'); // Matches numbers optionally followed by a decimal point
List<double> extractedValues = [];
for (var part in parts) {
final match = regex.matchAsPrefix(part);
if (match != null) {
// Extract the captured group (the number) and convert to double
extractedValues.add(double.parse(
match.group(0)!.substring(1))); // Remove leading "+"
}
}
if (extractedValues.length >= 2) {
completeData = extractedValues[extractedValues.length - 2].toString();
}
print('check data and complete data $data, $completeData');
setState(() {
data = completeData;
});
});
}
}
void _getStartDateWithTime(DateTime data) {
startDate = data.millisecondsSinceEpoch;
}
String getSystemTime() {
var now = DateTime.now();
return DateFormat("hh:mm:ss a").format(now);
}
String getSystemDateAndTime(String inputFormat) {
var now = DateTime.now();
DateFormat.yMd().add_jm();
var formattedMonthYear = DateFormat(inputFormat);
String formatMonthYear = formattedMonthYear.format(now);
return formatMonthYear;
}
@override
Widget build(BuildContext context) {
var appState = context.watch<MyAppState>();
var pair = appState.current;
IconData icon;
if (appState.favorites.contains(pair)) {
icon = Icons.favorite;
} else {
icon = Icons.favorite_border;
}
return Container(
padding: const EdgeInsets.fromLTRB(40, 20, 20, 40),
color: Colors.white,
child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Column(
children: <Widget>[
const SizedBox(
width: 500,
child: Text(
'Setup',
textAlign: TextAlign.left,
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
))
],
),
const SizedBox(height: 10),
Row(
mainAxisSize: MainAxisSize.min,
children: [
(!startReadingFlag)
? (ElevatedButton.icon(
onPressed: () {
_getPortsAndOpen();
setState(() {
startReadingFlag = true;
startTime = getSystemTime();
});
// appState.toggleFavorite();
},
icon: const Icon(Icons.play_arrow),
style: const ButtonStyle(
foregroundColor:
WidgetStatePropertyAll<Color>(Colors.white),
backgroundColor: WidgetStatePropertyAll<Color>(
Color.fromRGBO(0, 145, 255, 1))),
label: const Text('START READING',
style: TextStyle(color: Colors.white)),
))
: (ElevatedButton.icon(
onPressed: () {
_getPortsAndClose();
setState(() {
startReadingFlag = false;
endTime = getSystemTime();
});
},
icon: const Icon(Icons.stop),
label: const Text('STOP READING',
style: TextStyle(color: Colors.white)),
style: const ButtonStyle(
foregroundColor:
WidgetStatePropertyAll<Color>(Colors.white),
backgroundColor: WidgetStatePropertyAll<Color>(
Color.fromRGBO(255, 111, 0, 1))),
)),
],
),
const SizedBox(width: 100),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
child: Text(
'Readings',
textAlign: TextAlign.left,
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
)),
Padding(
padding: const EdgeInsets.only(top: 20, bottom: 20),
child: TimeCard(
startTime: startTime,
startDateWithTime: _getStartDateWithTime,
endTime: endTime,
startReadingFlag: startReadingFlag),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Padding(
padding: const EdgeInsets.only(right: 20),
child: SizedBox(
height: 220,
width: 230,
child: BigCard(pair: pair, data: data),
))
],
),
],
),
],
),
);
}
}
class BigCard extends StatelessWidget {
const BigCard({super.key, required this.pair, required this.data});
final WordPair pair;
final String data;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final style = theme.textTheme.displayMedium!
.copyWith(color: theme.colorScheme.onSecondary, fontSize: 50);
return Card(
color: theme.colorScheme.secondary,
child: Center(
child: Text(
data,
style: const TextStyle(fontSize: 30, color: Colors.white),
semanticsLabel: data,
),
),
);
}
}
class TimeCard extends StatelessWidget {
const TimeCard(
{super.key,
required this.startTime,
required this.endTime,
required this.startDateWithTime,
required this.startReadingFlag});
final String startTime;
final String endTime;
final void Function(DateTime) startDateWithTime;
final bool startReadingFlag;
String getSystemTime() {
var now = DateTime.now();
// DateFormat.yMd().add_jm().format(now)
startDateWithTime(now);
return DateFormat("hh:mm:ss a").format(now);
}
String getSystemDate(String inputFormat) {
var now = DateTime.now();
var formattedMonthYear = DateFormat(inputFormat);
String formatMonthYear = formattedMonthYear.format(now);
return formatMonthYear;
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Card(
color: theme.colorScheme.secondary,
child: Padding(
padding: const EdgeInsets.all(15),
child: Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(getSystemDate('d'),
style:
const TextStyle(fontSize: 30, color: Colors.white)),
Text(getSystemDate('MMMM y'),
style: const TextStyle(fontSize: 20, color: Colors.white))
],
),
const SizedBox(width: 80),
Column(
children: [
const Text('Start time',
style: TextStyle(fontSize: 15, color: Colors.white)),
SizedBox(
width: 130,
height: 50,
child: Card(
child: Center(
child: Text(
startTime,
style: const TextStyle(
color: Color(0xff2d386b),
fontSize: 16,
fontWeight: FontWeight.w700),
))))
],
),
const SizedBox(width: 20),
Column(
children: [
const Text('End time',
style: TextStyle(fontSize: 15, color: Colors.white)),
SizedBox(
width: 130,
height: 50,
child: Card(
child: Center(
child:
(startReadingFlag == true && startTime != '')
? TimerBuilder.periodic(
const Duration(seconds: 1),
builder: (context) {
return Text(
getSystemTime(),
style: const TextStyle(
color: Color(0xff2d386b),
fontSize: 16,
fontWeight: FontWeight.w700),
);
})
: (startTime == '' &&
startReadingFlag == false)
? (null)
: Text(
endTime,
style: const TextStyle(
color: Color(0xff2d386b),
fontSize: 16,
fontWeight: FontWeight.w700),
))))
],
),
],
),
));
}
}
The version 2.x lib now has three re-design API. readBytes
is similar with readOnListen
. But it has a timeout parameter.
print(await port.readBytesUntil(Uint8List.fromList("T".codeUnits))); /// '\0' is not included
/// or
var read = port.readBytes(18, timeout: Duration(milliseconds: 10))..then((onValue) => print(onValue));
var result = await read;
print(result);
/// or
var fixedBytesRead = port.readFixedSizeBytes(2)..then((onValue) => print(onValue));
await fixedBytesRead;
/// see more in small example
Hello @FengChendian , I am using the physical device (USB Serial port) to test the code. I upgraded the library version to serial_port_win32: ^2.1.3 and tried using the above code which you shared removing singleton code and I see the error still exist and this time I am not able to open the port from the first time only.
@MANOJKUMAR26
INVALID_HANDLE_VALUE
but there is still a valid handle (opened port) which you can't fetch.EDIT: I notice your USB-SERIAL is CH340. So, I use a ch340 chip to test. And I found it may enter ERROR_IO_PENDING
in some older drivers. I published version 2.1.5 to fix it.
Hello @FengChendian , Now I can open and close the port but when I open the port every time, I am getting below attached error. I am not able to read the data after I open the port, not sure if this is because of the below attached error. Previously readBytesOnListen function used to show the correct reading from the same device but now with this new read functions (tried all 3 read function) I am getting just array of zeros. Can you please suggest
It's a really weird bug……
So,
SetCommState
Error code 0
, but you can read right thing.SetCommState
reports error code 31
@MANOJKUMAR26
3.8.2023.2
The test for ch340 local loopback in example/main.dart
can work on my pc. You can see version in COM Port properties --> Driver.BandRate
if you communicate with other devices. I see your original code is 9600
. But now you use default 115200
.Sharing you the driver version for the first error:
Also Sorry, As you suggested It was my mistake on updating the baud rate. I have updated it to 9600 and tried to use readBytes function but I am getting only one value. Actually the device value keeps changing and all the changing of numbers should be visible on screen but It is sending only one initial value. I tried using print(await serialSingle!.readBytesUntil(Uint8List.fromList("T".codeUnits))); function also but I am not getting any data using this function and when I close the port I am getting below error for readBytesUntil Function.
@MANOJKUMAR26
readBytes
once, so it reads once. It should be true behaviour. If you want to read loop, you can use code like:
for (int i=0; i < 100; i++) {
var a = await readBytes();
/// some things
}
It is a basic loop read. Also, you can use stream like:
Stream<Uint8List> process() async* {
for (int i=0; i < 100; i++) {
var a = await readBytes();
yield a;
}
}
https://dart.dev/libraries/async/creating-streams
In version 1.x, you can use readOnListen
to loop read. But it can't be directly controlled by users. So, I remove it in 2.x.
BTW, if you use readBytes
many times and you read same things. You need to consider that your device sends wrong data.
ClearCommError
is a reasonable exception. You use readBytesUntil
to read something, but return conditions is not satisfied for some reasons. Your read is still not completed. If you close the port, you will still read after close port (Maybe I should add some warning in close
port and stop read). You need to ensure that all I/O function is done when you close it.
And maybe your device doesn't send string ends with 'T'. For example, it sends 'xx t' ends with 't'. They are different codes. Or device sends "Xxxxxxxxxxxxxxxxx" but doesn't contain "T", function will not be completed.
Hi Team, I am trying to read serial data through USB for flutter windows desktop application. The data gets read the first time properly but when I stop the port and start the reading again, I am getting setCommState error. I am using : serial_port_win32: ^1.3.0
Below is the code I am using to open the port and read the data and close the port.
late SerialPort port; void _getPortsAndClose() { port.close(); showToast( 'Readings stopped successfully', duration: Duration(seconds: 3), position: const ToastPosition(align: Alignment.topRight), backgroundColor: Colors.green ); }
void _getPortsAndOpen(Device selectedDevice) { final List portInfoLists = SerialPort.getPortsWithFullMessages();
ports = SerialPort.getAvailablePorts();
String datacopy = '';
print(portInfoLists);
print(ports);
if (ports.isNotEmpty) {