I have a serial app on C that receives data and writes it onto a binary file. The problem is that all the data is the same but when i have 0A on sending side, i have 0D on receiving side. I have set the serial port on raw mode and opened the file with wb option. Any clue how to avoid this? If some code is needed, i'll post it.
thanks
EDIT--------------------------
File opening:
FILE *fout;
fout = fopen(file,"wb");
Serial options:
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
/* To disable software flow control simply mask those bits: */
options.c_iflag &= ~(IXON | IXOFF | IXANY);
options.c_lflag &= ~(ICANON|ECHO|ECHOE|ISIG);
tcsetattr(fd, TCSANOW, &options);
success = 1;
return success;
Writting on the file:
fwrite(buffer,1,n,fout);
----------FIX----------------------
Setting this option fixes the problem :
options.c_oflag &= ~OPOST;
You need to mask off the ICRNL mode which translates the enter (carriage return) key to the newline character. This is on the receiving end, not in your program. There's also a corresponding output mode that might be set on your end, but less likely.
Related
My application is able to communicate with baud rates like 4800, 9600 and 115200 but can't with 14400 or 38400. I have to include asm/termios because I need struct termios2 since I'm going to use c_ispeed and c_ospeed members for any buad rate.
Also the second problem I encounter is that read function doesn't return afterVTIME. Do you know why this happens? Any help is appreciated. Thanks.
#include <asm/termios.h>
int serialDevice = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_SYNC);
serialSettings.baudRate = 4800;
serialSettings.dataBits = 8;
serialSettings.hardwareFlowControl = 0;
serialSettings.parity = 0;
serialSettings.parityOdd = 0;
serialSettings.stopBits = 1;
serialSettings.xonxoff = 1;
setSerialSettings(serialDevice, &serialSettings);
//-------------------------------------------------------
int8_t setSerialSettings(int serialDevice, Serial_Params_t *settings)
{
struct termios2 tty;
memset(&tty, 0, sizeof tty);
// get current serial settings
if (ioctl(serialDevice, TCGETS2, &tty) == -1)
{
sendLog("Can't get serial attributes | setSerialSettings", LOG_TYPE_ERROR);
return FALSE;
}
// baudrate
tty.c_cflag &= ~CBAUD;
tty.c_cflag |= BOTHER;
tty.c_ispeed = MAX(110, MIN(settings->baudRate, MAX_BAUDRATE));
tty.c_ospeed = MAX(110, MIN(settings->baudRate, MAX_BAUDRATE));
// enable input parity check
tty.c_iflag |= INPCK;
// data bits: CS5, CS6, CS7, CS8
tty.c_cflag &= ~CSIZE;
switch (settings->dataBits)
{
case 5:
tty.c_cflag |= CS5;
break;
case 6:
tty.c_cflag |= CS6;
break;
case 7:
tty.c_cflag |= CS7;
break;
case 8:
default:
tty.c_cflag |= CS8;
break;
}
// stop bit
switch (settings->stopBits)
{
case 1:
default:
tty.c_cflag &= ~CSTOPB;
break;
case 2:
tty.c_cflag |= CSTOPB;
}
// parity
if (settings->parity == 1)
tty.c_cflag |= PARENB;
else
tty.c_cflag &= ~PARENB;
// odd/even parity
if (settings->parityOdd == 1)
tty.c_cflag |= PARODD;
else
tty.c_cflag &= ~PARODD;
// flow control
// XON/XOFF
if (settings->xonxoff == 1)
tty.c_iflag |= (IXON | IXOFF | IXANY);
else
tty.c_iflag &= ~(IXON | IXOFF | IXANY);
// enable RTS/CTS
if (settings->hardwareFlowControl == 1)
tty.c_cflag |= CRTSCTS;
else
tty.c_cflag &= ~CRTSCTS;
tty.c_cc[VMIN] = 1; // return read function when receive 1 byte
tty.c_cc[VTIME] = 10; // 1 seconds read timeout (deciseconds)
tty.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines
// non-canonical mode
tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL);
tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
tty.c_oflag &= ~OPOST;
// flush port & apply attributes
tcflush(serialDevice, TCIFLUSH);
if (ioctl(serialDevice, TCSETS2, &tty) == -1)
{
sendLog("Can't set serial attributes | setSerialSettings", LOG_TYPE_ERROR);
return FALSE;
}
return TRUE;
}
My application is able to communicate with baud rates like 4800, 9600 and 115200 but can't with 14400 or 38400.
There is a pretty nice writeup for how custom serial speed setting works here: https://github.com/npat-efault/picocom/blob/master/termios2.txt.
In brief, given a struct termios2 identified by tty, to set both input and output speed to custom values, you must
ensure that tty.c_cflag & CBAUD == BOTHER. You appear to do this correctly.
set the desired output speed in tty.c_ospeed. You do this, too.
either
ensure that (tty.c_cflag >> IBSHIFT) & CBAUD == B0, in which case the output speed will also be used as the input speed, or
ensure that (tty.c_cflag >> IBSHIFT) & CBAUD == BOTHER, in which case tty.c_ispeed will be used as the input speed.
You do not do either of those. I'm uncertain why this would cause incorrect communication for some speeds and not others, but the driver is reputed to play some interesting games with speed settings, and maybe you've stumbled across one.
As for
read function doesn't return after VTIME
I think you have incorrect expectations. You are setting VMIN and VTIME both to nonzero values. In this case, VTIME is the maximum inter-character time, not an overall read timeout. With these settings, a blocking read will wait indefinitely for the first character, then will keep reading subsequent characters, up to the requested number, as long as each one arrives within VTIME deciseconds of the previous one.
If you want an overall timeout on every read() call, then set VMIN to 0, and be prepared for some read() calls to read 0 bytes. As always, read() may also read a positive number of bytes but fewer than requested. That may be more likely to happen in this configuration than in the one you're presently using, depending on your choice of VTIME and the behavior of the peer.
I am writing a Linux driver for my chinese arduino. At one moment I need to change the baud rate. I looked for examples and found that listing:
Listing 2 - Setting the baud rate.
struct termios options;
/*
* Get the current options for the port...
*/
tcgetattr(fd, &options);
/*
* Set the baud rates to 19200...
*/
cfsetispeed(&options, B19200);
cfsetospeed(&options, B19200);
/*
* Enable the receiver and set local mode...
*/
options.c_cflag |= (CLOCAL | CREAD);
/*
* Set the new options for the port...
*/
tcsetattr(fd, TCSANOW, &options);
The next to last line of code has the |= operator. What does it do? I've never seen it before.
options.c_cflag |= (CLOCAL | CREAD);
is generally equivalent to
options.c_cflag = options.c_cflag | (CLOCAL | CREAD);
except options.c_cflag is evaluated only once, which doesn't matter in the above expression, but it would matter if options.c_cflag had any side effects (for example, if it were *options.c_cflag++)
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.
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.
options.c_cflag = ~PARENB;
options.c_cflag |= ~PARENB; // So it will be the only true
I wrote a program that communicate with serial port, using termios, this program will read serial port in non-blocking mode and write response to serial port once it read data. If there is no data read from serial port, the program will do other thing, on next loop, the program read serial port again.
now the question is, after sometimes gone, maybe several minutes, or maybe several hours, the serial port don't respond to my program any more. Even I execute echo 'HB\n' > /dev/ttyUSB0(then the serial port should respond 'HACK'), it doesn't respond any more..
I even don't known when the serial port is 'dead', I don't have any clue.. it 'dead' untimed.
here is my configuration:
/// set local mode options
//tminfo.c_lflag |= ICANON;
tminfo.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
/// set control mode options
tminfo.c_cflag |= (CLOCAL | CREAD);
tminfo.c_cflag |= HUPCL;
// set hardware flow control
tminfo.c_cflag &= ~CRTSCTS;
// set how many bits in a character
tminfo.c_cflag &= ~CSIZE;
tminfo.c_cflag |= CS8;
// set parity mode (default to odd validation), this option (PARENB) will both enable input and output parity checking
tminfo.c_cflag &= ~PARENB; // we don't need prity checking now
/// set input mode options
// set input parity checking
tminfo.c_iflag &= ~INPCK;
tminfo.c_cflag &= ~CSTOPB;
/// set output mode options
tminfo.c_oflag &= ~OPOST;
tminfo.c_cc[VMIN] = 1;
tminfo.c_cc[VTIME] = 1;
/// set line speed, defaults to 38400bps, both for input and output
// this call will set both input and output speed
cfsetspeed(&tminfo, B38400);
It's hard to debug the serial in this situation. I really can't figure out what cause the serial port 'dead' on earth. I'm nearly crazy...
what the possible reason? Any help will be appreciated!
update:
I have wrote some code to the other end of the serial port, when it receive 'HB', it will respond 'HACK'
I have writen some Linux program to comunicate my device. I have "same" my program for Windows ("same" because of it's same logic).
I'm using 8N2 data frame format # 9600 bps, with neither software (XOn/XOff) nor hardware (RTS/CTS) flow control. I don't use DTR, DCD, RI, DSR pins of RS-232 9-pin D-sub. I use only RX and TX pins to communicate with my device.
In Linux I have this part of code:
struct termios PortOpts, result;
int fd; /* File descriptor for the port */
/* Configure Port */
tcgetattr(fd, &PortOpts);
// BaudRate - 9600
cfsetispeed(&PortOpts, B9600);
cfsetospeed(&PortOpts, B9600);
// enable reciever and set local mode, frame format - 8N2, no H/W flow control
PortOpts.c_cflag &= (~(CLOCAL | CREAD | CSIZE | CSTOPB));
PortOpts.c_cflag |= ((CLOCAL | CREAD | CS8 | CSTOPB) & (~PARENB));
PortOpts.c_cflag &= (~CRTSCTS);
// PortOpts.c_cflag &= ~PARENB
// PortOpts.c_cflag |= CSTOPB
// PortOpts.c_cflag &= ~CSIZE;
// PortOpts.c_cflag |= CS8;
// no parity check, no software flow control on input
PortOpts.c_iflag |= IGNPAR;
PortOpts.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY | INPCK);
// raw data input mode
PortOpts.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
// raw data output
PortOpts.c_oflag &= ~OPOST;
// setting timeouts
PortOpts.c_cc[VMIN] = 1; // minimum number of chars to read in noncanonical (raw mode)
PortOpts.c_cc[VTIME] = 5; // time in deciseconds to wait for data in noncanonical mode (raw mode)
if (tcsetattr(fd, TCSANOW, &PortOpts) == 0) {
tcgetattr(fd, &result);
if ( (result.c_cflag != PortOpts.c_cflag) ||
(result.c_oflag != PortOpts.c_oflag) ||
(result.c_iflag != PortOpts.c_iflag) ||
(result.c_cc[VMIN] != PortOpts.c_cc[VMIN]) ||
(result.c_cc[VTIME] != PortOpts.c_cc[VTIME]) ) {
perror("While configuring port1");
close(fd);
return 1;
}
} else {
perror("While configuring port2");
close(fd);
return 1;
};
File descriptor 'fd' is for '/dev/ttyS0' device.
I get that message: While configuring port2: Input/output error
I have a laptop, though I don't have any serial ports except for USB. Is this a reason?
I run program as 'root'.
Sorry for my broken English.
Can you run strace on the program; that will give more specifics of just where the IO error is occurring.
One thing to keep in mind - errno doesn't get reset, so the actual error could be from any system call before the perror.