How to open, read, and write from serial port in C?
I am a little bit confused about reading and writing to a serial port. I have a USB device in Linux that uses the FTDI USB serial device converter driver. When I plug it in, it creates: /dev/ttyUSB1.
I thought itd be simple to open and read/write from it in C. I know the baud rate and parity information, but it seems like there is no standard for this?
Am I missing something, or can someone point me in the right direction?
2 Answers 2
I wrote this a long time ago (from years 1985-1992, with just a few tweaks since then), and just copy and paste the bits needed into each project.
You must call cfmakeraw on a tty obtained from tcgetattr . You cannot zero-out a struct termios , configure it, and then set the tty with tcsetattr . If you use the zero-out method, then you will experience unexplained intermittent failures, especially on the BSDs and OS X. «Unexplained intermittent failures» include hanging in read(3) .
The values for speed are B115200 , B230400 , B9600 , B19200 , B38400 , B57600 , B1200 , B2400 , B4800 , etc. The values for parity are 0 (meaning no parity), PARENB|PARODD (enable parity and use odd), PARENB (enable parity and use even), PARENB|PARODD|CMSPAR (mark parity), and PARENB|CMSPAR (space parity).
«Blocking» sets whether a read() on the port waits for the specified number of characters to arrive. Setting no blocking means that a read() returns however many characters are available without waiting for more, up to the buffer limit.
CMSPAR is needed only for choosing mark and space parity, which is uncommon. For most applications, it can be omitted. My header file /usr/include/bits/termios.h enables definition of CMSPAR only if the preprocessor symbol __USE_MISC is defined. That definition occurs (in features.h ) with
Reading from Serial Port in linux using C language
I am new to serail programing in Linux (Fedora 12) using C Language. I have a simple device, it is supposed to get 3 bytes command in hex (wirte) like <0x02,0x03,0x0D>and return 4 bytes response.
First I wrote a simple java program on windows, and I get the correct response.. as and when,I switch to linux, I can’t read from serial com port neither using java nor C language.
I tried using libraries like rs232 .. but still the problem remains. I can open «/dev/ttyS0», and write on it .. (none of them returns any Error), but read is not possible ..
If I use canonical mode, the program blocks on reading until i kill the program.. If use non-canonical mode, with VMIN=0 and VTIME=5, read function returns whith -107725432 bytes for example .. (I have tried reading and writing byte by byte or all at the same time .. no difference ..)
I am really confused .. I tried almost every samples on the Internet .. An
y Idea Please?! I have traced the program, using strace ..
mmap2(NULL,4096,PROT_READ|PROT_WRITE, MAP_PRIVATE| MAP_ANONYMOUS,-1,0) = 0Xb78b4000
Reading and writing to serial port in C on Linux
I’m trying to send/receive data over an USB Port using FTDI, so I need to handle serial communication using C/C++. I’m working on Linux (Ubuntu).
Basically, I am connected to a device which is listening for incoming commands. I need to send those commands and read device’s response. Both commands and response are ASCII characters.
Everything works fine using GtkTerm but, when I switch to C programming, I encounter problems.
What happens is that read() returns 0 (no bytes read at all) or block until timeout ( VTIME ). I’m assuming this happens because write() does not send anything. In that case, device wouldn’t receive command and I cannot receive response. In fact, turning off the device while my program is blocked on reading actually succeded in getting a response (device sends something while shutting down).
Strange thing is that adding this
right after write() call, I receive:
which is exactly what I expect. Only my program doesn’t work as it should, like my device cannot receive what I’m actually writing on port.
I’ve tried different things and solution, also regarding data types (I’ve tried using std::string, such as cmd = «INIT \r» or const char ) but nothing really worked.
Can someone tell me where I’m wrong?
Thank you in advance.
EDIT: Previously version of this code used
unsigned char cmd[] = «INIT \n»
and also cmd[] = «INIT \r\n» . I changed it because command sintax for my device is reported as
I’ve also tried avoiding the O_NONBLOCK flag on reading, but then I only block until forever. I’ve tried using select() but nothing happens. Just for a try, I’ve created a waiting loop until data is avaliable, but my code never exit the loop. Btw, waiting or usleep() is something I need to avoid. Reported one is only an excerpt of my code. Complete code needs to work in a real-time environment (specifically OROCOS) so I don’t really want sleep-like function.
Read from serial port linux
I’m trying to read from serial port, but always get 0 (zero) characters back. Already read the «Serial Programming Guide for POSIX Operating Systems», but can’t find out why the program not waiting (blocking). The code:
2 Answers 2
This information was originally from the Serial Programming Guide 1 .
The reason you are getting a 0 return value is because of this line:
If you want a normal blocking read, unset that flag.
You are using O_NDELAY
O_NONBLOCK or O_NDELAY
When possible, the file is opened in non-blocking mode. Neither the open() nor any subsequent operations on the file descriptor which is returned will cause the calling process to wait. For the handling of FIFOs (named pipes), see also fifo(7). For a discussion of the effect of O_NONBLOCK in conjunction with mandatory file locks and with file leases, see fcntl(2).
EDIT: You’re doing the same thing in your fcntl() call, as well.
Not the answer you’re looking for? Browse other questions tagged c serial-port or ask your own question.
Related
Hot Network Questions
Subscribe to RSS
To subscribe to this RSS feed, copy and paste this URL into your RSS reader.
site design / logo © 2020 Stack Exchange Inc; user contributions licensed under cc by-sa. rev 2020.9.18.37632
Linux — serial port read returning EAGAIN
I am having some trouble reading some data from a serial port I opened the following way. I’ve used this instance of code plenty of times and all worked fine, but now, for some reason that I cant figure out, I am completely unable to read anything from the serial port.
I am able to write and all is correctly received on the other end, but the replies (which are correctly sent) are never received (No, the cables are all ok 😉 )
The code I used to open the serial port is the following:
After the port is initializeed I write some stuff to it through simple write command.
where hCom is the file descriptor (and it’s ok), and (as I said) this works. But. when I do a read afterwards, I get a «Resource Temporarily Unavailable» error from errno.
I tested select to see when the file descriptor had something t read. but it always times out!
I read data like this:
and I always get an EAGAIN and I have no idea why.
Update:
The HW is working fine! I can see that there is inbound data on the serial port because I’ve made a debug cable to read whats going on on another terminal. So.
I know what nonblocking should do. My question is. why isn’t anything getting read!. The same setup works fine on windows, so all hardware is working fine.
This is driving me nuts! I’m sure it’s something simple as hell! I even tried getting rid of O_NONBLOCK to see when I would receive something. but nothing.
Linux Serial Ports Using C/C++
Overview
Unluckily, using serial ports in Linux is not the easiest thing in the world. When dealing with the termios.h header, there are many finicky settings buried within multiple bytes worth of bitfields. This page is an attempt to help explain these settings and show you how to configure a serial port in Linux correctly.
Everything Is A File
In typical UNIX style, serial ports are represented by files within the operating system. These files usually pop-up in /dev/ , and begin with the name tty* .
- /dev/ttyACM0 — ACM stands for the ACM modem on the USB bus. Arduino UNOs (and similar) will appear using this name.
- /dev/ttyPS0 — Xilinx Zynq FPGAs running a Yocto-based Linux build will use this name for the default serial port that Getty connects to.
- /dev/ttyS0 — Standard COM ports will have this name. These are less common these days with newer desktops and laptops not having actual COM ports.
- /dev/ttyUSB0 — Most USB-to-serial cables will show up using a file named like this.
- /dev/pts/0 — A pseudo terminal. These can be generated with socat .
A listing of the /dev/ directory in Linux with a connected Arduino. The Arduino serial port is present as /dev/ttyACMO0.
To write to a serial port, you write to the file. To read from a serial port, you read from the file. Of course, this allows you to send/receive data, but how do you set the serial port parameters such as baud rate, parity, e.t.c? This is set by a special tty configuration struct .
Basic Setup In C
First we want to include a few things:
Then we want to open the serial port device (which appears as a file under /dev/ ), saving the file descriptor that is returned by open() :
One of the common errors you might see here is errno = 2 , and strerror(errno) returns No such file or directory . Make sure you have the right path to the device and that the device exists!
Another common error you might get here is errno = 13 , which is Permission denied . This usually happens because the current user is not part of the dialout group. Add the current user to the dialout group with:
You must log out and back in before these group changes come into effect.
At this point we could technically read and write to the serial port, but it will likely not work, because the default configuration settings are not designed for serial port use. So now we will set the configuration correctly.
When modifying any configuration value, it is best practice to only modify the bit you are interested in, and leave all other bits of the field untouched. This is why you will see below the use of &= or |= , and never & or | when setting bits.
Configuration Setup
We need access to the termios struct in order to configure the serial port. We will create a new termios struct, and then write the existing configuration of the serial port to it using tcgetattr() , before modifying the parameters as needed and saving the settings with tcsetattr() .
We can now change tty ‘s settings as needed, as shown in the following sections.
Control Modes (c_cflags)
The c_cflags member of the termios struct contains control parameter fields.
PARENB (Parity)
If this bit is set, generation and detection of the parity bit is enabled. Most serial communications do not use a parity bit, so if you are unsure, clear this bit.
CSTOPB (Num. Stop Bits)
If this bit is set, two stop bits are used. If this is cleared, only one stop bit is used. Most serial communications only use one stop bit.
Number Of Bits Per Byte
The CS fields set how many data bits are transmitted per byte across the serial port. The most common setting here is 8 ( CS8 ). Definitely use this if you are unsure, I have never used a serial port before which didn’t use 8 (but they do exist).
Flow Control (CRTSCTS)
If the CRTSCTS field is set, hardware RTS/CTS flow control is enabled. The most common setting here is to disable it. Enabling this when it should be disabled can result in your serial port receiving no data, as the sender will buffer it indefinitely, waiting for you to be “ready”.
CREAD and CLOCAL
Setting CLOCAL disables modem-specific signal lines such as carrier detect. Is also prevents the controlling process from getting sent a SIGHUP signal when a modem disconnect is detected, which is usually a good thing here. Setting CLOCAL allows us to read data (we definitely want that!).
Local Modes (c_lflag)
Disabling Canonical Mode
UNIX systems provide two basic modes of input, canonical and non-canonical mode. In canonical mode, input is processed when a new line character is received. The receiving application receives that data line-by-line. This is usually undesirable when dealing with a serial port, and so we normally want to disable canonical mode.
Canonical mode is disabled with:
Also, in canonical mode, some characters such as backspace are treated specially, and are used to edit the current line of text (erase). Again, we don’t want this feature if processing raw serial data, as it will cause particular bytes to go missing!
If this bit is set, sent characters will be echoed back. Because we disabled canonical mode, I don’t think these bits actually do anything, but it doesn’t harm to disable them just in case!
Disable Signal Chars
When the ISIG bit is set, INTR , QUIT and SUSP characters are interpreted. We don’t want this with a serial port, so clear this bit:
Input Modes (c_iflag)
The c_iflag member of the termios struct contains low-level settings for input processing. The c_iflag member is an int .
Software Flow Control (IXOFF, IXON, IXANY)
Clearing IXOFF , IXON and IXANY disables software flow control, which we don’t want:
Disabling Special Handling Of Bytes On Receive
Clearing all of the following bits disables any special handling of the bytes as they are received by the serial port, before they are passed to the application. We just want the raw data thanks!
Output Modes (c_oflag)
The c_oflag member of the termios struct contains low-level settings for output processing. When configuring a serial port, we want to disable any special handling of output chars/bytes, so do the following:
Both OXTABS and ONOEOT are not defined in Linux. Linux however does have the XTABS field which seems to be related. When compiling for Linux, I just exclude these two fields and the serial port still works fine.
VMIN and VTIME (c_cc)
VMIN and VTIME are a source of confusion for many programmers when trying to configure a serial port in Linux.
An important point to note is that VTIME means slightly different things depending on what VMIN is. When VMIN is 0, VTIME specifies a time-out from the start of the read() call. But when VMIN is > 0, VTIME specifies the time-out from the start of the first received character.
Let’s explore the different combinations:
VMIN = 0, VTIME = 0: No blocking, return immediately with what is available
VMIN > 0, VTIME = 0: This will make read() always wait for bytes (exactly how many is determined by VMIN ), so read() could block indefinitely.
VMIN = 0, VTIME > 0: This is a blocking read of any number chars with a maximum timeout (given by VTIME ). read() will block until either any amount of data is available, or the timeout occurs. This happens to be my favourite mode (and the one I use the most).
VMIN > 0, VTIME > 0: Block until either VMIN characters have been received, or VTIME after first character has elapsed. Note that the timeout for VTIME does not begin until the first character is received.
VMIN and VTIME are both defined as the type cc_t , which I have always seen be an alias for unsigned char (1 byte). This puts an upper limit on the number of VMIN characters to be 255 and the maximum timeout of 25.5 seconds (255 deciseconds).
“Returning as soon as any data is received” does not mean you will only get 1 byte at a time. Depending on the OS latency, serial port speed, hardware buffers and many other things you have no direct control over, you may receive any number of bytes.
For example, if we wanted to wait for up to 1s, returning as soon as any data was received, we could use:
Baud Rate
Rather than use bit fields as with all the other settings, the serial port baud rate is set by calling the functions cfsetispeed() and cfsetospeed() , passing in a pointer to your tty struct and a enum :
If you want to remain UNIX compliant, the baud rate must be chosen from one of the following:
If you are compiling with the GNU C library, you can forgo these enumerations and just specify an integer baud rate directly, e.g.:
Not all hardware will support all baud rates, so it is best to stick with one of the standard BXXX rates above if you have the option to do so. If you have no idea what the baud rate is and you are trying to communicate with a 3rd party system, try B9600 , then B57600 and then B115200 as they are the most common rates.
For Linux serial port code examples see https://github.com/gbmhunter/CppLinuxSerial.
Saving termios
After changing these settings, we can save the tty termios struct with tcsetattr() :
Reading And Writing
Now that we have opened and configured the serial port, we can read and write to it!
Writing
Writing to the Linux serial port is done through the write() function. We use the serial_port file descriptor which was returned from the call to open() above.
Reading
Reading is done through the read() function. You have to provide a buffer for Linux to write the data into.
Closing
This is a simple as:
Full Example
Issues With Getty
Getty can cause issues with serial communication if it is trying to manage the same tty device that you are attempting to perform serial communications with.
To Stop Getty:
Getty can be hard to stop, as by default if you try and kill the process, a new process will start up immediately.
These instructions apply to older versions of Linux, and/or embedded Linux.
- Load /etc/inittab in your favourite text editor.
- Comment out any lines involving getty and your tty device.
- Save and close the file.
- Run the command
$ init q to reload the /etc/inittab file.
Exclusive Access
It can be prudent to try and prevent other processes from reading/writing to the serial port at the same time you are.
One way to accomplish this is with the flock() system call: