C# Gui Refresh and Async Serial Port Communication

How should I update my UI from C# events triggered by serial port data?

If i understand:
First approach - always call invoke to update UI
Second approach - if InvokeRequired returns true call invoke else - just do UI stuff

Now, if we know that handle for control was created and we want just made small and fast UI updates we can use first approach and UI will be responsible, but with Invoke deadlock is still possible. Than if we don't now if the handle for control is created we must call IsHandleCreated to ensure that Invoke will be successfull and will not throw exception. If IsHandleCreated returns false we cannot update via Invoke and we must wait for handle to be created.

Second approach is worse, because field.InvokeRequired may return false if handle for control is not created and when we call field.Text = d; the control's handle may be created on the background thread, isolating the control on a thread without a message pump and making the application unstable.

So as for me this is the better way:

private void port_DataReceived(object sender, SerialDataReceivedEventArgs e) {
input = (sender as SerialPort).ReadLine();
if (input.Contains("look for this"))
{ if (this.IsHandleCreated == false)
{
//do some stuff to proper handle creation or just wait for handle creation
}

this.BeginInvoke(new EventHandler(doSomething));
}
}

Receiving data from serial port in C#, while updating ui

you have to use Serial Port DataReceived Event and Delegate

    private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{

if (TextBox.InvokeRequired)
TextBox.Invoke(new myDelegate(updateTextBox));

}
public delegate void myDelegate();

public void updateTextBox()
{
int iBytesToRead = serialPort1.BytesToRead;
//Your Codes For reding From Serial Port Such as this:
char[] ch = new char[?];
serialPort1.Read(ch, 0, ?? ).ToString();
//........

}

Asynchronous serial communication thread options

That isn't frequent enough to justify burning up an expensive resource like a Thread. Use a System.Timers.Timer or System.Threading.Timer (better) instead. Write the device query command in the callback. Use the SerialPort.DataReceived event to receive the response and fire the event. Now everything runs on cheap threadpool threads.

C# Serial Port, wait for correct Response before allowing a new message

After 4 days of almost no sleep I figure it out and want to post the solution to anybody who is trying to have some sort of a flow control in their serial communication. In the end I was using async methods. I think this is as simple as it can get for somebody who doesn't have a lot of C# experience. Here is the code for the form:

    namespace serialInterfaceTest
{

public partial class Form1 : Form
{
string serialDataIn;

public Form1()
{
InitializeComponent();
serialPort.PortName = "COM3";
serialPort.BaudRate = 9600;
serialPort.Open();
}

private void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
serialDataIn = serialPort.ReadExisting();
this.Invoke(new EventHandler(saveData));
}

public void saveData(object sender, EventArgs e)
{
string trimmedMsg = serialDataIn;
richTextBox.Text += trimmedMsg;


}


private void richTextBox_TextChanged(object sender, EventArgs e)
{
richTextBox.SelectionStart = richTextBox.Text.Length;
richTextBox.ScrollToCaret();
}

private async void button_sendMsg_Click(object sender, EventArgs e)
{
button_sendMsg.Enabled = false;
await Task.Run(() => send(textBox_message.Text));
button_sendMsg.Enabled = true;

//WAIT FOR RESPONSE BEFORE ALLOWING THE USER TO SEND ANOTHER MESSAGE
}

private async void button_loopMsg_Click(object sender, EventArgs e)
{
button_loopMsg.Enabled = false;
for (int i = 0; i < 10; i++)
{
await Task.Run(() => send(textBox_message.Text));

//WAIT FOR RESPONSE BEFORE CONTINUING THE LOOP
}
button_loopMsg.Enabled = true;
}

private async Task send(String message)
{
serialDataIn = "";
serialPort.Write(message);

while (!serialDataIn.Contains("*"))
{

//PROCESS ANSWERS HERE
serialDataIn = serialPort.ReadExisting();
if (serialDataIn.Contains("*"))
{
this.Invoke(new EventHandler(saveData));
}

}

}

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{

if (serialPort.IsOpen)
{
try
{
serialPort.Close();
}
catch (Exception error)
{
MessageBox.Show(error.Message);
}
}
}
}

}

I have the async method send data, and the two buttons are async as well. When I press them I'm just waiting for the task to complete before another input is allowed. I think this should be a good starting point for other projects as well. UI stays responsive, messages don't get queued up. The richTextBox on the UI get`s updated via Invoke so messages are displayed as soon as they arrive.

Here is the test code for an arduino:

#define println Serial.println

char serialIn;
String appendSerialData;

void setup()
{
Serial.begin(9600);
}

void loop()
{
appendSerialData = "";
while (Serial.available() > 0)
{
serialIn = Serial.read();
appendSerialData += serialIn;
}

/* asterisk functions as message identifier */
delay(1000);

if (appendSerialData != "") println(appendSerialData + " *");

for (int i = 0; i < 5; i ++)
{
println(i);
}
delay(100);

}

If there are any improvements I can make to this I`m happy to hear about it.

How to synchronize SerialPort operations?

I don't know the whole situation, but it seems to me you can just use a simple lock to serialize your write followed by read, like this:

static class SerialCommunication
{
static SerialPort serialPort;
static string endOfString = "" + char.MinValue;
static readonly object _commandLock = new object();

public static string SendCommand(string text) {
lock (_commandLock) {
SerialWrite(text);
return SerialRead();
}
}

private static string SerialRead() {
try {
return serialPort.ReadTo(endOfString);
}
catch (TimeoutException) {
throw new Exception(Properties.Resources.serial_read_timeout);
}
}

private static void SerialWrite(string text) {
try {
serialPort.Write(text);
}
catch (TimeoutException) {
throw new Exception(Properties.Resources.serial_write_timeout);
}
}
}


Related Topics



Leave a reply



Submit