Main Site Documentation

Serial port exception


#1

I have a small problem re-initialising the comm port after an exception has occurred. I need to set up a try / catch when I read the comm port and try and re-boot the port if possible.

Once transmission is synchronised it runs forever, and its only intermittent that the panda barfs, but I must have a constant connection. This is my receive code.


private static void UART_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
         // read the data
         
        read_count = UART.Read(rx_data, 0, UART.BytesToRead);
        crc = (byte)((int)rx_data[0] + (int)rx_data[1] % 255);
        UART.Write(tx_data, 0, tx_data.Length);
    }

Like I said I need to catch the exception after the read_count barfs.

Please help… Ian

Oh yes I forgot… If I reboot the panda it goes back into sync…


#2

Do you know what the exception is caused by?

I know it may have nothing to do with anything, but when I was playing with the ROV Control project, I would get an exception because I had a leak in memory. I ended up putting a small sleep in the start of the event and for some reason that fixed the leak and the garbage collector cleaned up properly. I can run the thing for days now?


private static void UART_DataReceived(object sender, SerialDataReceivedEventArgs e)//Received Event
        {
            Thread.Sleep(5);//for some reason before adding this had memory leak that would eventually freeze Panda
            byte[] rx_data = new byte[16];//set up variable for "inbound buffer"
            UART.Read(rx_data, 0, rx_data.Length);//read serial port
            Debug.Print(new String(Encoding.UTF8.GetChars(rx_data)));//Print to Debug screen
            
            ParseData(rx_data);//send inbound buffer array to ParseData Method
         }

I know it’s not your try/catch, but maybe you won’t get the exception???

Mike in MN

*** added name :slight_smile:


#3

Cheers Mike… I’ve struggled all day with this…I’ve put a try / catch in the function and the exception has gone… but that wasn’t the problem…Oh no… "bluddy windows… " I have a full 3d model of a crane I am controlling via xbee from a panda… I created a Visual basic interface to read in the value’s for debugging purposes but the serial api is really hard to control (why use the serial api I hear you say!!), because I use Blitz basic for all my 3d world / modelling simulation and Blitz doesn’t have native serial comm port availability…hence the windows serial comm api… I have found out how to purge the comm port buffers and that helped alot, but it runs out of sync if started incorrectly… I have packets and crc in place and there is no fault atall using MScomm control only the api…

At least its working good enough to show… Wednesday next week… starting to panic…

Cheers anyway… Ian

I’ll also put the sleep in… good call.


#4

The sleep is working for mike because his data is in 16 byte packets. The data event occurs before there are 16 bytes in the internal buffer. The sleep is allowing the buffer to fill or staying in the handler until 16bytes are available.

Using a sleep in an event handler is not a best practice.

You should have a static buffer of 16 bytes, and fill it up with multiple data ready events, and then process it.

While the sleep my seem to fix a problem, it may cause problems at a latter point which will be difficult to diagnose.


#5

@ Mike

So how would one set something like that up?



static byte[] rx_data = new byte[16];//set up variable for "inbound buffer"

private static void UART_DataReceived(object sender, SerialDataReceivedEventArgs e)//Received Event
        {
            UART.Read(rx_data, 0, rx_data.Length);//read serial port
            Debug.Print(new String(Encoding.UTF8.GetChars(rx_data)));//Print to Debug screen
 
            ParseData(rx_data);//send inbound buffer array to ParseData Method
         }



Would declaring it “static” in the Public Class like you would any variable work correctly?

Wouldn’t static screw up the garbage collector, or will it simply be overwritten everytime?

The full code for this project is under my ROV Control software … http://www.microframeworkprojects.com/index.php?title=ROV

It would make sense, it was driving me crazy…lol

Initially I figured defining a byte array of 16, would keep the Panda in my case from reading partial data, so standardizing the length I figured it would just wait until it filled up, but as you can see that presented problems.

Mike in MN


#6

