Reception problem on serial port

Hello guys,

I have a problem with my FEZ Cobra board. I’m trying to use the serial port in communication but it doesn’t work.
I send a frame and a another system respond a new frame a 6 bytes. But the board don’t read all time the same thing. Some times it read 1, 2, 3 or 4 bytes, sometimes 6. But not allways 6 bytes. I’m sure of the respond frame size (i see it on an oscilloscope) but it seems that the board loose some bytes.

About my soft.
First I used a pulling ont the SerialPort.BytesToRead parameter. And after I used the DataReceived event, and the resulst is the same in the 2 soft.

So I would like to know if someone ever had a problem like mine, or if someone has a code that works that I could try, or if there is some spécifications to follow with the SerialPort on the FEZ Cobra ?

Thanks for your help.
Sylvain.

PS : I would put my code after, but now it is so much draft with many comments.

How are the systems connected? Picture? What is the code you are using?

BytesToRead is the wrong way to figure out if you have got all your data. It’s like the postman who pops all your mail into the letterbox individually, and you counting what has come in while he’s potentially still outside with more envelopes in his hand starting to feed them in.

There are some good examples in other forum posts here about how to make sure you get all the data. A simple approach is to buffer the incoming data and add to the buffer each time you get a datarecieved event (reading the full contents of the serial port at that time, using BytesToRead). Assuming you send a lot of data over time, you can just read it and look for a termination character/sequence and act on that.

Hello, thanks for your answer.

Here is the soft I’m using :


        public static void Thread_Communication()
        {
            byte[] Messages_From_SPV;
            byte[] Messages_To_SPV;
            byte[] Tab_Temp;

            /***********      INITIALISATION DE LA COMMUNICATION SERIE       ***********/
            SerialPort UART = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
            UART.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
            UART.Open();


            // First, make sure we actually have a network interface to work with!19.
            if (Microsoft.SPOT.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces().Length < 1)
            {
                Debug.Print("No Active network interfaces. Bombing out.");
                Thread.CurrentThread.Abort();
            }

            // OK, retrieve the network interface
            Microsoft.SPOT.Net.NetworkInformation.NetworkInterface NI = Microsoft.SPOT.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces()[0];

            // Set the StaticIP
            NI.EnableStaticIP("192.168.1.1", "255.255.255.0", "192.169.1.1");

            // Create the socket
            Socket listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            
            // Bind the listening socket to the port
            IPAddress hostIP = IPAddress.Parse(NI.IPAddress);
            IPEndPoint ep = new IPEndPoint(hostIP, 3000);
            listenSocket.Bind(ep);
            
            // Start listening
            listenSocket.Listen(1);

            // Main thread loop
            while (true)
            {
                try
                {
                    Socket newSock = listenSocket.Accept();
                    //// Vidage du buffer de liaison série ////
                    if (UART.BytesToRead != 0)
                    {
                        Messages_To_SPV = new byte[UART.BytesToRead];               // On crée un buffer pour sauvegarder les octets
                        UART.Read(Messages_To_SPV, 0, Messages_To_SPV.Length);      // On lis les octets
                    }
                    if (newSock.Available > 0)
                    {
                        Messages_From_SPV = new byte[newSock.Available];
                        newSock.Receive(Messages_From_SPV, Messages_From_SPV.Length, 0);
                        UART.Write(Messages_From_SPV, 0, Messages_From_SPV.Length);         // Transfert des données sur la liaison série pour la CN
                        ushort tempo = 0;
                    }
                    newSock.Close();
                }
                catch (Exception e)
                {
                    Debug.Print(e.Message);
                }
            }
       }

	static void DataReceivedHandler(object sender, SerialDataReceivedEventArgs args)
        {
            SerialPort sp = (SerialPort)sender;
            byte[] tab = new byte[sp.BytesToRead];
            sp.Read(tab, 0, tab.Length);
        }

