Reputation: 13
I have been trying to read the responses from a serial temperature sensor interfaced to my raspberry pi using a USB to serial converter.
I can see that the writes to the sensor device seem to work. However when I try to read back from the serial chip the read fails with -1.
I did try to use the same baud rate 9600 8 bit no parity settings using realterm program and was able to read and write hex values as expected, kindly point me in the right direction.
void serial_write(char parameter,char value) {
int fd;
uint8_t bytes_wr;
char wr_buffer[3];
fd = open("/dev/ttyUSB0",O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1)
ERROR("Error! in Opening ttyUSB0 \n");
else
DEBUG("ttyUSB0 Opened Successfully \n");
struct termios SerialPortSettings;
tcgetattr(fd, &SerialPortSettings);
cfsetispeed(&SerialPortSettings,B9600);
cfsetospeed(&SerialPortSettings,B9600);
SerialPortSettings.c_cflag &= ~PARENB;
SerialPortSettings.c_cflag &= ~CSTOPB;
SerialPortSettings.c_cflag &= ~CSIZE;
SerialPortSettings.c_cflag |= CS8;
SerialPortSettings.c_cflag &= ~CRTSCTS;
SerialPortSettings.c_cflag |= CREAD | CLOCAL;
SerialPortSettings.c_iflag &= ~(IXON | IXOFF | IXANY);
SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);
SerialPortSettings.c_oflag &= ~OPOST;
if ((tcsetattr(fd,TCSANOW,&SerialPortSettings)) != 0)
ERROR("ERROR ! in Setting attributes \n");
else
DEBUG("BaudRate=9600\tStopBits=1\tParity=none \n");
wr_buffer[0] = write;
wr_buffer[1] = parameter;
wr_buffer[2] = value;
bytes_wr = write(fd, wr_buffer,sizeof(wr_buffer));
DEBUG("Total Bytes written: %d \n", sizeof(wr_buffer));
close(fd);
}
The above function seems to write as expected to the serial port, however when I try to read, the reads fails with a -1
char serial_read(char parameter) {
int fd, read_length, i;
uint8_t bytes_wr;
char wr_buffer[2];
fd = open("/dev/ttyUSB0",O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1)
ERROR("Error! in Opening ttyUSB0 \n");
else
DEBUG("ttyUSB0 Opened Successfully \n");
struct termios SerialPortSettings;
tcgetattr(fd, &SerialPortSettings);
cfsetispeed(&SerialPortSettings,B9600);
cfsetospeed(&SerialPortSettings,B9600);
SerialPortSettings.c_cflag &= ~PARENB;
SerialPortSettings.c_cflag &= ~CSTOPB;
SerialPortSettings.c_cflag &= ~CSIZE;
SerialPortSettings.c_cflag |= CS8;
SerialPortSettings.c_cflag &= ~CRTSCTS;
SerialPortSettings.c_cflag |= CREAD | CLOCAL;
SerialPortSettings.c_iflag &= ~(IXON | IXOFF | IXANY);
SerialPortSettings.c_iflag &= ~(ICANON | ECHO | ECHOE | ISIG);
SerialPortSettings.c_oflag &= ~OPOST;
if ((tcsetattr(fd,TCSANOW,&SerialPortSettings)) != 0)
ERROR("ERROR ! in Setting attributes \n");
else
DEBUG("BaudRate=9600\tStopBits=1\tParity= none\n");
wr_buffer[0] = read;
wr_buffer[1] = parameter;
bytes_wr = write(fd, wr_buffer,sizeof(wr_buffer));
DEBUG("Total Bytes written: %d \n", sizeof(wr_buffer));
usleep(8000);
tcflush(fd,TCIFLUSH);
char rd_buffer[4];
read_length = read(fd, rd_buffer,sizeof(rd_buffer));
DEBUG("Total bytes read = %d \n",read_length);
for (i==0;i<read_length;i++){
DEBUG("rd_buffer[%d]=%x \n",i,rd_buffer[i]);
}
close(fd);
return rd_buffer[0];
}
With realterm windows application all writes and reads seem to work fine.
Upvotes: 0
Views: 409
Reputation: 19
From the open(2) manpage:
O_NONBLOCK or O_NDELAY
When possible, the file is opened in nonblocking mode.
Neither the open() nor any subsequent operations on the file
descriptor which is returned will cause the calling process to
wait.
For a serial connection, the end result will be that if you ask to read some number of bytes from the serial port and there are no characters waiting, then read will return with -1 and 'errno' will probably be EAGAIN or EWOULDBLOCK.
So your usleep(8000) was probably an attempt to wait long enough for the device to respond but the device may not have data for you; especially if it is in the middle of an adc operation, it might take longer than 8ms.
There are a few things you can do:
You can (in pseudo code):
int retries=10;
while(retries--) {
read_length = read(fd, rd_buffer,sizeof(rd_buffer));
if(read_length > 0)
break;
usleep(1000);
}
Unfortunately, one side effect of this is that if the temperature sensor is sending you a lengthy string and your program read()s while the temperature sensor is still writing, you will get a partial string. So if you know the length of string that you're waiting to receive, you could use an ioctl() to find out how many characters are waiting:
ioctl(fd, FIONREAD, &bytes_avail);
So the pseudo code would look more like:
int retries=10;
int bytes_avail=0;
while(retries--) {
if (ioctl(fd, FIONREAD, &bytes_avail) < 0) {
fprintf(stderr, "ioctl failed\n");
return; // Do something here
}
if (bytes_avail >= sizeof(rd_buffer)) {
read_length = read(fd, rd_buffer,sizeof(rd_buffer));
if(read_length > 0)
break;
}
usleep(1000);
}
If the temperature sensor sends an ascii string that is terminated with a newline or carriage-return, then the code would look different.
Upvotes: 1