Thursday, April 2, 2009

Serial Port Communication in C#

Stumble del.icio.us Reddit MyWeb! Facebook Google bookmark

I had a requirement of communicating on Serial Port in C#. I have tried to leverage the System.IO.Ports.SerialPort class to meet the needs. Here is the class CgSerialPort which derives from SerialPort and provides access to some custom events. Most of the time, the messages which are communicated have a header-message-footer structure. I have kept the same structure in mind while writing this class. Though, if you have a plain structure -message-, just ignore the ExpectedHeaders/ExpectedFooters part, and do not subscribe to the header/footer related events and you will be fine. The XML comments for each class/method/field/property are self explanatory. Enjoy ...



    1 // No Copyright © . Use it anywhere you want.

    2 

    3 using System;

    4 using System.Collections.Generic;

    5 using System.ComponentModel;

    6 using System.IO;

    7 using System.IO.Ports;

    8 using System.Text;

    9 

   10 namespace SerialProto

   11 {

   12 // *************************************************************************

   13 /// <summary>

   14 /// The class represents a serial port resource.

   15 /// </summary>

   16 /// <remarks>

   17 /// <para>The serial port on a PC is a full-duplex device meaning that

   18 /// it can send and receive data at the same time. In order to be able to

   19 /// do this, it uses separate lines for transmitting and receiving data.

   20 /// Some types of serial devices support only one-way communication, and

   21 /// therefore, use only two wires in the cable - the transmit line and the

   22 /// signal ground.

   23 /// </para>

   24 /// <para> In serial communication, a byte of data is transferred through a

   25 /// single wire one bit at a time. The packets contain a start bit, data,

   26 /// and stop bit. Once the start bit has been sent, the transmitter sends

   27 /// the actual data bits. There may either be 5, 6, 7, or 8 data bits,

   28 /// depending on the number you have selected. Both receiver and the

   29 /// transmitter must agree on the number of data bits, as well as the

   30 /// baud rate.

   31 /// </para>

   32 /// <para> A Null Modem cable simply crosses the receive and transmit lines

   33 /// so that transmit on one end is connected to receive on the other end

   34 /// and vice versa. In addition to transmit and receive, DTR & DSR, as well

   35 /// as RTS & CTS are also crossed in a Null Modem connection.

   36 /// </para>

   37 /// <para>

   38 /// The pin (Male RS232 DB9) looks like this on a 9 pin connection on a DTE

   39 /// device:

   40 /// ------------------

   41 /// \ 1 2 3 4 5 /

   42 /// \ 6 7 8 9 /

   43 /// --------------

   44 /// or in some of the pins it may be like this:

   45 /// ------------------

   46 /// \ 5 4 3 2 1 /

   47 /// \ 9 8 7 6 /

   48 /// --------------

   49 /// Here is what each pin is usually meant for:

   50 /// Pin # Direction of signal

   51 /// 1 Carrier detect (CD)

   52 /// 2 Received data (RD)

   53 /// 3 Transmitted data (TD)

   54 /// 4 Data terminal ready (DTR)

   55 /// 5 Signal ground common reference voltage

   56 /// 6 Data set ready (DSR)

   57 /// 7 Request to send (RTS)

   58 /// 8 Clear to send (CTS)

   59 /// 9 Ring indicator (RI) (from DCE) incoming signal from modem

   60 /// </para>

   61 /// <para>If you do not want to use any handshake, you will use three wire

   62 /// connections in which you will connect pin 2(RD) of one connector to

   63 /// pin 3(TD) of the other. For both the connectors, connect pin 5 (ground)

   64 /// of both the connectors with each other (common ground).If you want,

   65 /// you can use only one PC as both transmitter and receiver for test

   66 /// communication. Then, just take a DB 9 connector and a small wire, and

   67 /// connect pin no 2 and 3 using the wire that will connect a loop back.

   68 /// That is, whatever you will send, the same data you will be receiving.

   69 /// </para>

   70 /// <para><seealso cref="SerialPort"/></para>

   71 /// <author>Authors:Praveen K. Jha</author>

   72 /// </remarks>

   73 public class CgSerialPort : SerialPort

   74 {

   75 #region events and delegates

   76 

   77 /// <summary> Serial port message header received event.</summary>

   78 [field: NonSerialized]

   79 public event EventHandler<CgSerialPortEventArgs> HeaderReceived;

   80 /// <summary> Serial port message footer received event.</summary>

   81 [field: NonSerialized]

   82 public event EventHandler<CgSerialPortEventArgs> FooterReceived;

   83 /// <summary> Serial port message data received event.</summary>

   84 [field: NonSerialized]

   85 public event EventHandler<CgSerialPortEventArgs> MessageReceived;

   86 /// <summary> Serial port header data receive error event.</summary>

   87 [field: NonSerialized]

   88 public event EventHandler<CgSerialPortEventArgs> HeaderRecvError;

   89 /// <summary> Serial port footer data receive error event.</summary>

   90 [field: NonSerialized]

   91 public event EventHandler<CgSerialPortEventArgs> FooterRecvError;

   92 /// <summary> Serial port message data receive error event.</summary>

   93 [field: NonSerialized]

   94 public event EventHandler<CgSerialPortEventArgs> MessageRecvError;

   95 /// <summary> Serial port error event.</summary>

   96 [field: NonSerialized]

   97 public event EventHandler<CgSerialPortEventArgs> PortError;

   98 

   99 //**********************************************************************

  100 /// <summary>

  101 /// Delegate for use by this class to manage data received.

  102 /// </summary>

  103 /// <remarks>

  104 /// The delegate is set by <see cref="CgSerialPort"/> and is invoked

  105 /// during the DataReceived event handling.

  106 /// </remarks>

  107 private delegate void DataReceivedCb();

  108 

  109 #endregion events and delegates

  110 

  111 #region private fields

  112 

  113 /// <summary>The Delegate for use by this class to manage data received.

  114 /// The delegate is set by <see cref="CgSerialPort"/> and is invoked

  115 /// during the DataReceived event handling.</summary>

  116 [NonSerialized]

  117 private DataReceivedCb DataRcvdCb;

  118 

  119 /// <summary> Read/write timeout values in milliseconds.</summary>

  120 private const int TIMEOUT = 500;

  121 private SerialDataReceivedEventHandler DataRcvdHandler;

  122 private IList<char> m_expectedHeaders;

  123 private IList<char> m_expectedFooters;

  124 

  125 private int m_headerIndex = -1;

  126 private int m_footerIndex = -1;

  127 private StringBuilder m_sbHdr;

  128 private StringBuilder m_sbFtr;

  129 

  130 #endregion private fields

  131 

  132 #region Constructors and overrides

  133 

  134 // *********************************************************************

  135 /// <summary>

  136 /// Initializes a new instance of the <see cref="CgSerialPort"/> class.

  137 /// </summary>

  138 public CgSerialPort() : base()

  139 {

  140 this.Parity = Parity.Even;

  141 this.ReadTimeout = TIMEOUT;

  142 this.WriteTimeout = TIMEOUT;

  143 }

  144 

  145 // *********************************************************************

  146 /// <summary>

  147 /// Initializes a new instance of the <see cref="CgSerialPort"/> class

  148 /// using the specified port name.

  149 /// </summary>

  150 /// <param name="portName"> The port to use (for example, COM1).</param>

  151 /// <exception cref="IOException">

  152 /// The specified port could not be found or opened.

  153 /// </exception>

  154 public CgSerialPort(string portName)

  155 : base(portName)

  156 {

  157 this.Parity = Parity.Even;

  158 }

  159 

  160 // *********************************************************************

  161 /// <summary>

  162 /// Initializes a new instance of the <see cref="CgSerialPort"/> class

  163 /// using the specified port name.

  164 /// </summary>

  165 /// <param name="portName"> The port to use (for example, COM1).</param>

  166 /// <param name="baudRate">The baud rate.</param>

  167 /// <exception cref="IOException">

  168 /// The specified port could not be found or opened.

  169 /// </exception>

  170 public CgSerialPort(string portName, int baudRate)

  171 : base(portName, baudRate)

  172 {

  173 this.Parity = Parity.Even;

  174 }

  175 

  176 // *********************************************************************

  177 /// <summary>

  178 /// Initializes a new instance of the <see cref="CgSerialPort"/> class

  179 /// using the specified port name.

  180 /// </summary>

  181 /// <param name="portName"> The port to use (for example, COM1).</param>

  182 /// <param name="baudRate">The baud rate.</param>

  183 /// <param name="parity">One of the <see cref="SerialPort.Parity"/>

  184 /// values.</param>

  185 /// <exception cref="IOException">

  186 /// The specified port could not be found or opened.

  187 /// </exception>

  188 public CgSerialPort(string portName, int baudRate, Parity parity)

  189 :base(portName, baudRate, parity)

  190 {

  191 }

  192 

  193 // *********************************************************************

  194 /// <summary>

  195 /// Initializes a new instance of the <see cref="CgSerialPort"/> class

  196 /// using the specified port name.

  197 /// </summary>

  198 /// <param name="portName"> The port to use (for example, COM1).</param>

  199 /// <param name="baudRate"> The baud rate.</param>

  200 /// <param name="parity"> One of the <see cref="SerialPort.Parity"/>

  201 /// <param name="dataBits"> The databits value.</param>

  202 /// values.</param>

  203 /// <exception cref="IOException">

  204 /// The specified port could not be found or opened.

  205 /// </exception>

  206 public CgSerialPort(string portName, int baudRate, Parity parity,

  207 int dataBits)

  208 : base(portName, baudRate, parity, dataBits)

  209 {

  210 }

  211 

  212 // *********************************************************************

  213 /// <summary>

  214 /// Initializes a new instance of the <see cref="CgSerialPort"/> class

  215 /// using the specified port name.

  216 /// </summary>

  217 /// <param name="portName"> The port to use (for example, COM1).</param>

  218 /// <param name="baudRate"> The baud rate.</param>

  219 /// <param name="parity"> One of the <see cref="SerialPort.Parity"/>

  220 /// <param name="dataBits"> The databits value.</param>

  221 /// <param name="stopBits"> One of the <see cref="SerialPort.StopBits"/>

  222 /// values.</param>

  223 /// values.</param>

  224 /// <exception cref="IOException">

  225 /// The specified port could not be found or opened.

  226 /// </exception>

  227 public CgSerialPort(string portName, int baudRate, Parity parity,

  228 int dataBits, StopBits stopBits)

  229 : base(portName, baudRate, parity, dataBits, stopBits)

  230 {

  231 }

  232 

  233 //**********************************************************************

  234 /// <summary>

  235 /// Releases the unmanaged resources used by this class and

  236 /// optionally releases the managed resources.

  237 /// </summary>

  238 /// <param name="disposing"><see langword="true"/> to release both

  239 /// managed and unmanaged resources; <see langword="false"/> to release

  240 /// only unmanaged resources.</param>

  241 protected override void Dispose(bool disposing)

  242 {

  243 if (disposing)

  244 {

  245 // Free managed objects here; set references to null.

  246 }

  247 // Free unmanaged objects here; set references to null.

  248 base.Dispose(disposing);

  249 }

  250 

  251 #endregion Constructors and overrides

  252 

  253 #region Utility methods and properties

  254 

  255 // *********************************************************************

  256 /// <summary>

  257 /// Gets or sets the list of char values which are expected to be

  258 /// received in header.

  259 /// </summary>

  260 /// <value> A list of char values.</value>

  261 public IList<char> ExpectedHeaders

  262 {

  263 get { return m_expectedHeaders; }

  264 set { m_expectedHeaders = value; }

  265 }

  266 

  267 // *********************************************************************

  268 /// <summary>

  269 /// Gets or sets the list of char values which are expected to be

  270 /// received in footer.

  271 /// </summary>

  272 /// <value> A list of char values.</value>

  273 public IList<char> ExpectedFooters

  274 {

  275 get { return m_expectedFooters; }

  276 set { m_expectedFooters = value; }

  277 }

  278 

  279 // *********************************************************************

  280 /// <summary>

  281 /// Starts the serial port communication on the specified port.

  282 /// </summary>

  283 /// <returns> <see langword="true"/> if the serial port was opened and

  284 /// started successfully; <see langword="false"/> otherwise.</returns>

  285 public bool Start()

  286 {

  287 bool success = false;

  288 try

  289 {

  290 this.Open();

  291 DataRcvdHandler =

  292 new SerialDataReceivedEventHandler(HandleDataReceived);

  293 this.DataReceived += DataRcvdHandler;

  294 DataRcvdCb = ReadHeader;

  295 success = true;

  296 }

  297 catch (Exception e)

  298 {

  299 // Do error handling

  300 OnPortError(new CgSerialPortEventArgs(e.ToString()));

  301 }

  302 return success;

  303 }

  304 

  305 // *********************************************************************

  306 /// <summary>

  307 /// Stops communicating on serial port and closes it.

  308 /// </summary>

  309 public void Stop()

  310 {

  311 this.DataReceived -= DataRcvdHandler;

  312 DataRcvdCb = null;

  313 this.Close();

  314 }

  315 

  316 #endregion Utility methods and properties

  317 

  318 #region Message data receive handling

  319 

  320 // *********************************************************************

  321 /// <summary>

  322 /// Handles the <see cref="SerialPort.DataReceived"/> event for serial port.

  323 /// </summary>

  324 /// <param name="sender">The original object who started this event.</param>

  325 /// <param name="e">A <see cref="SerialDataReceivedEventArgs"/>

  326 /// containing the event data.</param>

  327 private void HandleDataReceived

  328 (

  329 object sender,

  330 SerialDataReceivedEventArgs e

  331 )

  332 {

  333 DataRcvdCb();

  334 }

  335 

  336 // *********************************************************************

  337 /// <summary>

  338 /// Reads the header of the message (if any).

  339 /// </summary>

  340 private void ReadHeader()

  341 {

  342 // See if we've already received header details

  343 if (ExpectedHeaders != null && ExpectedHeaders.Count > 0 &&

  344 m_headerIndex < ExpectedHeaders.Count - 1)

  345 {

  346 m_headerIndex++;

  347 try

  348 {

  349 if (m_sbHdr == null) m_sbHdr = new StringBuilder();

  350 // Read the next available header

  351 string hdr = this.ReadTo(ExpectedHeaders[m_headerIndex].ToString());

  352 m_sbHdr.Append(hdr);

  353 if (m_headerIndex == ExpectedHeaders.Count - 1)

  354 {

  355 m_sbHdr.Append(((List<char>) ExpectedHeaders).ToArray());

  356 DataRcvdCb = ReadMessage;

  357 OnHeaderReceived(new CgSerialPortEventArgs(m_sbHdr.ToString()));

  358 }

  359 }

  360 catch (TimeoutException)

  361 {

  362 // Handle timeout exception

  363 OnHeaderRecvError(new CgSerialPortEventArgs(m_sbHdr.ToString()));

  364 }

  365 }

  366 else

  367 {

  368 DataRcvdCb = ReadMessage;

  369 ReadMessage();

  370 }

  371 } // end ReadHeader

  372 

  373 // *********************************************************************

  374 /// <summary>

  375 /// Reads the footer of the message (if any).

  376 /// </summary>

  377 private void ReadFooter()

  378 {

  379 // See if we've already received header details

  380 if (ExpectedFooters != null && ExpectedFooters.Count > 0 &&

  381 m_footerIndex < ExpectedFooters.Count - 1)

  382 {

  383 m_footerIndex++;

  384 try

  385 {

  386 if (m_sbFtr == null) m_sbFtr = new StringBuilder();

  387 // Read the next available footer

  388 string ftr = this.ReadTo(ExpectedFooters[m_footerIndex].ToString());

  389 m_sbFtr.Append(ftr);

  390 if (m_footerIndex == ExpectedFooters.Count - 1)

  391 {

  392 m_sbFtr.Append(((List<char>) ExpectedFooters).ToArray());

  393 DataRcvdCb = ReadHeader;

  394 OnFooterReceived(new CgSerialPortEventArgs(m_sbFtr.ToString()));

  395 }

  396 }

  397 catch (TimeoutException)

  398 {

  399 // Handle timeout exception

  400 OnFooterRecvError(new CgSerialPortEventArgs(m_sbFtr.ToString()));

  401 }

  402 }

  403 else

  404 {

  405 DataRcvdCb = ReadHeader;

  406 ReadHeader();

  407 }

  408 } // end ReadFooter

  409 

  410 // *********************************************************************

  411 /// <summary>

  412 /// Reads the full message content.

  413 /// </summary>

  414 private void ReadMessage()

  415 {

  416 // See if we've already received header details

  417 if (ExpectedFooters != null && ExpectedFooters.Count > 0)

  418 {

  419 string msg = string.Empty;

  420 try

  421 {

  422 m_footerIndex = 0;

  423 string ftrStart = ExpectedFooters[0].ToString();

  424 // Read the message content

  425 msg = this.ReadTo(ftrStart);

  426 DataRcvdCb = ReadFooter;

  427 OnMessageReceived(new CgSerialPortEventArgs(msg));

  428 if (ExpectedFooters.Count == 1)

  429 {

  430 // There is only one footer character, meaning we've already

  431 // received all footers

  432 StringBuilder sb = new StringBuilder();

  433 DataRcvdCb = ReadHeader;

  434 OnFooterReceived(new CgSerialPortEventArgs(ftrStart));

  435 }

  436 }

  437 catch (TimeoutException)

  438 {

  439 // Handle timeout exception

  440 OnMessageRecvError(new CgSerialPortEventArgs(msg.ToString()));

  441 }

  442 }

  443 else

  444 {

  445 // Nothing in footer is specified, so assume that newline is the

  446 // end of message.

  447 // Read the message content

  448 string msg = this.ReadTo(this.NewLine);

  449 DataRcvdCb = ReadFooter;

  450 OnMessageReceived(new CgSerialPortEventArgs(msg));

  451 }

  452 } // end ReadMessage

  453 

  454 //**********************************************************************

  455 /// <summary>

  456 /// Raise header received notification event for registered listeners.

  457 /// </summary>

  458 /// <param name="e">The <see cref="CgSerialPortEventArgs"/> instance

  459 /// associated with this notification event.</param>

  460 private void OnHeaderReceived(CgSerialPortEventArgs e)

  461 {

  462 EventHandler<CgSerialPortEventArgs> h = HeaderReceived;

  463 if (h != null)

  464 {

  465 h(this, e);

  466 }

  467 m_headerIndex = -1;

  468 m_sbHdr = null;

  469 }

  470 

  471 //**********************************************************************

  472 /// <summary>

  473 /// Raise header receive error notification event for registered listeners.

  474 /// </summary>

  475 /// <param name="e">The <see cref="CgSerialPortEventArgs"/> instance

  476 /// associated with this notification event.</param>

  477 private void OnHeaderRecvError(CgSerialPortEventArgs e)

  478 {

  479 EventHandler<CgSerialPortEventArgs> h = HeaderRecvError;

  480 if (h != null)

  481 {

  482 h(this, e);

  483 }

  484 m_headerIndex = -1;

  485 m_sbHdr = null;

  486 DataRcvdCb = ReadMessage;

  487 }

  488 

  489 //**********************************************************************

  490 /// <summary>

  491 /// Raise footer received notification event for registered listeners.

  492 /// </summary>

  493 /// <param name="e">The <see cref="CgSerialPortEventArgs"/> instance

  494 /// associated with this notification event.</param>

  495 private void OnFooterReceived(CgSerialPortEventArgs e)

  496 {

  497 EventHandler<CgSerialPortEventArgs> h = FooterReceived;

  498 if (h != null)

  499 {

  500 h(this, e);

  501 }

  502 m_footerIndex = -1;

  503 m_sbFtr = null;

  504 }

  505 

  506 //**********************************************************************

  507 /// <summary>

  508 /// Raise footer receive error notification event for registered listeners.

  509 /// </summary>

  510 /// <param name="e">The <see cref="CgSerialPortEventArgs"/> instance

  511 /// associated with this notification event.</param>

  512 private void OnFooterRecvError(CgSerialPortEventArgs e)

  513 {

  514 EventHandler<CgSerialPortEventArgs> h = FooterRecvError;

  515 if (h != null)

  516 {

  517 h(this, e);

  518 }

  519 m_footerIndex = -1;

  520 m_sbFtr = null;

  521 DataRcvdCb = ReadHeader;

  522 }

  523 

  524 //**********************************************************************

  525 /// <summary>

  526 /// Raise message received notification event for registered listeners.

  527 /// </summary>

  528 /// <param name="e">The <see cref="CgSerialPortEventArgs"/> instance

  529 /// associated with this notification event.</param>

  530 private void OnMessageReceived(CgSerialPortEventArgs e)

  531 {

  532 EventHandler<CgSerialPortEventArgs> h = MessageReceived;

  533 if (h != null)

  534 {

  535 h(this, e);

  536 }

  537 m_headerIndex = -1;

  538 }

  539 

  540 //**********************************************************************

  541 /// <summary>

  542 /// Raise message receive error notification event for registered listeners.

  543 /// </summary>

  544 /// <param name="e">The <see cref="CgSerialPortEventArgs"/> instance

  545 /// associated with this notification event.</param>

  546 private void OnMessageRecvError(CgSerialPortEventArgs e)

  547 {

  548 EventHandler<CgSerialPortEventArgs> h = MessageRecvError;

  549 if (h != null)

  550 {

  551 h(this, e);

  552 }

  553 m_headerIndex = -1;

  554 m_footerIndex = -1;

  555 DataRcvdCb = ReadFooter;

  556 }

  557 

  558 //**********************************************************************

  559 /// <summary>

  560 /// Raises port open errors to registered listeners.

  561 /// </summary>

  562 /// <param name="e">The <see cref="CgSerialPortEventArgs"/> instance

  563 /// associated with this notification event.</param>

  564 private void OnPortError(CgSerialPortEventArgs e)

  565 {

  566 EventHandler<CgSerialPortEventArgs> h = PortError;

  567 if (h != null)

  568 {

  569 h(this, e);

  570 }

  571 }

  572 

  573 #endregion Message data receive handling

  574 

  575 } // end class CgSerialPort

  576 } // end namespace SerialProto