The purpose of my board is to convert the Ethernet order comming from a PC in RS232 to a system. And to convert the response from the system in RS232 to the PC in Ethernet.
For that :
[ulist]
I first configure the 2 comm (Ethernet and RS232).
I configure the event of the RS232 reception.
I wait for an Ethernet connection.
I get the Ethernet received frame.
I send the frame thru the RS232.
I wait for reception in the RS232 event.
[/ulist]

The last thing doesn’t work. Sometimes there is event, but not enought bytes casn be read. Sometimes there no event (while I see bytes on the oscilloscope). Sometimes I have event but when I read the sp.BytesToRead there is 0 bytes to read ???. So I don’t uderstand what happens.

First, you should register for the data received event after you open the uart.

Why are you reading the uart in a loop and using a receive event?

I registered for the data received event before the open of the UART like I found it in the Microsoft Msdn example : [url]Microsoft Learn: Build skills that open doors in your career.
But first I registered after and the results was the same :(.

For the loop, its not final code. The loop i just here for test. I generate an frame send and I block the code by a button and look to the RS232 reception.

And the first read of the UART i juste be sure that there is no bytes attending in the UART buffer, before the sent.

Have you tried doing a simple TX-RX loop back test on the Fez (leaving the other device out of the picture) ? also tried com2-4?

Is the other serial devices TTL (5.0Vdc) serial, (3.3Vdc TLL) or are you using an interposing MAX232 chip?

I first tested just the EMX and a PC with hyperterminal. And at this time I was able to see the bytes comming from the PC. But hyperterminal is not good to simulate a real communication (time between 2 bytes, number of bytes, etc).

I didn’t try yet with an another port COM. I was thinking the problem was only software.

And the other device is in RS232. My EMX is connected to a MAX3232.

[quote]I was thinking the problem was only software.
[/quote]
Well I think I agree !

BytesToRead is the wrong way to think about this problem. It’s worse in your code sample because you’re also using the event handler. You need to have ONE way to get data out of the serial port. You currently have two. Pick one, work with that. Either CAN be made to work for what you want.

There’s a good discussion that William had in this thread: [url]http://www.tinyclr.com/forum/2/2208/#/1/msg22664[/url] that talks about some options and extensions. The key is that you are looking for a terminator so the ReadTo method he talks about might be relevant.

When I look at your code my head hurts :slight_smile: Where do you think the data is going when it’s read in your handler? It’s going nowhere. You have really bad scoping of strings that will churn the GC a lot.

Why don’t you start simple. I personally think that using a terminal program from a PC is a perfectly acceptable way to do data simulation. Your code needs to handle the fact that you issue the command and pause before issuing the terminator. Your code needs to handle the fact that the datarecievedevent may not get the terminator in the same pass as the first character in the command. The first character you get in any pass through the handler may not be the first character in your command.

I’d suggest you need to think about a circular buffer - read up on them. Use the CBuf as the place your handler dumps the data for pickup in your main code - it needs to have global scope.

Yes my code is maybe not really clear, because I was testing further methods. First pulling, and because it didn’t work good, I tried the event way.

Ok, thanks I will read.

Yes I know that the data went nowhere. But I was testing in debug mode, so I didn’t have to finish my code. I just wanted to see if a 6 bytes frame will well “trigger” (?) 6 events. That It was what I thought it will happen.

As I said I started simple, by sending and getting bytes thru the hyperterminal. But at this time I was using a BytesToRead pulling method. I had many interrogations about the Ethernet and RS232 protocole of the 2 other systems (no documents to describe it, I just had to find myself how they work).

I’m not sur to understand what you want to say, I’m not english :(.

I also thought about this solution, but at the first time I thought this doesn’t give me anything interresting. Because the communication is a question/answer. The system that send thru the RS232 to me, never talk alone. It allways talk in response to a question that I sent.

Yes my code is maybe not really clear, because I was testing further methods. First pulling, and because it didn’t work good, I tried the event way.

Ok, thanks I will read.

Yes I know that the data went nowhere. But I was testing in debug mode, so I didn’t have to finish my code. I just wanted to see if a 6 bytes frame will well “trigger” (?) 6 events. That It was what I thought it will happen.

As I said I started simple, by sending and getting bytes thru the hyperterminal. But at this time I was using a BytesToRead pulling method. I had many interrogations about the Ethernet and RS232 protocole of the 2 other systems (no documents to describe it, I just had to find myself how they work).

I’m not sur to understand what you want to say, I’m not english :(.

I also thought about this solution, but at the first time I thought this doesn’t give me anything interresting. Because the communication is a question/answer. The system that send thru the RS232 to me, never talk alone. It allways talk in response to a question that I sent.

This really now comes down to your algorithm. Comms over both ethernet and serial are subject to delays outside your control, and you need to handle that appropriately depending on how you want the app to react.

I think you need to expand on how you want the app to work, what you can control and what you can’t - for example are you able to guarantee that a http request and a serial request won’t overlap do you only ever do one-request at a time? Those things will help you develop a successful algorithm for your app.

So to give you more explaination of my system I put a image with this post.

In the communication the master is the PC. He send a question to the Electronic system in Ethernet. The problem is that the Electronic system has an RS232 communication. So I put between the two my EMX board to convert the Ethernet question into an RS232 question. And the EMX send it to the Electronic System and wait for the answer. When the answer arrive the EMX convert it into Ethernet send it to the computer.

So my first algorithm was this one :

[ulist]Initialisation of the RS232 communication (speed, stopbit, etc).
Initialisation of the Ethernet communication (type, IP adress, etc).
Open socket to listen the Ethernet connection.
Wait for Ethernet connection ( Accept() )
Get of the frame that has been sent into the Ethernet.
Send of the frame in RS232.
Wait for the RS232 answer.
Get the RS232 answer.
Send the answer in Ethernet.
Close Ethernet socket.
Get back to “Wait for Ethernet connection”.[/ulist]

The computer has a blocking timeout of 3secs after the send of one frame. So it can only send one frame at a time.

My problem is I can’t know the size of the RS232 answer frame.
First I wanted to use a pulling method (and not an event method) because didn’t find a way to close the socket if I use a event method.
For example :
[ulist]I receive the Ethernet question. (So the socket is created)
I sent it to the RS232.
I close the socket.[/ulist]
In the event.
[ulist]When I receive an RS232 byte.
I create a new socket and a new connection to the computer.
I send the byte.
I close the socket.[/ulist]
I can’t be sure that this method can work. I think that the computer need the answer in the same socket that the question, but I’m not sure (it’s my first work with the Ethernet protocole and I’m not realy a expert :slight_smile: ).

OK a couple of quick clarifying questions ?

The 3 seconds, does that mean the PC will only request once and then wait at least 3 secs before asking again?

Do you know all the commands that the PC requests will contain? Do you know what the responses from the serial device for each of those requests are structured like? And do you have an idea what the bounds of the response is - up to X bytes, and does it always have a terminating character? How will you know when the end of the RS232 data comes in?

About the timeout. Actually the PC send the request. Wait 3 secs for the answer. And if no answer arrived it put an error on the screen for the user. But it didn’t try a new send.

About the commands I don’t know all but most of them. They all have the same structures.
[ulist]Command
Destination (always 0 in my application)
Nb a parameters
Tab parameters
CheckSum[/ulist]
For the answer I don’t know all either, and I don’t know all answer for all request. I know the structure of the answer. There is no end byte but there a byte that is like a frame-size byte.
[ulist]Command accepted or not
Nb of the error (if not accepted else 0)
System state
System status
Nb a parameters
Tab parameters[/ulist]

At the beginning I was reading the “Nb of parameters” byte to wait for the good number of RS232 bytes. But I thought if I had a transimission problem just on this byte, it can crash my soft. So I just would like to make read -> send soft without any interpretation of the frames.

[quote]How will you know when the end of the RS232 data comes in?
[/quote]
I don’t know, that’s the joke ;).

not having an easy “end of stream” means you can’t use a datarecieved event, you need to poll the port for data, and you need to have an acceptable timeout - if you don’t get a full sequence of data before that timeout you will have to abort the read sequence and return that back to the PC via your ethernet connection.

Do you have the serial device? Can you demonstrate the actual data that comes from it ? The data stream samples could be used to check that the algo used in the harvesting of the data is robust enough to handle the scenarios you get.

By the way this isn’t a university assignment we’re helping you do is it ? :slight_smile:

Given that nothing in your program logic overlaps and you have a very synchronous process, your simple ladder / state machine approach should work fine. You just need to control how and when you progress through the states.

Here’s an approach that might work to handle the serial data - note it’s untested.


{in main}
	int myserialtimeout = 2000;  //chosen to allow you time to 
            com1 = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
            com1.ReadTimeout = myserialtimeout;
//....


        public static string ReadSerialData(SerialPort port, int maxBufSize = 300)
        {
            if (maxBufSize <= 0) throw new ArgumentOutOfRangeException("maxBufSize");
            byte[] buf = new byte[maxBufSize];
            int curPos = 0;

            while (curPos < maxBufSize)  //simply loop until you hit the timeout on any read.
            {
                int read = port.Read(buf, curPos, 1);
                if (read == 0) break;  // at this point, the timeout has occurred and you have no new data so step out of the while loop
                curPos += read;
            }

// think about if you need to clear the remaining port data using port.Flush();

            // curPos will be zero if first read is zero.
            if (curPos == 0) return null;
            if (curPos == maxBufSize)
                throw new InvalidOperationException("Line size > maxBufSize.");
// here you can check validity of the data sequence - this is one of my examples - but you may just pass this string back and parse it out later
            if (buf[curPos] != 13)
            {
                port.Flush();
                return null; // if no delim found, assume comms failure. drop the current data and move on
            }

//pass a string back
            char[] ca = Encoding.UTF8.GetChars(buf);
            return new string(ca);
        }

 

From your main app you can simply use:

response=ReadSerialData(com1, 100);

If response == null, then your data didn’t arrive and you should handle that. If it’s non-null then you need to parse it and validate that it is as expected, and then hand back to the ethernet response.

My suggestion would be to make sure you test each aspect of your app in independent modules - test that you can do ethernet incoming request handling and outgoing response; test that you can do outgoing serial requests and incoming serial response correctly - and only then try to link the two. You can “fake up” the data between the modules if needed, for instance you can simply change the “response” string instead of actually reading the value from the serial port and see how the ethernet handling works.

Hope that is a helpful suggestion.

Thanks for your answer. And sorry for my answer delay.

That’s exactly what I wanted to do first. Regards of your advise I think I gonna back in this way.

Yes I can have it but most of time it is used by someone else. But could spy the data comming from it to my EMX when I sent a frame. I saw the delay between the question and the anwser, I could saw that there is a checksum that is not the specification protocole, etc.

No it’s not. Is it a problem for you ? I fact I’m an software engineer but specialized in µC like PIC and C language. It’s my first work with a system like EMX, with C# and with .NET µFramework, so it’s why I have so much troubles.

I gonna test something like your example, I didn’t thought to play with the SerialCom timeout, it’s a good idea ;).

re doing your Uni assignments - no I really don’t have a problem unless you come along and say “here’s my problem, solve it for me” but you’re engaging with us to discuss and try things etc etc so its all good. There certainly are other areas on the interwebs where this is a bigger issue than here :slight_smile:

I reckon the timeout will be the key - good luck and good testing :smiley:

It’s done I tested your solution to manage my serial communication and it seems to work.

Honnestly the test is not complete because I cound’t test on the électronic equipment, I programmed a µC to simulate the electronic equipement thanks to the measures that I maid last week.

Tomorrow I will test (if I can :slight_smile: ) on the electric equipment.

I still have somes questions on the ethernet protocole, but I will wait, it’s just for my own knowledge :).