I'm using a digital scale connected to the rs232 port on the back of my pc with under Ubuntu. The application is written in WxWidgets and C/C++ and it works very well even if I found out that sometimes the code stucks immediately before the while() loop without throwing any errors, it just get stuck and nothing happens. Then I run again the code and it works fine.
The device connected to the serial port is a digital scale and it works in this way when it receives READ<CR><LF>
01ST,GS, 0.0,kg<CR><LF>
where
01 code to use only for 485 communications
ST scale status:
US - measurement not stable
ST - measurement stable
OL - overload weight
UL - underload weight
TL - scale non balanced
, ASCII 044
GS Tipo di dato di peso (2 chars)
, ASCII 044
0.0 weight
, ASCII 044
kg measurement unit (2 caratteri)
<CR><LF> end of packet ASCII 013 e ASCII 010
Why the serial read gets stuck sometimes?
Sometimes, it prints "Entering the while loop..
" and nothing else then I need to send CTRL+c to quit the process.
Is there any way to detect if the while() loop is not working in order to skip the operation?
Can it be related to the parameters of the serial port?
This is my code (minimal working code for tests):
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <ctype.h>
double get_double(const char *str)
{
/* First skip non-digit characters */
/* Special case to handle negative numbers and the `+` sign */
while (*str && !(isdigit(*str) || ((*str == '-' || *str == '+') && isdigit(*(str + 1)))))
str++;
/* The parse to a double */
return strtod(str, NULL);
}
char buf[80] = {'\0' }; // buffer is zero'ed
int set_interface_attribs(int fd, int speed)
{
struct termios tty;
if (tcgetattr(fd, &tty) < 0) {
printf("Error from tcgetattr: %s\n", strerror(errno));
return -1;
}
cfsetospeed(&tty, (speed_t)speed);
cfsetispeed(&tty, (speed_t)speed);
tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8; /* 8-bit characters */
tty.c_cflag &= ~PARENB; /* no parity bit */
tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
tty.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */
/* setup for non-canonical mode */
tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
tty.c_oflag &= ~OPOST;
/* fetch bytes as they become available */
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 1;
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
printf("Error from tcsetattr: %s\n", strerror(errno));
return -1;
}
return 0;
}
void set_mincount(int fd, int mcount)
{
struct termios tty;
if (tcgetattr(fd, &tty) < 0) {
printf("Error tcgetattr: %s\n", strerror(errno));
return;
}
tty.c_cc[VMIN] = mcount ? 1 : 0;
tty.c_cc[VTIME] = 5; /* half second timer */
if (tcsetattr(fd, TCSANOW, &tty) < 0)
printf("Error tcsetattr: %s\n", strerror(errno));
}
int main()
{
const char *portname = "/dev/ttyS4";
int fd;
int wlen;
printf("Opening the connection on serial port\n");
fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0) {
printf("Error opening %s: %s\n", portname, strerror(errno));
return -1;
}
/*baudrate 9600, 8 bits, no parity, 1 stop bit */
set_interface_attribs(fd, B9600);
//set_mincount(fd, 0); /* set to pure timed read */
/* simple output */
printf("Sending the command READ\n");
wlen = write(fd, "READ\r\n", 6);
if (wlen != 6) {
printf("Error from write: %d, %d\n", wlen, errno);
}
tcdrain(fd); /* delay for output */
int rdlen = 0, total = 0, timeoutcnt = 0;
printf("Entering the while loop..\n");
while ((rdlen = read(fd, &buf[total], sizeof(buf) - total - 1)) >= 0 && total + rdlen < (int)sizeof(buf)) {
if (rdlen == 0) {
// printf("Timeout from read\n");
if (++timeoutcnt > 100)
break;
continue;
}
// printf("%s", buf);
total += rdlen;
if (total > 1 && strcmp(&buf[total-2], "\r\n") == 0)
break;
}
if (rdlen < 0) {
printf("Error from read: total:%d rdlen:%d: %s\n", total, rdlen, strerror(errno));
} else if (total + rdlen >= (int)sizeof(buf)) {
printf("message too long for buffer: total:%d rdlen:%d: %s\n", total, rdlen, buf);
} else if (rdlen == 0) {
printf("Too many timeouts from read. total:%d buf:%s\n", total, buf);
} else {
printf("Success. total:%d rdlen:%d buf:%s\n", total, rdlen, buf);
}
printf("Stringa: %s and number: %f\n", buf, get_double(buf));
}