Serial comms - using all the memory up

me again, ::slight_smile:
after much playing i have finally got the code to work however im not to happy with the solution i have come up with. it seems within the datareceived event if i slept the event for a small time then the code would work, i discovered this by accident to be honest, if i placed a break point at the start of the event which i was doing for testing and looking at byte counts in and out i discovered the code worked however without a breakpoint the event only ran the once and never retriggers. now im aware that by not having a time i will get partial message returned because the event get triggered multiple times, however if i try to implement any of the previous codes or try to and while loops inside the datareceived event things seem to go wrong. like i say i`m not to happy with my implementation but i dont see a way round it at the moment.



using System;
using System.Threading;
using System.IO.Ports;
using System.Text;

using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

using GHIElectronics.NETMF.FEZ;

namespace FEZ_Domino_Application2
{
    public class Program
    {
        static SerialPort uart = new SerialPort("COM1");
        static int Count = 0;

        public static void Main()
        {
            uart.Open();
            if (uart.IsOpen)
            {
                uart.DataReceived += new SerialDataReceivedEventHandler(Test_DataReceived);
            }

            byte[] TX_Data = Encoding.UTF8.GetBytes("$GPRMC,225446,A,4916.45,N,12311.12,W,000.5,054.7,191194,020.3,E*68"); // switched data out for testing //  0123456789

            while (true)
            {
                uart.Write(TX_Data, 0, TX_Data.Length);
                Thread.Sleep(1000);
            }
        }


        static void Test_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            Thread.Sleep(100);
            if (uart.BytesToRead > 0)
            {
                Count += 1;
                Debug.Print("Bytes to read before uart read: " + uart.BytesToRead.ToString()); 
                byte[] ByteBuffer = new byte[256];
                uart.Read(ByteBuffer, 0, uart.BytesToRead);
                string RX_Data = new string(System.Text.Encoding.UTF8.GetChars(ByteBuffer));
                Debug.Print(Count + ": Data: " + RX_Data);
                Debug.Print("Bytes to read after uart read: " + uart.BytesToRead.ToString());
                Debug.Print("************************************");
            }
        }



    }
}


Bytes to read before uart read: 66
1: Data: $GPRMC,225446,A,4916.45,N,12311.12,W,000.5,054.7,191194,020.3,E*68
Bytes to read after uart read: 0


Bytes to read before uart read: 66
2: Data: $GPRMC,225446,A,4916.45,N,12311.12,W,000.5,054.7,191194,020.3,E*68
Bytes to read after uart read: 0


Bytes to read before uart read: 66
3: Data: $GPRMC,225446,A,4916.45,N,12311.12,W,000.5,054.7,191194,020.3,E*68
Bytes to read after uart read: 0


Bytes to read before uart read: 66
4: Data: $GPRMC,225446,A,4916.45,N,12311.12,W,000.5,054.7,191194,020.3,E*68
Bytes to read after uart read: 0


Bytes to read before uart read: 66
5: Data: $GPRMC,225446,A,4916.45,N,12311.12,W,000.5,054.7,191194,020.3,E*68
Bytes to read after uart read: 0


The event fires on the first byte received. Now, if you read data, you will only read what was int eh buffer at that time, maybe 10 bytes. Now, when you add a delay, you are allowing more time for the data to come and fill the buffer.

It is not a bad idea to create a thread that keeps reading the data and processing them. Then your thread can sleep whenever it reads zero bytes. The wakeup event can be triggered from inside the serial receive event.

This is not the most efficient way of doing the job. Too much garbage collection, but it works, and for one message a second it should be fine. I tested it at 10 messages per second.

using System;
using System.Threading;
using System.IO.Ports;
using System.Text;

using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

using GHIElectronics.NETMF.FEZ;

namespace FEZ_Domino_Application2
{
    public class Program
    {
        static SerialPort uart = new SerialPort("COM1");

        public static void Main()
        {
            uart.Open();
            if (uart.IsOpen)
            {
                uart.DataReceived += new SerialDataReceivedEventHandler(Test_DataReceived);
            }

            byte[] TX_Data = Encoding.UTF8.GetBytes("$GPRMC,225446,A,4916.45,N,12311.12,W,000.5,054.7,191194,020.3,E*68"); // switched data out for testing //  0123456789

            while (true)
            {
                uart.Write(TX_Data, 0, TX_Data.Length);
                Thread.Sleep(1000);
            }
        }

        private static String message = String.Empty;
        static void Test_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            int bytesToRead = uart.BytesToRead;
            byte[] buffer = new byte[bytesToRead];
            uart.Read(buffer, 0, bytesToRead);

            message += new String(Encoding.UTF8.GetChars(buffer));

            if (((message.Length - 3) > 0) && (message[message.Length - 3] == (byte)'*'))
            {
                Debug.Print(message);
                message = String.Empty;
            }
        }
    }
}


[quote]The event fires on the first byte received. Now, if you read data, you will only read what was int eh buffer at that time, maybe 10 bytes. Now, when you add a delay, you are allowing more time for the data to come and fill the buffer.

It is not a bad idea to create a thread that keeps reading the data and processing them. Then your thread can sleep whenever it reads zero bytes. The wakeup event can be triggered from inside the serial receive event.[/quote]
It only fires on byte 1? How does it decide to fire again then, does it involve a byte count, a general timeout, or an idle timeout? I thought it was related to whether or not the UART handling thread had to release the cpu to other threads.

It doesn’t fire on a byte count but on a receieved data

First off a many large thanks to all that helped with this, plus extra big thanks to Mike for modding my old code and coming up with a viable solution.

ok so what did i learn from something i expected to take me half hour … DOH. well that the data received event doesnt wait till its got all the message you send, and its damn critical to declare a buffer length as a interger and then process the data rather than using the uart.bytestoread flag, as this will change every time you use it if more data arrives during processing, im guessing but someone might correct me but i think the uart.bytetoread is native so it will be updated each time it was read where as declaring a int will mean that value stayed constant throughout the event interation. Aslo i cant expect that the uart will receive the same amount of bytes for a static message every thime its triggered.

I took the liberty of blending mikes code with my old code to make the results easier to read and commented it out for others, although i know the code doesn`t do anything useful it has been really interesting and i hope this might help someone else out at a later date. thank for all your help once again :slight_smile:

