- writing and reading to/from a serial port with a timeout in c++ and Linux
- 2 Answers 2
- Summary If you have never touched serial port programming, this short article may not be suitable for you^_^
- The difference between O_NDELAY and O_NOBLOCK
- There is one thing to note!
- Switch between blocking state and non-blocking state
- Used in non-blocking state
- Used in blocking state
- 2015-01-21 added:
- Linux serial port timeout
writing and reading to/from a serial port with a timeout in c++ and Linux
To be clear: I’m searching for the most simple way to achieve this.
Sorry if my question is dumb, but im new to this topic, thanks in advance!
EDIT: Sorry that I forgot to mention, it should run on Linux.
well, okay. but as its written in the file: If data are not received, this function will hang because no timeouts were set. — i think thats my biggest problem.
2 Answers 2
this should be similar to your declaration:
Setup(CSerial::EBaud9600,CSerial::EData8,CSerial::EParNone,CSerial::EStop1); Setup(CSerial::EBaudrate(9600), CSerial::EDataBits(8), CSerial::EParity(NOPARITY), CSerial::EStopBits(ONESTOPBIT));
// Read data, until there is nothing left DWORD dwBytesRead = 0; BYTE abBuffer[100]; do < // Read data from the COM-port serial.Read(abBuffer,sizeof(abBuffer),&dwBytesRead); if (dwBytesRead >0) < // TODO: Process the data >> while (dwBytesRead == sizeof(abBuffer));
Please note: I am used to programming serial ports in c#, and so (to the best of my knowledge) believe this would work for you. (I would also like to point outall serial port communication is send actually through as hex, but may be read via the buffer as a decimal value ( please refer to http://www.asciitable.com/ for converstion, or use something similar to UTF8 encoding)
EDIT — As per comment;
Write timeout will be similar to;
[BrowsableAttribute(true)] public: property int WriteTimeout
Which allows you to get or set the timeout attribute
Full Program
public: static void Main() < String^ name; String^ message; StringComparer^ stringComparer = StringComparer::OrdinalIgnoreCase; Thread^ readThread = gcnew Thread(gcnew ThreadStart(PortChat::Read)); // Create a new SerialPort object with default settings. _serialPort = gcnew SerialPort(); // Allow the user to set the appropriate properties. _serialPort->PortName = SetPortName(_serialPort->PortName); _serialPort->BaudRate = SetPortBaudRate(_serialPort->BaudRate); _serialPort->Parity = SetPortParity(_serialPort->Parity); _serialPort->DataBits = SetPortDataBits(_serialPort->DataBits); _serialPort->StopBits = SetPortStopBits(_serialPort->StopBits); _serialPort->Handshake = SetPortHandshake(_serialPort->Handshake); // Set the read/write timeouts _serialPort->ReadTimeout = 500; _serialPort->WriteTimeout = 500; _serialPort->Open(); _continue = true; readThread->Start(); Console::Write("Name: "); name = Console::ReadLine(); Console::WriteLine("Type QUIT to exit"); while (_continue) < message = Console::ReadLine(); if (stringComparer->Equals("quit", message)) < _continue = false; >else < _serialPort->WriteLine( String::Format(">: ", name, message) ); > > readThread->Join(); _serialPort->Close(); > static void Read() < while (_continue) < try < String^ message = _serialPort->ReadLine(); Console::WriteLine(message); > catch (TimeoutException ^) < >> >
Please refer to Linux Serial Port: Blocking Read with Timeout where this has been declared in the question and some of the answers may prove useful to you as well! 🙂
Summary If you have never touched serial port programming, this short article may not be suitable for you^_^
As we all know, all devices under Linux system exist in the form of files, and the serial port is the same.
Usually I/O operations are in two ways, blocking and non-blocking.
The concept of «timeout» is actually a processing method in blocking, and the essence is still a blocking I/O mode.
IO operation of serial port in Linux This article divides it into three states:
There are several combinations of these three states:
First, when the descriptor of a serial port is opened, specify whether its mode is blocking or blocking
fd = open("/dev/tttyS0",O_RDWR | O_NOCTTY);//Open the serial port in blocking mode fd = open("/dev/tttyS0",O_RDWR | O_NOCTTY | O_NDELAY);//Open the serial port in non-blocking mode //Some places use fd = open("/dev/tttyS0",O_RDWR | O_NOCTTY | O_NOBLOCK);
Quote «Advanced Programming in UNIX Environment» (Second Edition):
O_NOCTTY: O_NOCTTY If p a t h n a m e refers to a terminal device, then this device is not allocated as the controlling terminal of this process
The difference between O_NDELAY and O_NOBLOCK
The earlier version of the system V introduced the O _ N D E L AY (no delay) flag, which is the same as O _ N O N B L O C K
(No blocking) The options are similar, but they are ambiguous in the return value of the read operation. If you can’t get from the pipeline,
F I F O or the device reads the data, then the option is not delayed so that r e a d returns to 0, which is the same as the one that means the end of the file has been read
The return value 0 conflicts. SV R 4 still supports this semantic non-delay option, but new applications should
Use the non-blocking option instead.
When a serial port is blocked, it can be set to a timeout state.
Use the cc_t c_cc[NCCS] member of struct termios
- C_cc[VTIME] Timeout time when reading in non-standard mode (unit:Hundred milliseconds)
- C_cc[VMIN] The minimum number of characters when reading in non-standard mode
If you need to set a timeout, c_cc[VMIN]Must be equal to 0
This means that the smallest character that can be read is 0, that is, use read to read data overtime, read returns 0
There is one thing to note!
When c_cc[VTIME] is set to 0 and c_cc[VMIN] == 0, it meansTimeout 0 seconds (let’s call it so!)
At this time, using read to read the data will return immediately (the number of bytes is returned when the data is read, and the return is 0 if there is no data)
Although at this timePhenomenallyIt looks the same as non-blocking mode (read will not block) but the return value is different
- Non-blocking mode: read returns -1 if no data is read
- When the timeout is 0 seconds: read does not read the data and immediately returns 0 (the timeout blocking mode is set)
ret = read(fd,recvbuf,BUF_SIZE); if(ret == -1)//"No data returned" in non-blocking mode //do something > ret = read(fd,recvbuf,BUF_SIZE); if(ret == 0)//The blocking mode is set to "return over time" when the timeout is 0 seconds //do something >
supplement: Modify c_cc[VMIN] and c_cc[VTIME] in non-blocking mode
If inNon-blocking modeModify
When c_cc[VMIN] is 0 and c_cc[VTIME] is also 0, read without data will return 0 (the phenomenon is the same as «timeout 0 seconds»)
At this time, if any item in c_cc[VMIN] or c_cc[VTIME] is modified to >0, then read returns -1. To
Although the form of expression is the same, you must understand which mode you are using and the current state of the serial port during programming to better analyze and deal with problems.
Here is a problem I have encountered:
I opened the serial port in blocking mode, but did not set the value of c_cc[VMIN], and it was 0 after initialization, so I found that the serial port was not blocked. In fact, the reason is that the serial port mode or the blocking mode is correct, but it is timeout 0 The status is seconds, so read returns when no data arrives. To
Regarding the values and phenomena of c_cc[VMIN] and c_cc[VTIME] in blocking mode, hereinafter referred to as VMIN and VTIME
These two values have these combinations
The timeout is calculated when the first byte is received.
If the timeout period has not expired but the data has reached VMIN reads, it returns immediately.
If the timeout period expires, the number currently read will be returned.
Switch between blocking state and non-blocking state
Used in non-blocking state
flag = fcntl(fd,F_GETFL); //Get the original file status first (assuming that the function executes successfully and returns the file status) flag &= ~O_NONBLOCK; //Remove non-blocking flag fcntl(fd,F_SETFL,flag); //Set new file status
Use the above method to convert to a blocking state, and then you can set the timeout.
If the timeout has been set in the non-blocking state, the timeout will take effect after the transition to the blocking state.
Used in blocking state
flag = fcntl(fd,F_GETFL); //Get the original file status first (assuming that the function executes successfully and returns the file status) flag |= O_NONBLOCK; //Increase the blocking flag fcntl(fd,F_SETFL,flag); //Set new file status
Use the above method to convert to a non-blocking state, and the timeout effect is invalid.
You can also use the following methods to set to non-blocking state:
fcntl(fd,F_SETFL,FNDELAY); //Some codes use fcntl(fd,F_SETFL,FNONBLOCK);
Here are the definitions of several macros in the header file
gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5)
/* Define some more compatibility macros to be backward compatible with BSD systems which did not managed to hide these kernel macros. */ #ifdef __USE_BSD # define FAPPEND O_APPEND # define FFSYNC O_FSYNC # define FASYNC O_ASYNC # define FNONBLOCK O_NONBLOCK # define FNDELAY O_NDELAY #endif /* Use BSD. */
/* open/fcntl - O_SYNC is only implemented on blocks devices and on files located on a few file systems. */ #define O_ACCMODE 0003 #define O_RDONLY 00 #define O_WRONLY 01 #define O_RDWR 02 #define O_CREAT 0100 /* not fcntl */ #define O_EXCL 0200 /* not fcntl */ #define O_NOCTTY 0400 /* not fcntl */ #define O_TRUNC 01000 /* not fcntl */ #define O_APPEND 02000 #define O_NONBLOCK 04000 #define O_NDELAY O_NONBLOCK #define O_SYNC 04010000 #define O_FSYNC O_SYNC #define O_ASYNC 020000
The following conclusions can be drawn:
O_NDELAY == O_NONBLOCK == 0x4000
The above method of setting non-blocking mode in the final analysis is to add O_NONBLOCK a non-blocking sign to the file status.
2015-01-21 added:
If the data is not read immediately when calling read in non-blocking mode, -1 will be returned immediately, and the error message is (Resource temporarily unavailable)
Moreover, the data read later may be the data read the previous time, resulting in the previous data being read every time.
Linux serial port timeout
The default blocking mode is not practical when using serial communication under Linux. The non-blocking mode using the SELECT or EPOLL mechanism is more troublesome. Fortunately, Linux’s serial ports have a timeout mechanism.
Use the interfaces in Termios.h under Linux for serial port settings. The setting of specific baud rates, data bits, and the like are not described in detail, there are many Baidu.
Timeout setting is performed using Termios.h, mainly to configure two fields of VTIME and VMIN. Where vTIME specifies the waiting time (timeout = vTIME * 100ms), VMIN specifies the minimum number of read characters.
Note that these two fields must take effect, and the serial port must be operated in non-standard mode. . You can set it to the RAW mode (one of the standard modes, more for communication):
/* struct termio newtio; */
newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /*Input*/ newtio.c_oflag &= ~OPOST; /*Output*/
VTIME and VMIN need to be used, their combination is as follows:
1, vTIME = 0, vmin = 0: The function read will return even if any data is not read, the return value is 0.
2, vtime = 0, VMIN> 0: Read call has been blocked until it returns immediately after reading the VMIN characters.
3, VTIME> 0, vmin = 0: Read call Reads to return immediately, otherwise you will wait for VTIME * 100ms for each character.
4, vTIME> 0, VMIN> 0: Read call will keep blocked until the first character is read, After reading the first character, start timing After that, if the time has arrived at VTIME * 100ms or time, the VMIN is read, the VMIN is returned. If a character is read again (but the total number read at this time is still not VMIN), the timing restart (ie each character has timeout timeout time).