none
serialport write

    Question

  • Hi all!
    I have a problem with my serialport. Sometimes, if I send a long (35 char) command, only first 20 chars are sent; last chars, maybe, remain in a buffer..

    It seems commands are being interrupted before completion. The call to BaseStream->Flush() does not alleviate the problem.
    Does anyone know of a way to ensure that serial port writes proceed to completion without being interrupted?

    This is the code:
    1... 
    2this->serialPort1->BaudRate = 115200; 
    3this->serialPort1->PortName = L"COM2"
    4... 
    5this->Disposed += gcnew System::EventHandler(this, &Form1::Form1_Disposed); 
    6this->Load += gcnew System::EventHandler(this, &Form1::Form1_Load); 
    7... 
    8 
    9System::Void Form1_Load(System::Object^  sender, System::EventArgs^  e) { 
    10   this->serialPort1->Open(); 
    11 
    12   System::Threading::ThreadStart^ myThreadDelegate = gcnew System::Threading::ThreadStart(this, &deploy::Form1::ThreadTask); 
    13   System::Threading::Thread^ trd = gcnew System::Threading::Thread(myThreadDelegate); 
    14   trd->IsBackground = true
    15   trd->Start(); 
    16
    17 
    18System::Void Form1_Disposed(System::Object^  sender, System::EventArgs^  e) { 
    19   this->serialPort1->Close(); 
    20
    21 
    22System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) { 
    23   this->serialPort1->Write("this_is_a_very_long_string\r"); 
    24
    25 
    26System::Void ThreadTask(System::Void) { 
    27   while(1) 
    28      this->textBox1->AppendText(this->serialPort1->ReadExisting()); 
    29

    Wednesday, October 15, 2008 8:58 AM

Answers

  • The DataReceived event was pretty much designed to allow you to use blocking reads that do not cause problems.  The event is fired on a thread pool thread, you can take as long as you need.  Same issue with updating controls of course.
    Hans Passant.
    • Marked as answer by jack 321 Monday, October 20, 2008 6:55 AM
    Wednesday, October 15, 2008 12:49 PM

All replies

  • The problem is probably located on the other end of the wire.  If you use ReadExisting() there too, you're bound to only read the existing characters, not all of them.  Serial ports are slow, it takes a while before the bytes are sent and received.  The typical approach is to use either fixed length packets are send a special character that indicates the end of the packet.  SerialPort.NewLine and ReadLine() are dedicated to support this.  A linefeed ('\n') is the usual choice and the default value for the NewLine property.

    Another thing you're doing wrong is updating controls in a thread.  That's strictly verboten in Windows, it causes all kind of problems, including painting issues and deadlocks.  You must use Control::BeginInvoke() so the UI thread updates the control.

    Hans Passant.
    Wednesday, October 15, 2008 12:29 PM
  • Thanks a lot!

    I replaced ReadLine with ReadExisting because I need a "no-blocking" read.
    With ReadLine I was not able to send a command when I click the button; the command was sent when some character was readed!

    About the thread.. ok ;)
    Wednesday, October 15, 2008 12:42 PM
  • The DataReceived event was pretty much designed to allow you to use blocking reads that do not cause problems.  The event is fired on a thread pool thread, you can take as long as you need.  Same issue with updating controls of course.
    Hans Passant.
    • Marked as answer by jack 321 Monday, October 20, 2008 6:55 AM
    Wednesday, October 15, 2008 12:49 PM