Wednesday, May 31, 2017

Programming serial port in C++ with wxWidgets for Windows and Linux

I have developed a class library 'Serial.h' to use serial port (com port) on both Windows and Linux. This cross-platform 'Serial' class is written in C++. A simple example for C++ console program using the class is demonstrated. As an another example, using it with wxWidgets for GUI application is also presented. The source code can be found at

https://github.com/yan9a/serial


Figure. A wxWidgets GUI application using 'Serial' class with Visual Studio 2017


A simple example console program using 'Serial' class is shown below.
#include
#include "Serial.h"
using namespace std;
int main()
{
 Serial com("\\\\.\\COM1",9600,8,'N',1); //Windows
 //Serial com("/dev/ttyS0",9600,8,'N',1); //Linux
 printf("Opening port %s.\n",com.GetPort().c_str());
 if (com.Open() == 0) {printf("OK.\n");}
 else {printf("Error.\n");return 1;}

 bool successFlag;
 printf("Writing.\n");
 char s[]="Hello";
 successFlag=com.Write(s);//write string
 successFlag=com.WriteChar('!');//write a character

 printf("Waiting 3 seconds.\n");
 delay(3000);//delay 5 sec to wait for a character

 printf("Reading.\n");
 char c=com.ReadChar(successFlag);//read a char
 if(successFlag) printf("Rx: %c\n",c);

 printf("Closing port %s.\n",com.GetPort().c_str());
 com.Close();
 return 0;
}

The statement #include "Serial.h" is declared to use the class. Then, an object called 'com' is declared with settings for the port. For this example, it will be COM1 on Windows and ttyS0 on Linux. For a USB device on Linux, the port name may be ttyUSB0. For parity, it can be 'N','E','O','M', or 'S' for none, even, odd, mark, or space respectively.
The com port is opened using com.Open() statement. Use Write or WriteChar methods to send a null terminated string or a character from the serial port. ReadChar method reads a character from the serial port in non-blocking way. If there is no received character, the successFlag will be false. Close method closes the com port. It is also possilbe to control RTS and DTR lines. Status lines such as CTS and DSR can also be read.
The above example program "serialcon.cpp", can be compiled and run on Ubuntu Linux using the following commands.
g++ serialcon.cpp Serial.h -o serialcon
sudo ./serialcon

On Windows, it can be complied and run with Visual Studio or a compiler such as tdm-gcc, mingw as follows.
g++ serialcon.cpp Serial.h -o serialcon.exe -std=c++11
.\serialcon.exe

The source code also include an example wxWidgets GUI application - wxserial.cpp. The figure above illustrates using it with Visual C++ 2017.
Without modifying, this program can also be built and run on Ubuntu (16.04 in my case) using the following commands.
g++ wxserial.cpp Serial.h wx-config --cxxflags --libs -o wxserial -DNDEBUG
sudo ./wxserial


For the above commands to work, there should be wxWdigets installed in the machine. And installing wxWidgets on Linux is straightforward.
sudo apt-get install build-essential
sudo apt-get install libwxgtk3.0-dev


Running serial application on Ubuntu


The following links are about using wxWidgets and using PC serial port with VB6 and Visual Basic 2005.

Related posts:

6 comments:

  1. Hello,

    how can I display the data in Hexa?

    Thanks

    ReplyDelete
  2. The following code should work

    void ComPrintHex(unsigned char ch)
    {
    unsigned char a;
    a=(ch >> 4) | 0x30;
    if(a>0x39) a+=7;
    Putch(a);
    a=(ch & 0x0F) | 0x30;
    if(a>0x39) a+=7;
    Putch(a);
    }

    Some example VB code can be seen at
    http://cool-emerald.blogspot.sg/2009/03/string-and-ascii-code-conversion.html

    ReplyDelete
  3. Can the ReadChar function be executed in another thread as the Open call ?
    All read operations would be in the same thread, so ReadChar is not interrupted by another ReadChar.
    The use case is to read the data, decode messages and generate events out of it.

    ReplyDelete
    Replies
    1. Yes, that should be ok. I also intend to use it in that way.

      Delete
  4. How do you define the 250ms value, here:

    m_timer.Start(250);

    I'm using a 38400 baud rate, is that important?

    thank you!

    ReplyDelete
    Replies
    1. It is not important. It is an interval to check serial buffer regularly. You can change it to a faster interval to suit your need.

      Delete

Comments are moderated and don't be surprised if your comment does not appear promptly.