The CgSerialPort class uses and EventArgs class to notify the subscribers. It just has a property which contains the message that is received (or partial/error message in case of error). And here is the code for the CgSerialPortEventArgs:


  577 // No Copyright © . Use it anywhere you want.

  578 

  579 using System;

  580 

  581 namespace SerialProto

  582 {

  583 // *************************************************************************

  584 /// <summary>

  585 /// An eventargs class to cater to the <see cref="CgSerialPort"/> class needs.

  586 /// </summary>

  587 /// <remarks>

  588 /// <para><seealso cref="System.IO.Ports.SerialPort"/></para>

  589 /// <author>Authors:Praveen K. Jha</author>

  590 /// </remarks>

  591 public class CgSerialPortEventArgs : EventArgs

  592 {

  593 private string m_message;

  594 

  595 // *********************************************************************

  596 /// <summary>

  597 /// Initializes a new instance of the <see cref="CgSerialPortEventArgs"/>

  598 /// class.

  599 /// </summary>

  600 /// <param name="message"> The message that is received.</param>

  601 public CgSerialPortEventArgs(string message)

  602 {

  603 m_message = message;

  604 }

  605 

  606 // *********************************************************************

  607 /// <summary>

  608 /// Gets the message associated with this eventargs.

  609 /// </summary>

  610 /// <value> The message string.</value>

  611 public string Message

  612 {

  613 get { return m_message; }

  614 }

  615 

  616 } // end class CgSerialPortEventArgs

  617 } // end namespace SerialProto



