Trouble with RS232 module event handler

When I use a AutoResetEvent WaitOne() function and the RS232 module, the data received event handler for the RS232 module never gets called, it is blocked by WaitOne(). I am setting the AutoResetEvent signal inside the RS232 data received handler function. Here is my code:



using System;
using System.Collections;
using System.Text;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using GT = Gadgeteer;
using GTI = Gadgeteer.Interfaces;
using GTME = Gadgeteer.Modules.GHIElectronics;


        private GTME.RS232 rs232LCD;
        private AutoResetEvent LineSentEvent;
        private AutoResetEvent TimeoutEvent;



       //After sending a command to the LCD, the program must wait since the display
       //will not accept any other commands while executing the previous command. 
       //You will receive a NAK if Command is not in the list, Wrong number of command arguments, Invalid argument
        //if all is good, you will receive a ACK packet.
       private bool SendData(bool _WaitForACK, TimeSpan ts_time, int ms_time, params byte[] data)
        {
            bool retval = true;
            if (rs232LCD.serialPort.IsOpen)
            {
                LineSentEvent.Reset();
                TimeoutEvent.Reset();
                Debug.Print(DateTime.Now.ToString("HH:mm:ss.fff") + " Transmit: " + BytesToHexString(data));
                rs232LCD.serialPort.Write( data );
                if (_WaitForACK)
                {
                    retval = LineSentEvent.WaitOne(ms_time + 100, false);
                    if ( !retval )
                        Debug.Print(DateTime.Now.ToString("HH:mm:ss.fff") + " Transmit Error:  Timeout waiting for ACK from LCD" );
                }
                else
                {
                    timer.Interval = ts_time;
                    timer.Behavior = GT.Timer.BehaviorType.RunOnce;
                    timer.Start();
                    retval = TimeoutEvent.WaitOne(ms_time + 100, false);
                    if (!retval)
                        Debug.Print(DateTime.Now.ToString("HH:mm:ss.fff") + " Transmit Error:  Timeout waiting for timer tick event");
                }
                LineSentEvent.Reset();
                TimeoutEvent.Reset();
                if ( timer.IsRunning ) timer.Stop();
            }
            else
            {
                Debug.Print("rs232LCD serial port is not open");
                retval = false;
            }
            return retval;
        }

        /// <summary>
        /// This is the function that will be called when data is available on the serial port.
        /// This function will not be called again if the data isn't read in.
        /// </summary>
        /// <param name="sender">Object that sent called this function</param>
        /// <param name="data">serial data received</param>
        private void Display_DataReceived(GT.Interfaces.Serial sender, System.IO.Ports.SerialData data)
        {
            try
            {
                // Create a buffer that is the length of the data that is available
                // the BytesToRead variable tells us how many bytes are waiting in a buffer.
                byte[] readData = new byte[rs232LCD.serialPort.BytesToRead];
                // Now we read the data into the buffer we just created, starting at the first byte.
                rs232LCD.serialPort.Read(readData, 0, readData.Length);
                Debug.Print(DateTime.Now.ToString("HH:mm:ss.fff") +  " Receive: " + BytesToHexString(readData));
                OnDisplayEvent( new DisplayEventArgs( readData ));
                LineSentEvent.Set();
            }
            catch (Exception ex)
            {
                Debug.Print("KeyPad_DataReceived exception " + ex.Message);
            }
        }



if the send data method is called from a timer event then you have seized the event thread and the data received event is in the event queue.

there is only one thread for system events.

I had a very similar problem and had the same issue that Mike explained.
My solution is here: https://www.ghielectronics.com/community/codeshare/entry/748
I have rewritten it again recently and will post that in the next day or two as version 3.

I am using two rs232 modules. An rs232 module is connected to a keyboard and receives keyboard ASCII characters, and this rs232 module’s data received event handler calls the SendData function in my post here, which sends data to another rs232 module that sends the character to a LCD display, and calls LineSentEvent.WaitOne(), waiting for an event object to be signaled which never happens, because the data received event handler of the second rs232 module never gets called until the SendData function gives up waiting and returns. So have I seized the event thread with my SendData function in this case? How do I fix this?

Yes!

This situation calls for the use of threads.

The SendData logic can be in a separate thread. It waits on a AutoResetEvent that is set when the keyboard ReceivedData event fires. The SendData logic can then send the data, and then can wait on another AutoResetEvent.When you do this, the event thread will not be seized by the keyboard ReceivedData event fires.

Of course, you will need a way of passing data from the keyboard event to the thread. Do a search in the CodeShare section for “queue” lots of samples of ways of passing data between threads.

Thanks, Mike, very helpful. Is this single event thread limitation imposed by .NET MF or by GHI? If it is from the GHI design, could you put on your wish list a wish from me to add more event threads so multiple event could be raised at the same time by Gadgeteer modules?

The basic limitation is within MF.

It is generally good practice to minimize the time spent in an event handler, regardless of the version of .NET.

The only needs I see for multiple event handler threads involve priorities and preemption, which would increase the complexity and resource requirements for MF beyond it design goals.