What is preventing my event handler method from completing?

71 Views Asked by At

I'm using a SerialPort, WPF for user interface, a 'ui' object to handle application logic, and a wrapper around SerialPort.

The method in question is called when the SerialPort.DataReceived event is fired. It begins to run, then after reading the data, just seems to exit, even though it has tons more to do.

It doesn't seem to be throwing any exceptions, it doesn't act like it's stuck in the loop (reading synchronously should time out + I'd be getting tons of "I READ A THING"), and I'm stumped. Almost all of the GiveFeedback calls are results of my trying to debug what's going on, as I'm unable to test on the machine I'm writing this on.

The 'ui' symbol refers to an object that fires an event when its GiveFeedback(string) is called, ultimately updating the contents of a textbox by calling Dispatcher.BeginInvoke(stuff).

Here's the code in its entirety:


public void DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    try
    {
        ui.GiveFeedback("DataReceived... Begin");
        List<byte> bytes = new List<byte>();
        int r = comm.comPort.ReadByte();
        while ( r != -1 )
        {
            bytes.Add((byte) r);
            try
            {
                r = comm.comPort.ReadByte();
            }
            catch(Exception ioe)
            {
                r = -1;
                ui.GiveFeedback(ioe.Message);
            }
            ui.GiveFeedback("read a byte...");
            ui.GiveFeedback("read : '" + System.Text.Encoding.ASCII.GetString(bytes.ToArray()) + "'");
        }
        //It NEVER reaches this line.
        //It NEVER throws an exception of any kind.
        throw new ApplicationException("I threw myself");
        i.GiveFeedback("done read : '" + System.Text.Encoding.ASCII.GetString(bytes.ToArray()) + "'");

        string msg = BitConverter.ToString(bytes.ToArray()).Replace("-", " ");

        string submsg;
        if ( msg.Length > 5 )
            submsg = msg.Substring(0, 5);
        else
        {
            submsg = msg.Substring(0, 2);
        }
        ui.GiveFeedback("msg: " + msg);
        ui.GiveFeedback("submsg: " + submsg);

        switch ( submsg )
        {
            case "10":
                ui.GiveFeedback("'Incoming -- VMC: Reset - 10' -- CommInterface");
                ACK();
                break;

            case "00":
                //DisplayData(MessageType.Incoming, " VMC: ACK - 00\n");
                ui.GiveFeedback("'Incoming -- VMC: ACK - 00' -- CommInterface");
                break;

            case "12":
                ui.GiveFeedback("'Incoming -- VMC: Poll - 12' -- CommInterface");
                switch ( ui.Stage )
                {
                    case Stages.SessionSelect:
                        BeginSession();
                        Poll();
                        break;
                        default:
                            ACK();
                            break;
                }
                break;

            case "14 01":
                //DisplayData(MessageType.Incoming, " VMC: Enable Reader - 14 01\n");
                ui.GiveFeedback("'Incoming -- VMC: Enable Reader - 14 01' -- CommInterface");
                ACK();
                break;

            case "14 00":
                //DisplayData(MessageType.Incoming, " VMC: Disable Reader - 14 00\n");
                ui.GiveFeedback("'Incoming -- VMC: Disable Reader - 14 00' -- CommInterface");
                ACK();
                break;

            case "11 00":
                ui.GiveFeedback("'Incoming -- VMC: Setup Config - 11 00' -- CommInterface");
                ConfigurationDataLevel01();
                break;

            case "11 01":
                ui.GiveFeedback("'Incoming -- VMC: Setup Max Min Price - 00' -- CommInterface");
                SetupMaxMinPrices();
                break;

            case "13 00":
                //DisplayData(MessageType.Incoming, " VMC: Vend Request - 13 00\n");
                ui.GiveFeedback("'Incoming -- VMC: Vend Request - 13 00' -- CommInterface");
                if ( ui.Stage == Stages.SessionSelect )
                {
                    ui.NextStage();
                    ApproveVend();
                }
                else
                    DenyVend();
                break;

            case "13 02":
                //DisplayData(MessageType.Incoming, " VMC: Vend Success - 13 02\n");
                ui.GiveFeedback("'Incoming -- VMC: VendSuccess - 13 02' -- CommInterface");
                ui.NextStage();
                ACK();
                break;

            case "13 05":
                //DisplayData(MessageType.Incoming, " VMC: Cash Sale - 13 05\n");
                ui.GiveFeedback("'Incoming -- VMC: Cash Sale - 13 05' -- CommInterface");
                ACK();
                break;

            case "13 04":
                //DisplayData(MessageType.Incoming, " VMC: Session Complete - 13 04\n");
                ui.GiveFeedback("'Incoming -- VMC: Session Complete - 13 04' -- CommInterface");
                ACK();
                break;

            case "17 00":
                //DisplayData(MessageType.Incoming, " VMC: Expansion Command - 17 00\n");
                ui.GiveFeedback("'Incoming -- VMC: Expansion Command - 17 00' -- CommInterface");
                break;

            default:
                //DisplayData(MessageType.Incoming, "unknown\n");
                ui.GiveFeedback("'Incoming -- VMC: Unknown - ?? ??' -- CommInterface");
                ACK();
                break;
        }
        ui.GiveFeedback("DataReceived... End");
    }
    catch(Exception ex)
    {
        ui.GiveFeedback("Exception Thrown!");
        ui.GiveFeedback(ex.Message);
        ex = ex.InnerException;
        while (ex != null)
        {
            ui.GiveFeedback(ex.Message);
            ex = ex.InnerException;
        }
    }
}

I don't know what's happening, and I cannot find any resources that would help me. I've tried running it without any try/catches, to see if it was throwing something weird, I've tried running it with specific exception catches, I've tried everything I can think of and know to do.

Why is it not running all the way through, and how do I fix it? Even if you have an idea that would help towards debugging this, I would LOVE to hear it! Please, stackoverflow, you're my only hope!

1

There are 1 best solutions below

1
On BEST ANSWER

There are a number of possibilities here...

First, the SerialDataReceivedEvent is fired when data is placed in the serial buffer. This does not mean an entire message is available, just that the serial port object has buffered bytes from the underlying stream. You are then using a while loop to read bytes until you get a -1.

The ReadByte method says that it returns -1 if the end of the stream has been read. This needs to be carefully deciphered since the end of the stream is really the Eof character, not necessarily that there isn't any more data to be received.

Aside from that, you are catching the exception, I'm assuming so that you can tell when the read has timed out. If you set a really, really big timeout, or leave it at the default SerialPort.InfiniteTimeout, then you'll never throw this exception.

Lastly, the event is raised when data is read into the buffer, and this isn't to say that the event can't be raised more than once. So for example it may raise the event when you receive 10 bytes, and while you are looping through data it may raise it again, creating another instance of your handler which is then fighting each other for data.

I would use the event only to signal another thread to read data. If the other thread is already reading it, then it won't do anything. The thread should suspend when its out of work to do. You should also be checking the SerialPort.BytesToRead property for determining if there is more data, see https://msdn.microsoft.com/en-us/library/system.io.ports.serialport.bytestoread(v=vs.110).aspx I'm also not sure why you are looping through byte-by-byte when you can just call SerialPort.ReadExisting to get everything that is available in one call...?