1
votes

Life status of device connected via serial port.

Hello everyone.

How can I check if the device responds to the request? I'm googling this for couple days and tried lot of solutions also from SO, but nothing gave me results that I've expected. After lot of tries I'm in point described below. I think I'm very close but now I need little help, so thanks for every answer in advance.

The current situation

What am I doing right now is very simple. First of all I'm opening serial port serialPort.Open() at very beggining of app (data is receiving almost all the application running time).

As this is just an example in my form is only one label called labelStatus and labelStatus.Text = "Not connected"

Next I'm adding a timer and it's tick method, that contains execute of serialPort.Write(). Timer Interval is set to 100 if that matters.

private void timer_Tick(object sender, EventArgs e)
{
    if (serialPort.IsOpen)
    {
        serialPort.WriteLine("r"); //I'm sending "r" message and device send data back
    }
}

Next step is create DataReceived event like below (very simplified version, in my app received data is parsing to floats and storing in array, but it's just to show the problem)

private void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
    string someVariable = serialPort.ReadLine();
    labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Connected"));
    //If i received something that means the device is plugged in and connection is correct (still very simplified)
}

One last thing is create ErrorReceived method.

private void serialPort_ErrorReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
    labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Not connected"));
}

Untill now everything works brilliant. Sending data works. DataReceived event is executig each 100 miliseconds when data is send. My data is received properly with no problems. When I start application labelStatus text is "Not connected" (device cable is not plugged in). When I plugged in device labelStatus text changing to "Connected". But now when I plugged of cable ErrorReceived event is not executing and labelStatus text is still "Connected". So as I've asked before: How can I check is device still connected to computer? (Or maybe: how to execute ErrorReceived event, when data is not receiving?).

Note: Serial port ReadTimeout is set to 300 miliseconds.

What have I tried

I've tried lot of things but this one in my head seems to should work but doesn't.

I've modified DataReceived event and I've put serialPort.ReadLine() into try/catch block with TimeoutException where I've tried to manually execute ErrorReceived method like below

private void serialPort_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
    try
    {
        string someVariable = serialPort.ReadLine();
        labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Connected"));
        //If i received something that means the device is plugged in and connection is correct (still very simplified)
    }
    catch (TimeoutException)
    {
        serialPort_ErrorReceived(null, null);
    }
}

I was hoping that will work like I want.

BTW. Sorry for my English. It's not perfect, but I do my best. Cheers!

2
Are you using handshaking on the serial line? Maybe I'm not understanding correctly, but handshaking seems to be the obvious solution to what you are trying to achieve? Without it, Serial Comms is connectionless.Bryan

2 Answers

0
votes

Listen to the WM_DEVICECHANGE event that will be fired when a device is removed or inserted.

Here is an example of a implementation and some more information:

0
votes

This is solution in my case

Regarding to Martjin's answer i need to further explain my situation. First of all I want to say that I'm not installing any hardware into my computer, so in my opinion WM_DEVICECHANGE event was not what i need (but of course thanks for information, I've learned something new). Application is reading data from scale. Scale after plug into com port is not sending any data and actually there's no communication between it and computer at all. The only way to read data is to send request to scale, so I have to rely on that.

First try

The plan:

  • Add two static int fields (flags) checkOld and checkNew,
  • increment checkNew in DataReceived, check in timer Tick method
  • is checkOld is equal to checkNew. If true that means checkNew was not increment, and that means DataReceived was not executed.

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

    checkNew++;

    string someVariable = serialPort.ReadLine();
    labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Connected"));
    //If i received something that means the device is plugged in and connection is correct (still very simplified)
}

private void timer_Tick(object sender, EventArgs e)
{
    if (serialPort.IsOpen)
    {
        serialPort.WriteLine("r"); //I'm sending "r" message and device send data back
    }
    if (checkOld == checkNew)
    {
        labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Not connected"));
    }
}

`

The plan was good but when I've tested it result was not even good. What happened? Actually device status was blinking connected-not connected-connected-not connected etc. I've wrote some data to output and get answer. The timer was looping so fast that DataReceived event could not always increment checkNew value.

Final solution

Based on what I had at the moment I've decided to add some little changes. Instead of comparing two integers values try to collect couple last values ad check if all were the sem or not.

The plan:

  • Add three static fields: first six elements array of integers statusArray, second integer index with value equals to 6 (last element of array + 1), third integer checkNew,
  • increment checkNew in DataReceived event,
  • in timer Tick event fill array to index, decrement index value untill whole array is filled, and if index == 0 reset index value to 6,
  • and last check if last six values of checkNew, stored in statusArray are the same. If true that means DataReceived did not executed six times in a row, and now I can be sure that connection is lost.

` static int index = 6; static int checkNew = 0;

static int[] statusArray = {0,0,0,0,0,0};

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

    checkNew++;

    string someVariable = serialPort.ReadLine();
    labelStatus.Invoke((MethodInvoker)(() => labelStatus.Text = "Connected"));
    //If i received something that means the device is plugged in and connection is correct (still very simplified)
}

private void timer_Tick(object sender, EventArgs e)
{
    if (serialPort.IsOpen)
    {
        serialPort.WriteLine("r"); //I'm sending "r" message and device send data back
    }

    if (index == 0)
        index = 6;
    index--;

    int value = statusArray[index] = checkNew;
}

`