1

I have been trying to set up a serial port on an Olimex A13 machine with the Linux (Debian Wheezy) operating system. To set up the parameters to set up the UART I am using the termios structure. In my case I am simply setting a parameter = value like below...

options.c_cflag = (CLOCAL | CREAD);

I have also seen example code on the internet that looks like the following...

tcgetattr(fd, &options);

cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
options.c_cflag &= ~( ICANON | ECHO | ECHOE |ISIG );
options.c_iflag &= ~(IXON | IXOFF | IXANY );
options.c_oflag &= ~OPOST;

tcsetattr(fd, TCSANOW, &options);

In the above case it looks like the parameter assignments are using bit-wise operators to set the parameters.
My question is, how are the above assignments interpreted?

For example: How is...

options.c_cflag |= (CLOCAL | CREAD);

interpreted compared to...

options.c_cflag = (CLOCAL | CREAD);   

???

And the same for: How is...

options.c_cflag &= ~PARENB;  

interpreted Compared to...

options.c_cflag = ~PARENB;   

???

Are the termios flags really a set of bits where the parameters correspond to a particular bit location in the flag?
Since these values are being set by parameters (i.e. CLOCAL, CREAD) are the bit wise operators redundant when setting the flag = to the parameters?
If someone can clarify this I would greatly appreciate it.

sawdust
  • 16,103
  • 3
  • 40
  • 50
mikenycz
  • 81
  • 1
  • 1
  • 5
  • From the [Serial Programming Guide for POSIX Operating Systems](http://www.cmrr.umn.edu/~strupp/serial.html#3_1_3): *"Never initialize the c_cflag (or any other flag) member directly; you should always use the bitwise AND, OR, and NOT operators to set or clear bits in the members. Different operating system versions (and even patches) can and do use the bits differently, so using the bitwise operators will prevent you from clobbering a bit flag that is needed in a newer serial driver."* – sawdust Apr 09 '14 at 21:45
  • Defensive programming has taught me that you should always check the return code from all system calls, even "trivial" ones like **tc[gs]etattr()**, for possible errors. Too many tutorials leave these checks out to make the examples easier to read. But what is easy to read is not suitable for real-world programming where anything can and does happen. Take a look at this [sample code](http://stackoverflow.com/questions/12437593/how-to-read-a-binary-data-over-serial-terminal-in-c-program/12457195#12457195) – sawdust Apr 09 '14 at 21:48
  • How to [Set Terminal Modes Properly](http://www.chemie.fu-berlin.de/chemnet/use/info/libc/libc_12.html#SEC237) – sawdust May 10 '14 at 21:18

2 Answers2

3

The termios bits are indeed bits set on an unsigned int wiithin a struct termios (at least on Linux). They are defined in /usr/include/<platform>/bits/termios.h.

How is... options.c_cflag |= (CLOCAL | CREAD); ...interpreted compared to... options.c_cflag = (CLOCAL | CREAD);

|= (CLOCAL | CREAD) will set the requested termios bits additionally to what's already there, while = (CLOCAL | CREAD) will set only the bits you requested resetting everything else to zero (which is plain wrong most likely since it will set e.g. the character size to 5 bits (CS5).

The same with c_cflag &= ~PARENB; against options.c_cflag = ~PARENB. While the former will set only the PARENB flag to zero, the latter will set all bits to 1 except the PARENB flag which will be set to zero - I don't think that's the desired result.

mfro
  • 3,286
  • 1
  • 19
  • 28
0

options.c_cflag = ~PARENB;

options.c_cflag |= ~PARENB; // So it will be the only true

Alex
  • 1