Wednesday, May 31, 2017

Programming serial port in C++ for Windows, Mac and Linux

I have developed a class library 'ceSerial.h' to use serial port (com port) on Windows, Mac and Linux. This cross-platform 'ceSerial' class is written in C++ and we just need to include "ceSerial.h" in your source code in order to use it. A simple example for C++ console program using the class is demonstrated. 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 'ceSerial' class is shown below.
// File: test.cpp
// Description: Serial communication console program for Windows and Linux
// WebSite: http://cool-emerald.blogspot.sg/2017/05/serial-port-programming-in-c-with.html
// MIT License (https://opensource.org/licenses/MIT)
// Copyright (c) 2018 Yan Naing Aye

#include < stdio.h >
#include "ceSerial.h"
using namespace std;

int main()
{
#ifdef CE_WINDOWS
	ceSerial com("\\\\.\\COM1",9600,8,'N',1); // Windows
#else
	ceSerial com("/dev/ttyS0",9600,8,'N',1); // Linux
#endif

	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");
	ceSerial::Delay(3000); // delay 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 "ceSerial.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 "test.cpp", can be compiled and run on Ubuntu Linux using the following commands.
g++ test.cpp -o test -std=c++11
sudo ./test

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

The source code also include an example GUI application - test_gui.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++ test_gui.cpp `wx-config --cxxflags --libs` -o test_gui
sudo ./test_gui


For the above commands to work, there should be wxWdigets installed in the machine. And installing wxWidgets on Linux is straightforward.
sudo apt update
sudo apt install build-essential libwxgtk3.0-gtk3-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.