Hi cncmike. Filling buffers with partial reads is key in network and serial readers. Always expect < what you asked for in Read - always. Zero also needs to handled. Should never get more then what you asked for. Sleep is a “hope and pray” strategy and should never be used for this task. You need to read, count, handle, and continue. Normally, this is done in a loop, but using an event like this takes the place of the loop. Below is best effort with a brain compile. Change to static as needed. Note: static vars makes no diff to GC.

private byte[] buf = new byte[16];
        private int received = 0;
        private void MyEvent(object source, SerialDataReceivedEventArgs e)
        {
            int toRead = buf.Length - received;
            int read = sPort.Read(buf, received, toRead);
            received += read;
            Debug.Assert(received <= buf.Length, "What?");
            if (read == 0)
            {
                // Handle shutdown, error or partial msg.
                return;
            }
            if (received < buf.Length)
                return; // Keep reading.
            
            received = 0;
            HandleMessage(buf);
        }

        private void HandleMessage(byte[] msg)
        {}

#7

I tried both things…

First put the received buffer as static declared outside.

Next I Williams implementation.


private static byte[] rx_data = new byte[16];
        private static int received = 0;
        private static void UART_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            int toRead = rx_data.Length - received;
            int read = UART.Read(rx_data, received, toRead);
            received += read;
            Debug.Assert(received <= rx_data.Length, "What?");
            if (read == 0)
            {
                // Handle shutdown, error or partial msg.
                return;
            }
            if (received < rx_data.Length)
                return; // Keep reading.

            received = 0;
            //HandleMessage(rx_data);
            ParseData(rx_data);//send inbound buffer array to ParseData Method
        }

Both I get a growing Binary_Blob_Head in the GC??



Type 1E (BINARY_BLOB_HEAD    ):   7572 bytes

Type 1E (BINARY_BLOB_HEAD    ):  18792 bytes

Type 1E (BINARY_BLOB_HEAD    ):  26112 bytes

Type 1E (BINARY_BLOB_HEAD    ):  31272 bytes

Type 1E (BINARY_BLOB_HEAD    ):  35052 bytes

Type 1E (BINARY_BLOB_HEAD    ):  37392 bytes

etc. until memory runs out. I put that little sleep back in there, works forever. Even set up with either way, my original way, making just the incoming buffer static, or Williams method.

For some reason that Sleep does something here. Like I stated before, I am sure it’s just covering up the problem.

But without the sleep, that Blob grows exponentially, with the sleep, it stays at 252 bytes every single time the GC runs. My bytes available stays the same number everytime the GC runs also with the sleep.

I don’t know.

Mike in MN


#8

If you take out the sleep and the parse data do you still have the problem?


#9

You are nit reading all data uart got. I suggest a thread to read uart instead of event


#10

I think your right Gus.

The reason for the 16 length was because the event fires and the whole command isn’t received. I figured if I set a standard length for the read, that I would get the full command.

Well that would mean that there is more data on the BytesToRead because data is still coming in and the event is only triggering probably not as often as data is being received.

I will try to re-structure the Read, probably in a different thread like Gus suggests and see how it goes.

Kinda of a noob situation, but I will work through it…:slight_smile:

Thanks,

Mike in MN


#11

I have not seen that binary blob head yet. What is that? I agree with gus. Reading on another thread should be good. I have used both methods in FezTerm and have not seen this issue yet. Could this be coming from Parsexx method?


#12

@ Gus… Just to clarify… If I create a serial receive buffer of 3 bytes then wait for the interrupt! Does the interrupt fire every character read or when the receive buffer is full?

Because when 3 characters are read I complete a crc check and quickly reply with 6 characters (in the event handeller) is that too much… I’m using 9600 baud and transmitting about 20 times a second…

Cheers Ian


#13

The interrupt fires once on receive so if you get 100 bytes but you only read 10 then there is 90 left in there that you didn’t read and you will not get an even for those bytes


#14

Thanks for clearing that up… Its how I imagined, the same as the windows api… Can I re-wriite my code to have a single byte being received and process the packet myself?

When the code runs out of sync, I can’t seem to knock it back into sync… On the pic I read every byte in an interrupt and test the start and stop characters to identify the packets received… and make sure all is in sync with each other…

Cheers Ian