Finally here is the sample project file which will demonstrate the use of the above classes. Just copy paste the codes here in your project and you should be good to go.

  618 using System;

  619 using System.Collections.Generic;

  620 using System.IO.Ports;

  621 

  622 using SerialProto;

  623 

  624 public class PortChat

  625 {

  626 static bool _continue;

  627 static CgSerialPort _serialPort;

  628 

  629 public static void Main()

  630 {

  631 string name;

  632 string message;

  633 StringComparer stringComparer = StringComparer.OrdinalIgnoreCase;

  634 

  635 // Create a new SerialPort object with default settings.

  636 _serialPort = new CgSerialPort();

  637 

  638 // Allow the user to set the appropriate properties.

  639 _serialPort.PortName = SetPortName(_serialPort.PortName);

  640 _serialPort.BaudRate = SetPortBaudRate(_serialPort.BaudRate);

  641 _serialPort.Parity = SetPortParity(_serialPort.Parity);

  642 _serialPort.DataBits = SetPortDataBits(_serialPort.DataBits);

  643 _serialPort.StopBits = SetPortStopBits(_serialPort.StopBits);

  644 _serialPort.Handshake = SetPortHandshake(_serialPort.Handshake);

  645 

  646 // Set the read/write timeouts

  647 _serialPort.ReadTimeout = 500;

  648 _serialPort.WriteTimeout = 500;

  649 

  650 _serialPort.MessageReceived +=

  651 new EventHandler<CgSerialPortEventArgs>(_serialPort_MessageReceived);

  652 _serialPort.PortError +=

  653 new EventHandler<CgSerialPortEventArgs>(_serialPort_PortError);

  654 _serialPort.MessageRecvError +=

  655 new EventHandler<CgSerialPortEventArgs>(_serialPort_MessageRecvError);

  656 

  657 // Uncomment these if you have header/footer requirements

  658 //_serialPort.HeaderReceived +=

  659 // new EventHandler<CgSerialPortEventArgs>(_serialPort_HeaderReceived);

  660 //_serialPort.FooterReceived +=

  661 // new EventHandler<CgSerialPortEventArgs>(_serialPort_FooterReceived);

  662 //List<char> expHdr = new List<char>();

  663 //expHdr.Add('?');

  664 //expHdr.Add('?');

  665 //List<char> expFtr = new List<char>();

  666 //expFtr.Add('?');

  667 //expFtr.Add('?');

  668 //_serialPort.ExpectedHeaders = expHdr;

  669 //_serialPort.ExpectedFooters = expFtr;

  670 //_serialPort.HeaderRecvError +=

  671 // new EventHandler<CgSerialPortEventArgs>(_serialPort_HeaderRecvError);

  672 //_serialPort.FooterRecvError +=

  673 // new EventHandler<CgSerialPortEventArgs>(_serialPort_FooterRecvError);

  674 

  675 if (_serialPort.Start())

  676 {

  677 _continue = true;

  678 

  679 Console.Write("Name: ");

  680 name = Console.ReadLine();

  681 

  682 Console.WriteLine("Type QUIT to exit");

  683 

  684 while (_continue)

  685 {

  686 message = Console.ReadLine();

  687 

  688 if (stringComparer.Equals("quit", message))

  689 {

  690 _continue = false;

  691 }

  692 else

  693 {

  694 Console.WriteLine("XMIT:" + message);

  695 _serialPort.WriteLine(message);

  696 }

  697 }

  698 

  699 _serialPort.Stop();

  700 }

  701 else

  702 {

  703 Console.ReadLine();

  704 }

  705 }

  706 

  707 static void _serialPort_MessageRecvError(object sender, CgSerialPortEventArgs e)

  708 {

  709 Console.WriteLine("Msg RECV error" + e.Message);

  710 }

  711 

  712 static void _serialPort_FooterRecvError(object sender, CgSerialPortEventArgs e)

  713 {

  714 Console.WriteLine("Ftr RECV error" + e.Message);

  715 }

  716 

  717 static void _serialPort_HeaderRecvError(object sender, CgSerialPortEventArgs e)

  718 {

  719 Console.WriteLine("Hdr RECV error" + e.Message);

  720 }

  721 

  722 static void _serialPort_PortError(object sender, CgSerialPortEventArgs e)

  723 {

  724 Console.WriteLine( e.Message);

  725 }

  726 

  727 static void _serialPort_MessageReceived(object sender, CgSerialPortEventArgs e)

  728 {

  729 Console.WriteLine("RECVMSG:" + e.Message);

  730 }

  731 

  732 static void _serialPort_FooterReceived(object sender, CgSerialPortEventArgs e)

  733 {

  734 Console.WriteLine("RECVFTR:" + e.Message);

  735 }

  736 

  737 static void _serialPort_HeaderReceived(object sender, CgSerialPortEventArgs e)

  738 {

  739 Console.WriteLine("RECVHDR:" + e.Message);

  740 }

  741 

  742 

  743 public static string SetPortName(string defaultPortName)

  744 {

  745 string portName;

  746 

  747 Console.WriteLine("Available Ports:");

  748 foreach (string s in SerialPort.GetPortNames())

  749 {

  750 Console.WriteLine(" {0}", s);

  751 }

  752 

  753 Console.Write("COM port({0}): ", defaultPortName);

  754 portName = Console.ReadLine();

  755 

  756 if (portName == "")

  757 {

  758 portName = defaultPortName;

  759 }

  760 return portName;

  761 }

  762 

  763 public static int SetPortBaudRate(int defaultPortBaudRate)

  764 {

  765 string baudRate;

  766 

  767 Console.Write("Baud Rate({0}): ", defaultPortBaudRate);

  768 baudRate = Console.ReadLine();

  769 

  770 if (baudRate == "")

  771 {

  772 baudRate = defaultPortBaudRate.ToString();

  773 }

  774 

  775 return int.Parse(baudRate);

  776 }

  777 

  778 public static Parity SetPortParity(Parity defaultPortParity)

  779 {

  780 string parity;

  781 

  782 Console.WriteLine("Available Parity options:");

  783 foreach (string s in Enum.GetNames(typeof(Parity)))

  784 {

  785 Console.WriteLine(" {0}", s);

  786 }

  787 

  788 Console.Write("Parity({0}):", defaultPortParity.ToString());

  789 parity = Console.ReadLine();

  790 

  791 if (parity == "")

  792 {

  793 parity = defaultPortParity.ToString();

  794 }

  795 

  796 return (Parity) Enum.Parse(typeof(Parity), parity);

  797 }

  798 

  799 public static int SetPortDataBits(int defaultPortDataBits)

  800 {

  801 string dataBits;

  802 

  803 Console.Write("Data Bits({0}): ", defaultPortDataBits);

  804 dataBits = Console.ReadLine();

  805 

  806 if (dataBits == "")

  807 {

  808 dataBits = defaultPortDataBits.ToString();

  809 }

  810 

  811 return int.Parse(dataBits);

  812 }

  813 

  814 public static StopBits SetPortStopBits(StopBits defaultPortStopBits)

  815 {

  816 string stopBits;

  817 

  818 Console.WriteLine("Available Stop Bits options:");

  819 foreach (string s in Enum.GetNames(typeof(StopBits)))

  820 {

  821 Console.WriteLine(" {0}", s);

  822 }

  823 

  824 Console.Write("Stop Bits({0}):", defaultPortStopBits.ToString());

  825 stopBits = Console.ReadLine();

  826 

  827 if (stopBits == "")

  828 {

  829 stopBits = defaultPortStopBits.ToString();

  830 }

  831 

  832 return (StopBits) Enum.Parse(typeof(StopBits), stopBits);

  833 }

  834 

  835 public static Handshake SetPortHandshake(Handshake defaultPortHandshake)

  836 {

  837 string handshake;

  838 

  839 Console.WriteLine("Available Handshake options:");

  840 foreach (string s in Enum.GetNames(typeof(Handshake)))

  841 {

  842 Console.WriteLine(" {0}", s);

  843 }

  844 

  845 Console.Write("Handshake({0}):", defaultPortHandshake.ToString());

  846 handshake = Console.ReadLine();

  847 

  848 if (handshake == "")

  849 {

  850 handshake = defaultPortHandshake.ToString();

  851 }

  852 

  853 return (Handshake) Enum.Parse(typeof(Handshake), handshake);

  854 }

  855 }



