I am new on this forum but I have always checked it out and I appreciate it very much.
I must say in the beginning that I am not a very skilled or knowledgable software programmer and for the past days I am stuck on a problem. I have a barcode reader on my COM1 port. I connect, I write "TRIGGER", it returns with(hopefully) "OK", when I have the OK, then I send a "READ", and it comes back with a big line with some fields. So here is right now how my code looks like; (the code is mainly like this. I didn`t write it all but the serialPort and waitHandle stuff is like below)
in SerialPortExample class,
public AutoResetEvent waitHandle = new AutoResetEvent(false);
public string Read()
{
for (int i=0; i<1000; i++) {
this._serialPort.Write("TRIGGER" + Convert.ToChar(0));
waitHandle.WaitOne();
// a couple lines of stuff
this._serialPort.Write("GETSTRINGRESULTS" + Convert.ToChar(0));
waitHandle.WaitOne();
if (OBarcode.ReadStatus == ReadStatus.SUCCESS) {
return OBarcode.BarcodeString;
}
}
return "";
}
this is raised when some answer from serialPort
void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try {
string value = _serialPort.ReadExisting();
...
// stuff
waitHandle.Set();
} catch(Exception ex) {
// stuff
}
}
in the form with behind a button click, I open the connection, do the Read(), Close() the connection and so on. I have seen this AutoResetEvent online and decided to use. When I click the button for the first time, everything runs smooth, but, if I click the button again. which reoopens the closed connection and does the read again, this time the WaitOne() doesn`t wait.
I would appreciate very much appreciate your help. How should I normally handle this? I am doing something seriously wrong.
Related
Consider I have an event listener in C# that waits for the data from the serial port, which are returned once captured by setting some status. In the main loop I look into that status and based on that I decide what to do next.
To do that I first write the command into the serial port and wait for the output by using Thread.Sleep method. By the time when the main thread is still in sleep mode, the event listener would already send the data and there is nothing done to handle that scenario.
Can anyone please tell me what would be the outcome in this condition and how to prevent it?
The code would be like
bool status = false;
//main thread
private void Main()
{
//some Code
serialPort.Write("something");
//Wait for 10 sec
Thread.Sleep(10000);
while(status == false)
{
// do something else
}
}
//Ignore the syntax, this is just to make people understand
public void OndataReceived(object sender, EventArg arg)
{
//Function that recieve the data
Receive();
//change status to true
status = true;
return;
}
The question is awkwardly worded, but if I understand it correctly, you are asking how you can avoid waiting ten seconds if the data is received earlier than that.
It is possible to use older synchronization objects, such as one of the WaitHandle subclasses, Monitor, or even a semaphore. But for this type of scenario, the current C# idiom is to use TaskCompletionSource, which provides both a waitable object and the option to return a result value at the same time.
For example:
TaskCompletionSource<bool> _result;
//main thread
private void Main()
{
//some Code
serialPort.Write("something");
_result = new TaskCompletionSource<bool>();
// Normally, one should "await" a Task. But in the Main() method, which
// cannot be "async", we have to just wait synchronously.
Task completed = Task.WhenAny(_result.Task,
Task.Delay(TimeSpan.FromSeconds(10)).Result;
// Don't check "_result.Result" unless the task has completed,
// because otherwise the thread will block. If it is completed,
// check "_result.Result" as the equivalent to examining the "status"
// variable in the previous code example.
while(!_result.IsCompleted || !_result.Result)
{
// do something else
}
}
public void OndataReceived(object sender, EventArg arg)
{
//Function that recieve the data
Receive();
//change status to true
_result.SetResult(true);
return;
}
What you really need is separate threads, a state machine, and delegates (callbacks). I wrote a decent example here: https://stackoverflow.com/a/38536373/2009197
So Ive been at it for some time.
Reaching the end of the stream the program freezes till there is new input only to freeze again.
Using a thread I get the exception that I cant access the Textbox from that thread. backgroundworker just doesnt do anything.
Im really kinda lost here
my code kinda looks like this
in the class that manages the tcp stream:
string readMessage()
{
return inputStream.ReadLine()
}
in my windows form class I need to somehow keep updating the textbox with the input stream without freezing the ui
public string readMessage()
{
string message;
message = inputStream.ReadLine();
return message;
}
that is what handles the tcp stream
now in my main form class it looks like this:
void Refresh(object sender, EventArgs e)
{
Thread.Sleep(1000);
n+=1;
label1.Text = Convert.ToString(n);
}
public void update()
{
Channel.AppendText(irc.readMessage());
}
void WORK()
{
while(true)
{
Channel.Invoke(new MethodInvoker(() => update()));
}
}
Work is the method called by the thread, while refresh is a method called by a timer that periodically sets the main thread to rest so the other thread can do it's work
that got it to run... until it reaches the end of the current stream and freezes again, until there is a new input in the stream which it quickly writes to the textbox and freezez again, which is exactly what I don't want.
edit: I managed to get it to work with the tcp.SenderTimeout, setting the timeout to a few ms and only updating the chat once a second but it still feels really unresponsive.
Is there a way to make it run smoother in the background? since Ill also have to work and respond to the input at runtime.
I have created a wpf from and in it each time I get two byte from serial port and find the difference between them and then in a while loop I show the difference by a textbox:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
}
SerialPort port;
private void StartButton_Click(object sender, RoutedEventArgs e)
{
port = new SerialPort("COM3");
port.BaudRate = 9600;
port.DtrEnable = true;
port.RtsEnable = true;
port.Handshake = Handshake.None;
port.Open();
try
{
if (!port.IsOpen)
throw new Exception();
}
catch (Exception)
{
Console.Out.WriteLine("port is not open!!");
}
while (port.IsOpen)
{
var b1 = port.ReadByte();
var b2 = port.ReadByte();
double t1 = b1 * 1e-9;
double t2 = b2 * 1e-9; ;
var dift = t2 - t1;
if (dift == 0)
{
this.SpeedTextBox.Text = "0";
continue;
}
this.SpeedTextBox.Text = dift;
}
}
private void StopButton_Click(object sender, RoutedEventArgs e)
{
if (port != null)
{
if (port.IsOpen) port.Close();
port.Dispose();
}
}
}
but when I execute it and click on StartButton the form will be stoped working.I know that program receives data( I tested it with another simple program) . but I don't know what goes wrong here!!
can anyone help me?
thanks in advance.
ReadByte() is a blocking method, it won't return until a byte was received. This is why SerialPort has the DataReceived event.
First use another program like Hyperterminal or Putty to test the connection and eliminate simple mistakes like bad wiring, picking the wrong port number or baud rate and getting the Parity, DataBits and StopBits settings wrong. Which you don't set so there are non-zero odds that you'll get framing errors. You must implement the ErrorReceived event to ensure these kind of errors do not go unobserved and leave you mystified why it doesn't work.
If you don't use DataReceived then it is also important that you use the ReadTimeout property to ensure your program doesn't hang forever without any way to diagnose the cause if there's something wrong with the connection. Be prepared to catch the TimeoutException.
SysInternals' PortMon is a very useful utility to compare good vs bad, it shows you exactly what's going on inside the serial port driver. Beware however that it doesn't work on a 64-bit operating system.
Hans has covered the serial port cases, but another reason why your program will lock up is that your click handler uses an infinite wait loop. The way Windows applications work is that they have a main loop that gets messages (like click events) from a queue. For each message, your event handler is called, and it is only when your event handler returns control to the main loop that it can process the next message (e.g. to redraw your window and show the new text you have set on your control). So you can't use a long loop or blocking calls in your event handler if you want your program to remain responsive to user input.
I am work on a very simple program (C# WPF application in VS2010) that display data from SerialPort and display on a TextBox. The program works fine in normal circumstances. But when user open a connection, collect some data, close it, and open it again, and do this for several cycles, the program will eventually throw an exception:
"The I/O operation has been aborted because of either a thread exit or an application request."
[The I/O Exception occurred in the ReadLine()]
Sometime the program would throw me an exception; sometimes the program just hangs.
Below is my code:
/* Click to Open ComPort */
private void PortOpen_Click(object sender, RoutedEventArgs e)
{
if (!serialPort1.IsOpen)
{
serialPort1.PortName = "COM1";
serialPort1.BaudRate = 9600;
serialPort1.ReceivedBytesThreshold = 1;
serialPort1.NewLine = "\r\n";
serialPort1.Parity = Parity.None;
serialPort1.StopBits = StopBits.One;
serialPort1.DataBits = 8;
serialPort1.Handshake = Handshake.None;
serialPort1.Open();
serialPort1.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(Receive);
}
}
/* Receive data from ComPort */
private void Receive(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
if (serialPort1.IsOpen)
{
try
{
string1 = serialPort1.ReadLine(); /* This is where I/O Exception occurred */
Dispatcher.Invoke(DispatcherPriority.Send, new UpdateUiTextDelegate(DisplayText), string1);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}
private void DisplayText(string string1)
{
textBox1.Text = string1;
}
/* Close ComPort */
private void PortClose_Click(object sender, RoutedEventArgs e)
{
if (serialPort1.IsOpen)
{
serialPort1.Close();
}
}
Following summarize my head-banging-against-table attempts in the past 40 hours which result in no progress:
I have tried add Thread.Sleep(3000) before and after Open() and Close(). And I start to get so frustrated that I put Thread.Sleep in between every single line. I though that would allow enough time for some unfinished working in the background. Doesn't solve the problem.
I tried Zach Saw's Post. A lot of comments left on the blog post are very positive. I tried the approach and even copy and paste the exact code to mine. Doesn't solve the problem. A very long post that wasted half of my day.
Kim Hamilton address the issues here. which suggest using BeginInvoke instead of Invoke. Tried and still persist the same problem.
There was a very nice commercial SerialPort library Franson SerialTools which is fairly cheap and works fantastic with no bugs regardless of how many time and how quick I Open() or Close() the serialPort. However, they have discontinue their development and the library they have only works on Form application, not WPF. Some of their argument in their API only accepts Forms.Control. too bad. There are other Commercial product out there but either they are overly priced or do not offer free trail so I wouldn't know whether it works or not before purchase
Does anyone get the .NET SerialPort to work and actually check for bugs (Open() and Close() many times - even when there are no incoming data)?
When you open port you add event handler, when closing i think you should remove it.
Try to do this:
private void PortClose_Click(object sender, RoutedEventArgs e)
{
if (serialPort1.IsOpen)
{
serialPort1.DataReceived -= Receive;
serialPort1.Close();
}
}
Hope this solves problem.
I imagine the blocking call to ReadLine is interrupted by a call to Close from the UI thread. What's wrong with catching this error? I would expect it to happen.
#Reniuz solution didn't help me also.
Actually I couldn't understand how it could help at all, obviously as #Hans Passant comment, the DataReceived could be already in progress while unsubscribing the event.
My solution for this was to unsubscribe within the DataReceived event, just raise a flag whenever unsubscribe is needed and check for it in the DataReceived event.
public void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
// Brief: Handle data received event
{
// Read the data
// ~~~~~~~~~~~~~
// Check for unsubscribe
// ~~~~~~~~~~~~~~~~~~~~~
if (bStopDataRequested)
{
serialPort1.DataReceived -= DataReceivedHandler; // Unsubscribe to DataReceived event
// Only then close the port
}
}
I have a problem that I'd like some advice on. I have a button in my GUI that starts a complicated setup sequence (to connect to a analogue to digital converter and start logging data from an echo sounder). Once it is finished setting up, the button changes from START to STOP and has the expected behaviour. What I was experiencing is that during the long operation, if the user clicked on the button again (even though it was disabled) the event would still be sent to the button once it was reenabled. The only way I've found to make this work properly is to call Application.DoEvents() before enabling the button again. All I really want to do is swallow up the events destined for my button, so DoEvents() seems a bit heavy handed. Since people seem to be unanimously against calling DoEvents() I'm hoping that the bright minds here can help me come up with an alternative solution. Note I haven't tried my demo code but it follows my real code closely, excepting the really long methods.
Is there an alternative way to accomplish this?
Is it safe(ish) to call DoEvents() from the completion portion of the background worker?
public class Form1 : Form
{
BackgroundWorker worker;
Button startButton;
bool state;
public Form1() {
state = false;
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(StartSequence);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(ToggleButton);
startButton = new Button();
startButton.Text = "START";
startButton.Click += new System.EventHandler(StartClicked);
this.Controls.Add(startButton);
}
private void StartClicked( object sender, EventArgs e ) {
startButton.Enabled = false;
worker.RunWorkerAsync( !state );
}
private void StartSequence( object sender, DoWorkEventArgs e ) {
bool onState = (bool) e.Argument;
if ( onState ) {
RunReallyLongStartupSequence();
}
else {
RunReallyLongStopSequence();
}
state = onState;
}
private void ToggleButton( object sender, RunWorkerCompletedEventArgs e ) {
startButton.Text = state ? "STOP" : "START";
// THIS IS WHAT I AM WORRIED ABOUT!
Application.DoEvents();
startButton.Enabled = true;
}
}
Application.DoEvents() isn't heavy-handed, and I don't think programmers are unanimously opposed to DoEvents in all cases. DoEvents has a bad reputation because it has traditionally been used as a magical hack fix for badly-written code. In your case, it is the proper and normal way to deal with your situation.
In Windows, the situation you describe (where clicks on disabled buttons are applied when the buttons are re-enabled) is actually normal, expected behavior for a control. However, this does not mean that it is always desirable behavior from a programmer's standpoint, and if you have users that are prone to clicking away on disabled buttons, then the simplest way is to use DoEvents, which is nothing more than a method telling the form to go ahead and process any events it has queued up. Use it proudly!
First of all, I do not find DoEvents() bad at all, especially when it comes to gui, you can't imagine how many times it has helped me , and if you create things like progress bars, it is pretty much mandatory if you want to see it update, all I'm saying is that I don't really get why it is considered a bad command.
On the topic though, what I usually do in such situations is not disable the control at all
I use something similar to the following
public Class myForm :Form
{
private bool _working = false;
public myForm()
{
_working = true;
//code here
this.btnDoStuff.Click += new System.EventHandler(DoStuffClick);
_working = false;
}
private void DoStuffClick(object sender, EventArgs e)
{
if (_working) return;
_working = true;
DoStuff();
_working = false;
}
private void DoStuff()
{
//your code goes here
}
}
I find that the above helps me when it comes to allowing the user to do only one thing at a time, and if I want to be able to allow the user to do multiple stuff( for example while the command executes , to be able to press other buttons) I usually put the DoStuff() code to execute in a different thread
In case you were wandering, the reason I use an extra method (DoStuff()) to perform the actions, is that sometimes I need to execute code form other methods in one method, and if the _working flag is set to true, I can't call DoStuffClick(null , new EventArgs()) as it will not do anything
I hope I helped
p.s. yes I know it's been two years, but I only joined stackoverflow the other day (: