locked
Serial Port with C++/CLI - Disable EOF check / "ASCII character 26" break my reading buffer RRS feed

  • Question

  • Hello,

    i have a problem to read some bytes from my serialport.

    I set my ReceivedBytesThreshold to 3, then i sending 3 bytes to the port.

    look like this:

    first byte=dec "10";

    second byte=dec "26";

    third byte= dec "255";

    i can only receive the first byte, at the second DEC "26" break my function "this->serialPort1->Read(buffer_rx,0,3);"

    My Question, how i can change in visual studio 2008 c++/cli the input Mode to binary, like this old code:
     

    GetCommState(ComHandle, &CommDCB);

       CommDCB.BaudRate=BaudRate;
       CommDCB.Parity=NOPARITY;
       CommDCB.StopBits=ONESTOPBIT;
       CommDCB.ByteSize=8;

       CommDCB.fBinary=1;  //Binary Mode only <----I think thats the important point!!??
       CommDCB.fParity=0;

    I can not find this properties here: http://msdn.microsoft.com/en-us/library/system.io.ports.serialport_members%28v=vs.90%29.aspx

    Who can help me, to change the settings? Why are not therethis setting?->

    CommDCB.fBinary=1;

    have a nice day,

    Peter
    Friday, January 25, 2013 1:38 AM

Answers

  • "Please do not think that I am stupid. I program normally only hardware(big Cortex M3,M4 etc.)"

    I - in no way - regard you as stupid. I just recommend what I have used successfully at a 5 times higher speed than yours.

    SerialPort does not fire an event for every character received. It fires an event when there are bytes in the UART receiver FIFO, and this makes a tremendous difference. The interrupt latency of windows is approximately 1 ms, so at 921.6 kBit/s, you need a UART with at least a 128 bytes receiver FIFO like 16C950 or for example an Exar USB-serial converter with a 384 byte RX FIFO as I do. The standard PC UART 16C550 is not enough!

    Then you need to do the receiving in the most clever way, which cannot be overloaded and does not generate too many heavy TME (Thread Method Entry) objects.

    The way I do it - as you can see in the sample program - is just to let the handler for the DataReceived event wake a method on the UI thread by means of the standard delegate MethodInvoker and an Invoke call - not BeginInvoke! I do not transfer any data in a delegate as this would require a time consuming data copying! The UI method can then empty the receive buffer. When the job is done and the handler for the DataReceived event returns from the Invoke statement, it checks for any bytes received in the meantime (during Invoke) before returning. If there are any, it invokes the UI method again without returning. In case of continuous data, the handler for the DataReceived event is just invoked once. It only returns when it runs out of data and therefore it cannot be overloaded with events.

    PS. When you use Invoke, remember to close the task from a different thread as explained in the tutorial and shown in the sample program to avoid a dead lock.

    PPS. Note that the DataReceived event - or any other SerialPort event - cannot fire as long as you are in a handler for a SerialPort event (any SerialPort event), so the DataReceived event - or any other SerialPort event - cannot fire (again) until you return from the handler for the DataReceived event. If you do the receiving the way I recommend, no DataReceived events are therefore buffered up.


    Everything should be made as simple as possible, but not simpler. Any fool can write code that a computer can understand. Good programmers write code that humans understand.




    • Edited by Carsten Kanstrup Sunday, January 27, 2013 1:10 PM
    • Proposed as answer by Mike Feng Monday, January 28, 2013 1:22 PM
    • Marked as answer by Mike Feng Monday, February 4, 2013 5:12 AM
    Sunday, January 27, 2013 12:52 PM
  • "Yes, of course I can`t use this "small"chip CP2102 to transmit in one frame these 1000bytes!"

    Yes you can. The FIFO size should just be sufficiently big to hold the number of characters, which can be received (or transmitted) within 1 ms, and since you "only" run at 921.6 kbit/s, the FIFO sizes in the CP2102 is way above what you need (128).

    You need to distinguish between interrupt and events. Interrupts are handled by means of hardware, but events are handled by means of a message queue. All this is described in the tutorial if you bother to read it ;-) So the DataReceived event is NOT an interrupt. It confuses things when you don't use the right designations.

    Your problem is that the DataReceived event fires when an EOF character is received - no matter if you have asked for 3 characters. The obvious solution to this problem is the one I recommend you - simply not to ask for 3 characters, but just let the DataReceived event start the receive sequence.

    Any good protocol must have a way to distinguish the various telegrams from each other - even in case of errors! It is in my opinion bad programming to rely on a specific number of received characters. If you use ASCII, you can just use the ReadLine method, which actually gives you such a protocol (by default LF terminates the telegram). If you don't use ASCII, you have to design such a protocol yourself. I use a Break character and an Exar USB-converter in wide-mode to separate telegrams. In this mode, the converter transfers two bytes - data and flags - for every byte received (Microsoft throws the flags away after using them to fire events, so a hardware solution is necessary), but there are many other ways. You can for example define that one binary code is a sync character and then repeat this character (insert an extra) on the transmitter side in all other places than the sync position. On the receiver side, you must remove these extra inserted characters if possible. If the sync character is not followed by the same character, it is the sync. In this way, you can receive a continuous stream of data and later break it up in individual telegrams. It is in my opinion the only way to make real high speed reception.

    I have not tried the character enumeration myself, but if you really want to use it, you must do it right. Note the last part of the SerialPort1_DataReceived line:

    System::IO::Ports::SerialDataReceivedEventArgs^ e

    e is the event arguments, so you must test on e.EventType as in the code I showed you - not event_flag. If e.EventType == SerialData.eof, the last character received is Ctrl-Z and you may or may not have returned because of this (Ctrl-Z could be the last character in the telegram). If there are more characters, you must call your receiver routine again; but this time of course with the remaining number of characters to receive. Not a very clever way to do it if you want my opinion :-)

    PS. I wrote the tutorial because I was tired of answering the same questions again and again and because I wanted a common place to put the knowledge I dig up. You obviously havn't botherd to read it so far, but you would do yourself a favor to do it. It will learn you a lot about .Net allthough all examples are in VB. When you write a statement like this:

    "Yes, of course I can`t use this "small"chip CP2102 to transmit in one frame these 1000bytes!"

    which shows that you have not bothered to read the chapter (SerialPort Class) I recommended you, I begin to be a little tired of you - sorry to say it. I use a lot of time to try to help you and have spend over a month writing the tutorial, so I also expect that you at least try to understand what I tell you.

     


    Everything should be made as simple as possible, but not simpler. Any fool can write code that a computer can understand. Good programmers write code that humans understand.





    • Edited by Carsten Kanstrup Tuesday, January 29, 2013 5:43 PM
    • Marked as answer by Mike Feng Monday, February 4, 2013 5:09 AM
    Tuesday, January 29, 2013 5:19 PM

All replies

  • First of all - the use of ReceivedBytesThreshold is generally a bad idea. If you loose bytes, you may hang here forever.

    Decimal 26 is a Ctrl-Z character, which SerialPort regards as an End-of-file character, which courses it to fire the DataReceived event. This does not create problems with usual event driven communication where the DataReceived event should anyway fire at each character, so if you don't use ReceivedBytesThreshold, it should not course any problems.

    If you really want to use ReceivedBytesThreshold, you may be able to make a test (VB syntax - I am not sure of C#):

    If (e.EventType = SerialData.chars) then
    ' Do whatever you need to do
    End If

    The SerialData enumeration has only two members - Eof, which is the &H1A = 26 character, and chars, which stands for all other characters.


    Everything should be made as simple as possible, but not simpler. Any fool can write code that a computer can understand. Good programmers write code that humans understand.

    Friday, January 25, 2013 8:03 AM
  • Hello,

    I read a lot of older reports and everyone says, that the dec 26 fires an DataReceived event.

    I find this principle sad! totally useless!!

    Why I can`t disable the EOF-event-Flag easily? That would save any hassle.

    Now I`m working with this structure:

    void serialinterrupt_handler(SerialDataReceivedEventArgs){
    
    if(current_input_bytes == ReceivedBytesThreshold;){
    
    //copie my hardwarebuffer into my inputbufferarray
    
    }esle{
    
    //received ugly EOF charater =(
    
    //Do nothing or increase an my EOF received variablecounter..to see incomming CRTL-Z`s
    
    }
    

    It's not nice and at high bandwidths, it causes many errors.

    I DONT NOW....=(

    Saturday, January 26, 2013 12:05 PM
  • Hey,

    how i can get the current type of my DataReceived event?

    This way is wrong:

    private: System::Void serialPort1_DataReceived(System::Object^  sender, System::IO::Ports::SerialDataReceivedEventArgs^e{
    
    if(System::IO::Ports::SerialDataReceivedEventArgs::GetType() == 1){ // 1 is equal with SerialData Char, not Eof!
    	
    receivedbytes = this->serialPort1->Read(buffer_rx,0,3);
    			
     }
    			
    }//End DataReceived Event




    Saturday, January 26, 2013 1:10 PM
  • "I read a lot of older reports and everyone says, that the dec 26 fires an DataReceived event.

    I find this principle sad! totally useless!!

    Why I can`t disable the EOF-event-Flag easily? That would save any hassle."

    I completely agree with you. It is foolish. I can perhaps understand the purpose of Ctrl-Z for ASCII characters, but not if you use a byte related receive method where all values from 0 to 255 ought to be treated equally.

    "It's not nice and at high bandwidths, it causes many errors."

    Again, why use ReceivedBytesThreshold? I use SerialPort up to 5 Mbit/s with an Exar USB-serial converter and .Net 2.0, so if you do it right, I don't think that you will get any speed problems!

    If you don't mind VB examples, my SerialPort tutorial may be helpfull for you - especially the chapter "SerialPort Receive".


    Everything should be made as simple as possible, but not simpler. Any fool can write code that a computer can understand. Good programmers write code that humans understand.

    Saturday, January 26, 2013 2:23 PM
  • Hey Carsten,

    Again, why use ReceivedBytesThreshold?

    Ok, I use this method because 1000bytes be sent at a time, every 50ms. Speed 921600 baud.

    If every time an event is generated,then the software is overloaded.

    I think the best method is, at first load the uart buffer with new values and then copie these 1000bytes in one piece to the software buffer. Now they can be processed.

    How else?

    ->Please do not think that I am stupid. I program normally only hardware(big Cortex M3,M4 etc.)

    The best is, to use DMA-controller, jeah i can buffer some databytes without any CPU benefit!

    Peter


    Saturday, January 26, 2013 2:56 PM
  • Here are some of the settings.  Binary mode is part of encoding and is needed only if you converting bytes[] to a string class.  binary is handled by settting the data bits to 8 (not 7) and setting parity to none.

                SerialPort port = new SerialPort("Com1");
                port.StopBits = StopBits.One;
                port.Parity = Parity.None;
                port.RtsEnable = false;
                port.Handshake = Handshake.None;
                port.DtrEnable = false;
                port.DataBits = 8;
                port.BaudRate = 9600;


    jdweng

    Saturday, January 26, 2013 2:56 PM
  • "Please do not think that I am stupid. I program normally only hardware(big Cortex M3,M4 etc.)"

    I - in no way - regard you as stupid. I just recommend what I have used successfully at a 5 times higher speed than yours.

    SerialPort does not fire an event for every character received. It fires an event when there are bytes in the UART receiver FIFO, and this makes a tremendous difference. The interrupt latency of windows is approximately 1 ms, so at 921.6 kBit/s, you need a UART with at least a 128 bytes receiver FIFO like 16C950 or for example an Exar USB-serial converter with a 384 byte RX FIFO as I do. The standard PC UART 16C550 is not enough!

    Then you need to do the receiving in the most clever way, which cannot be overloaded and does not generate too many heavy TME (Thread Method Entry) objects.

    The way I do it - as you can see in the sample program - is just to let the handler for the DataReceived event wake a method on the UI thread by means of the standard delegate MethodInvoker and an Invoke call - not BeginInvoke! I do not transfer any data in a delegate as this would require a time consuming data copying! The UI method can then empty the receive buffer. When the job is done and the handler for the DataReceived event returns from the Invoke statement, it checks for any bytes received in the meantime (during Invoke) before returning. If there are any, it invokes the UI method again without returning. In case of continuous data, the handler for the DataReceived event is just invoked once. It only returns when it runs out of data and therefore it cannot be overloaded with events.

    PS. When you use Invoke, remember to close the task from a different thread as explained in the tutorial and shown in the sample program to avoid a dead lock.

    PPS. Note that the DataReceived event - or any other SerialPort event - cannot fire as long as you are in a handler for a SerialPort event (any SerialPort event), so the DataReceived event - or any other SerialPort event - cannot fire (again) until you return from the handler for the DataReceived event. If you do the receiving the way I recommend, no DataReceived events are therefore buffered up.


    Everything should be made as simple as possible, but not simpler. Any fool can write code that a computer can understand. Good programmers write code that humans understand.




    • Edited by Carsten Kanstrup Sunday, January 27, 2013 1:10 PM
    • Proposed as answer by Mike Feng Monday, January 28, 2013 1:22 PM
    • Marked as answer by Mike Feng Monday, February 4, 2013 5:12 AM
    Sunday, January 27, 2013 12:52 PM
  • The only way of reliably receive data on a windows operating system is to through away the Microsoft Driver.  It never worked properly from the beginning of time.  The Windows Driver doesn't impliment a hardware  interupt which is the only way of  ensuring you that you recieve every data byte.  The windows driver samples the UART using the timer tick interupt which is only 100ms.  I have been writing uart driver on PC since the first 8080 PC and never found a good method of getting the UART to run properly with the standard Microsoft Drivers.  Using the low level hardware interupt always works proivided there aren't other processes on the PC that is disabling interupts.


    jdweng

    Sunday, January 27, 2013 1:48 PM
  • @ Joel Engineer

     "The windows driver samples the UART using the timer tick interupt which is only 100ms."

    Nonsense. If this was really the case, the response time for a single byte could be as high as 100 mS and would be 50 mS in average. The only thing, which is timer controlled, is the USB port, which samples every port every 1 mS. This is in the same order as the interrupt latency, so the necessary UART FIFO size is the same no matter if you use a hardwired UART or a USB-serial converter.

    Please don't confuse things when you obviously don't know how it works.


    Everything should be made as simple as possible, but not simpler. Any fool can write code that a computer can understand. Good programmers write code that humans understand.


    Sunday, January 27, 2013 2:37 PM
  • Hey,

    Now I use a different kind. I send every 50ms some bytes (50) to my microcontroller, but in one piece!

    When they arrived, the microcontroller sends a frame with max. 1kByte inkl. CRC etc.

    They are stored in hardware buffer (UART to USB, CP2102 chip).

    They are processed without interrupt before the next transmission of my software comes.

    Only one thing bothers me, the jitter from my sending routine.

    I am using  one softwaretimer, which triggers every 50ms. When I set the timer value to 50ms, then my Uart sends every 45-65ms. I saw it on the oscilloscope. Under 50ms, there are only problems. The jitter increases....not nice


    Monday, January 28, 2013 9:11 PM
  • Windows is really not a RTOS (Real Time Operating System), and because there are more task switchings involved from the timer runs out until you transmit, a jitter from 45-65 ms really don't surprises me.

    I have had the same problems with generation of a break character, that is, a constant 0 for more than 10 bits including start and stop bit. If I set the timer value below approximately 11 ms (task switching on a single CPU core system is 10 ms and 15 ms on a multicore CPU), sometimes the break delay is not executed at all and the set and reset instructions are therefore executed immediately after each other (also tested on an oscilloscope).

    If you really need precise data timing, I would make the reception event driven (DataReceived event) as I recommended you and then let the ARM processor send the data (no polling).

    What are you trying to achive? It looks like industrial control, which I have been working with for approximately 35 years, so we may be in the same business.


    Everything should be made as simple as possible, but not simpler. Any fool can write code that a computer can understand. Good programmers write code that humans understand.

    Tuesday, January 29, 2013 9:33 AM
  • "When they arrived, the microcontroller sends a frame with max. 1kByte inkl. CRC etc.

    They are stored in hardware buffer (UART to USB, CP2102 chip)."

    They can't be since the CP2102 chip "only" has a 576 bytes receiver FIFO. However, within 1 ms the USB port detects that there are new data and then transfers them to the software buffer in SerialPort. You can find more information about buffering in chapter "SerialPort Class" of my tutorial.


    Everything should be made as simple as possible, but not simpler. Any fool can write code that a computer can understand. Good programmers write code that humans understand.

    Tuesday, January 29, 2013 11:11 AM
  • Hey Carsten,

    First of all thank you for the answers...

    Yes, of course I can`t use this "small"chip CP2102 to transmit in one frame these 1000bytes!

    I would take a larger or split the frame. I want to build general data transmission to the microcontroller.

    You can easily record data or directly represent.

    Well, could you help me with the syntaxfor check the EOF event?

    I know that my interrupt on end of file or maximum number of bytes is triggered.

    But how can I recognize it? How do I put this into C + + / cli and Windows Forms?

    I mean this:

    If (e.EventType = SerialData.chars) then
    ' Do whatever you need to do
    End If

    I can`t find the implementation to check the event Flags from my Serialport.

    Tuesday, January 29, 2013 4:27 PM
  • Here is an excerpt from my code:

    private: System::Void serialPort1_DataReceived(System::Object^  sender, System::IO::Ports::SerialDataReceivedEventArgs^  e){
    			
    			
    if(event_Flag == EOF){ //Can`t find this point in .NET 3.5??
      //Do nothing!
      }else{
        //copie my Hardware FIFo to Softwarebuffer
    }
    			
    		
    		
    }//End
    

    Tuesday, January 29, 2013 4:36 PM
  • "Yes, of course I can`t use this "small"chip CP2102 to transmit in one frame these 1000bytes!"

    Yes you can. The FIFO size should just be sufficiently big to hold the number of characters, which can be received (or transmitted) within 1 ms, and since you "only" run at 921.6 kbit/s, the FIFO sizes in the CP2102 is way above what you need (128).

    You need to distinguish between interrupt and events. Interrupts are handled by means of hardware, but events are handled by means of a message queue. All this is described in the tutorial if you bother to read it ;-) So the DataReceived event is NOT an interrupt. It confuses things when you don't use the right designations.

    Your problem is that the DataReceived event fires when an EOF character is received - no matter if you have asked for 3 characters. The obvious solution to this problem is the one I recommend you - simply not to ask for 3 characters, but just let the DataReceived event start the receive sequence.

    Any good protocol must have a way to distinguish the various telegrams from each other - even in case of errors! It is in my opinion bad programming to rely on a specific number of received characters. If you use ASCII, you can just use the ReadLine method, which actually gives you such a protocol (by default LF terminates the telegram). If you don't use ASCII, you have to design such a protocol yourself. I use a Break character and an Exar USB-converter in wide-mode to separate telegrams. In this mode, the converter transfers two bytes - data and flags - for every byte received (Microsoft throws the flags away after using them to fire events, so a hardware solution is necessary), but there are many other ways. You can for example define that one binary code is a sync character and then repeat this character (insert an extra) on the transmitter side in all other places than the sync position. On the receiver side, you must remove these extra inserted characters if possible. If the sync character is not followed by the same character, it is the sync. In this way, you can receive a continuous stream of data and later break it up in individual telegrams. It is in my opinion the only way to make real high speed reception.

    I have not tried the character enumeration myself, but if you really want to use it, you must do it right. Note the last part of the SerialPort1_DataReceived line:

    System::IO::Ports::SerialDataReceivedEventArgs^ e

    e is the event arguments, so you must test on e.EventType as in the code I showed you - not event_flag. If e.EventType == SerialData.eof, the last character received is Ctrl-Z and you may or may not have returned because of this (Ctrl-Z could be the last character in the telegram). If there are more characters, you must call your receiver routine again; but this time of course with the remaining number of characters to receive. Not a very clever way to do it if you want my opinion :-)

    PS. I wrote the tutorial because I was tired of answering the same questions again and again and because I wanted a common place to put the knowledge I dig up. You obviously havn't botherd to read it so far, but you would do yourself a favor to do it. It will learn you a lot about .Net allthough all examples are in VB. When you write a statement like this:

    "Yes, of course I can`t use this "small"chip CP2102 to transmit in one frame these 1000bytes!"

    which shows that you have not bothered to read the chapter (SerialPort Class) I recommended you, I begin to be a little tired of you - sorry to say it. I use a lot of time to try to help you and have spend over a month writing the tutorial, so I also expect that you at least try to understand what I tell you.

     


    Everything should be made as simple as possible, but not simpler. Any fool can write code that a computer can understand. Good programmers write code that humans understand.





    • Edited by Carsten Kanstrup Tuesday, January 29, 2013 5:43 PM
    • Marked as answer by Mike Feng Monday, February 4, 2013 5:09 AM
    Tuesday, January 29, 2013 5:19 PM
  • I'm sorry that I ask questions that you have already described most exactly.

    I just wanted to know how to turn off the EOFcheck! Nothing more!You helped me a little more anyway.I think we don`t need to add any more.


    Last question, at which email address i reach you? I want to send a thank you personally!

    Tuesday, January 29, 2013 6:57 PM
  • "I just wanted to know how to turn off the EOFcheck! Nothing more!"

    Yes, but the problem is that you can't. Therefore I suggested you another solution.

    "Last question, at which email address i reach you? I want to send a thank you personally!"

    It is not necessary to thank me personally. As everybody else here, we are here to help. If you help others, you are in a way also more entitled to receive help yourself :-) When you feel that your problem has been solved, mark the best reply as answer.

    Good luck with the project.


    Everything should be made as simple as possible, but not simpler. Any fool can write code that a computer can understand. Good programmers write code that humans understand.

    Tuesday, January 29, 2013 8:18 PM
  • There very well may be an answer further down this thread, but as Carston said, ReceivedBytesThreshold isn't the best way to handle serial. However, I have used it many times in the past out of pure laziness. The way I handle the EOF event when I don't want it causing problems is to throw this little snippet of code in the beginning of my DataReceived event handler:

    If e.EventType = SerialData.Eof Then Exit sub End If

    'Now process data


    Thursday, May 9, 2013 1:36 PM