Let me know how you think the codes helped you ... :)

7 comments:

  1. which compiler should I use to successfully use this code? I have MS Visual C/C++ v.1.52 for DOS and Windows. Can I use the code and make an exe file with my compiler? Or should I go and get MS Visual Studio .Net 2003 Professional?
    my e-mail: gk1@onet.eu

    ReplyDelete
  2. You will need Visual studio 2005 or above to compile this code. Check http://www.microsoft.com/exPress/download/.

    ReplyDelete
  3. Dear Sir,

    Which is better for this project:
    Visual Studio 2005 Standard or Visual Studio 2005 Professional?

    Best regards

    Greg Krupinski

    ReplyDelete
  4. Greg,

    You could use any of these editions. They are equally good. VS 2005 Pro just gives you a few more options. See http://msdn.microsoft.com/en-us/vstudio/aa700921.aspx for comparison.

    Thx

    ReplyDelete
  5. Dear Praveen,

    Do you have any simple C/C++ program for RS232 port that could be compiled with MS VC/C++ ver.1.52 for DOS/Windows.
    I prefer Microsoft, since this was my first compiler, and I still use it for simple programming under DOS and Windows 98.
    There must be a way of using either simple assembler code with direct register handling, or making simple functions to control the serial ports without much of a headache.
    =====================================================================================================
    Have you ever tried to do it with Borland Turbo Pascal, Borland Pascal 7.0, Borland Delphi or Borland C++ 4.2 all for DOS/Win'98?
    I will appreciate any suggestions from your experience.

    All I need is a simple connection between the screen (DOS/Win'98)) or Windows Form(Windows XP) and the RS232 port with writing all bytes to a text datafile as long as the port is open and data is received - all written in C/C++ (MS Visual C/C++ 5.0 or MSVC/C++ 1.52)

    I have bought the MS Visual Studio 2003 .Net Professional a year ago, but I could not find any SerialPort Component in it, and they told me it was included with Visual Studio 2005 Professional. So now I either use old DOS machine with good old compiler for DOS?Win'98 or I need to buy the whole MSVS 2005 Pro.

    Next I will need to receive, send confirmation character (or string) to the port and then receive the next record from the serial device connected to the serial port.

    I had many modules like this in the past, but they told me they were obsolete, and the old computer was scrapped.

    After many years of working with ready made applications I see the need to recover old programming solutions for simple dataloggers etc. with RS232 ports.

    Many old programs written with MSVC/C++ 1.52 for Windows 98 are running successfully under Windows XP, so I would very much tru to continue with the simple compiler and use it for RS232 programming (under Windows XP).

    Is this possible?

    Thank you for you help

    Greg

    ReplyDelete
  6. Hi Greg,

    I am sure, at some point I had written a small piece of code for VS 2003 when there was no serial port support in .Net. I can't find it right now. If I do, I'll send it to you or publish it on my blog. I would suggest at this time to see the following links which I think might help you:

    For VS2003:

    * http://msdn.microsoft.com/en-us/magazine/cc301786.aspx
    * http://www.lvr.com/serport.htm


    For Borland C++:

    * http://www.activexperts.com/activcomport/howto/cppbuilder/
    * http://www.daniweb.com/forums/thread56329.html#
    * http://simpleserial.com/


    Hope this helps. Good luck!

    -Praveen

    ReplyDelete
  7. Unfortunate the .NET 2.0/3.4 seems to have lots of known problems with handling the serial!

    I found this article:
    http://www.innovatic.dk/knowledg/SerialCOM/SerialCOM.htm

    Thats really sad.

    Im not sure how it would work with the old WIN32 API calls and than write an wrapper class ??

    Im planning to use serial-232 for a datalogger, but im not sure anymore if it can be trusted in WIN32 at all!

    ReplyDelete

Please leave your opinion...