Now i think i best get the domino to do something u :oseful



using System;
using System.Threading;
using System.IO.Ports;
using System.Text;

using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

using GHIElectronics.NETMF.FEZ;

namespace FEZ_Domino_Application2
{
    public class Program
    {
        static SerialPort uart = new SerialPort("COM1");
        static String RX_Data = String.Empty;
        static int Count = 0;

        public static void Main()
        {
            uart.Open();
            if (uart.IsOpen)
            {
                uart.DataReceived += new SerialDataReceivedEventHandler(Test_DataReceived);
            }

            byte[] TX_Data = Encoding.UTF8.GetBytes("$GPRMC,225446,A,4916.45,N,12311.12,W,000.5,054.7,191194,020.3,E*68");

            while (true)
            {
              uart.Write(TX_Data, 0, TX_Data.Length);
              Thread.Sleep(1000);
            }
        }


        static void Test_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            int BytesToRead = uart.BytesToRead; // define length of buffer
            byte[] ByteBuffer = new byte[BytesToRead]; // create buffer
            Count += 1; // increment intergartion counter
            uart.Read(ByteBuffer, 0, BytesToRead); // read uart to buffer
            RX_Data += new String(Encoding.UTF8.GetChars(ByteBuffer)); // create a new rxdata string and load it with buffer contents

            if (((RX_Data.Length - 3) > 0) && (RX_Data[RX_Data.Length - 3] == (byte)'*')) // decode rx data - ensure length is ok then check for * byte at end position - 3 bytes
            {
                Debug.Print(Count + ": Data: " + RX_Data); // print rxdata string
                Debug.Print("Bytes to read after uart read: " + uart.BytesToRead.ToString()); // prove uart is empty for test purposes
                Debug.Print("************************************"); // ease of read text
                RX_Data = String.Empty; // clear out rx data
            }
        }
    }

}





1: Data: $GPRMC,225446,A,4916.45,N,12311.12,W,000.5,054.7,191194,020.3,E*68
Bytes to read after uart read: 0


58: Data: $GPRMC,225446,A,4916.45,N,12311.12,W,000.5,054.7,191194,020.3,E*68
Bytes to read after uart read: 0


115: Data: $GPRMC,225446,A,4916.45,N,12311.12,W,000.5,054.7,191194,020.3,E*68
Bytes to read after uart read: 0


158: Data: $GPRMC,225446,A,4916.45,N,12311.12,W,000.5,054.7,191194,020.3,E*68
Bytes to read after uart read: 0


216: Data: $GPRMC,225446,A,4916.45,N,12311.12,W,000.5,054.7,191194,020.3,E*68
Bytes to read after uart read: 0


274: Data: $GPRMC,225446,A,4916.45,N,12311.12,W,000.5,054.7,191194,020.3,E*68
Bytes to read after uart read: 0


332: Data: $GPRMC,225446,A,4916.45,N,12311.12,W,000.5,054.7 :o :o,191194,020.3,E*68
Bytes to read after uart read: 0


Interesting. I’m glad you got it working the way you want it to.

I’ll have to look at this a little closer after I get my Panda. Not to solve any particular problem, but to satisfy my curiosity. Even with the way you currently handle the code, it appears the event fires 57 times between the first transmission and the second, and I didn’t expect that from what gus told us about how the event fires.

No matter what, queuing the data to be processed like you do with the RX_Data string should help iron out the curious points naturally.

Like I said, glad you got it to work. I’ll update if I find anything helpful once I have a device in hand.