Main Site Documentation

Serial ports stop receiving data


#1

I have a problem using serial ports. I have a Gadgeteer project on a Raptor board with three serial ports. For each serial port, I started a sender thread that sends data to a device every 250 milliseconds in a endless loop, and waits for a reply message from the device to be placed in a byte Queue. I started a second receiver thread that polls the serial port for incoming data and place the data bytes received on the same byte Queue. I use a lock for synchronization of the Queue access by the two threads.

The problem is that after working fine for about four hours, all three serial ports stop receiving data, and do not recover until my code re-boots the board.

I put a RS232 serial line analyzer device between the Raptor board and the device to monitor the data flow. I see that when the failure occurs, the Raptor board is transmitting the message, and the device is sending a reply, but my code never gets the data, that is, Port.Read function never returns with new data.

The core of the send function thread is this:



lock (RxDataQueue.SyncRoot)
{
       //thread-safe initialize the Queue of data received from the PLC reader
       RxDataQueue.Clear();
       RxDataEvent.Reset();
}

RS232PLC.Port.Write(sendData);
RS232PLC.Port.Flush();
rv = RxDataEvent.WaitOne(SmartTruckData.SerialPortTimeout, false);

The core of the receive function thread is this:



  /// <summary>
        /// Received data polling thread for PLC serial port
        /// </summary>
        void RS232DataReader()
        {
            try
            {
                while (true)
                {
                    //wait for RS232 data
                    if ((RS232Count = RS232PLC.Port.Read(RS232Data, 0, MaxRxDataQueueSize)) > 0)
                    {
                        //Put bytes received into a Queue, prevent the Queue size from expanding forever
                        lock (RxDataQueue.SyncRoot)
                        {
                            if (RxDataQueue.Count < MaxRxDataQueueSize)
                            {
                                for (int i = 0; i < RS232Count; i++)
                                {
                                    if (RxDataQueue.Count < MaxRxDataQueueSize)
                                    {
                                        RxDataQueue.Enqueue(RS232Data[i]);
                                    }
                                }
                            }
                            RxDataEvent.Set();
                        }
                    }
                }
            }
            catch (Exception ex1)
            {
                KioskUtilities.LogException(code + " RS232DataReader() exception - ", ex1);
            }
        }




#2

Perhaps try rewriting RS232DataReader() to use a WaitHandle and/or use event handling, instead of looped polling via a While() loop?

Rapid While loops without some sort of waiting mechanism are resource hogs, and I’ve noticed boards acting funny when I do this. If you must have an endless While(), I recommend adding a small Thread.Sleep() if you can tolerate that.


#3

The function RS232PLC.Port.Read() blocks and does not return until data is received. This is not exactly polling, I think. My thread is not using CPU time until the serial port receives data, then the function returns.

Another problem is that I am sending HTTP messages out and ICMP Ping messages out on the Ethernet LAN every few seconds, and these functions throw Socket exceptions after a few hours of working ok. Usually the serial port problem happens at the same time as the network exceptions. Is it possible that the Ethernet exceptions are causing the serial ports to go to sleep?


#4

irrespective of the interactions, I’d be looking to implement a serial “reply” lost/timeout scenario. What happens when a cable goes faulty ? I don’t think waiting for a (never to arrive) response will be sufficiently robust.


#5

Thanks, I do wait for a reply with a timeout, by using


RxDataEvent.WaitOne(SmartTruckData.SerialPortTimeout, false);

When .WaitOne returns with the timeout code, I send the message again. I did not show all of the code in the sending thread. The problem is, when the fault condition occurs after a few hours of working ok, no matter how many times I re-transmit the same message, I never get a reply again until I re-boot.


#6


Will this read above  lock until the entire buffer is filled with MaxRxDataQueueSize characters?

I prefer to use the DataReceived event and then check to see how many characters are available to read.

#7

As Mike said, I also recommend using the DataReceived event. My G400 commercial application reads 2 concurrent high-throughput serial streams with this approach, and it tends to run at 8 hours at a stretch (i.e., a whole workday) without a single hiccup. Perhaps you could try this and see if your problem goes away.