Old data is read from 485 port in Linux environment - c

I am reading data continuously from RS 485 port by C program from a device by the following code. For some reason, obtained data is not the latest data in the device. The changes of data is not reflected when I read data, it gives me old value. After couple of minutes, I get the changed value (since I am continuously reading). If I read the same device by Pytty I get the updated value immediately. So there must be some problem in my code though I couldn't figure it out. Any help would be great!
static int load_serial_port(char *port) //port is 485, port="/dev/ttyS2"/
{
int fd = 0;
fd = open (port, O_RDWR);
if (fd < 0) {
log_error("SerialPort opening failed.");
return -1;
}
struct serial_rs485 rs485conf;
/* Enable RS485 mode: */
rs485conf.flags |= SER_RS485_ENABLED;
/* Set logical level for RTS pin equal to 1 when sending: */
rs485conf.flags |= SER_RS485_RTS_ON_SEND;
/* or, set logical level for RTS pin equal to 0 when sending: */
rs485conf.flags &= ~(SER_RS485_RTS_ON_SEND);
/* Set logical level for RTS pin equal to 1 after sending: */
rs485conf.flags |= SER_RS485_RTS_AFTER_SEND;
/* or, set logical level for RTS pin equal to 0 after sending: */
rs485conf.flags &= ~(SER_RS485_RTS_AFTER_SEND);
/* Set rts delay before send, if needed: */
rs485conf.delay_rts_before_send = 0;
/* Set rts delay after send, if needed: */
rs485conf.delay_rts_after_send = 0;
/* Set this flag if you want to receive data even whilst sending data */
//rs485conf.flags |= SER_RS485_RX_DURING_TX;
if (ioctl (fd, TIOCSRS485, &rs485conf) < 0) {
log_error("SerialPort config failed.");
return -1;
}
struct termios option;
tcgetattr(fd, &option);
cfsetospeed(&option, B9600); /* baud rate */
option.c_cflag &= ~PARENB; /* no parity */
option.c_cflag &= ~CSTOPB; /* 1 stop bit */
option.c_cflag &= ~CSIZE;
option.c_cflag |= CS8 | CLOCAL; /* 8 bits */
option.c_lflag = ICANON; /* canonical mode */
option.c_oflag &= ~OPOST; /* raw output */
tcsetattr(fd, TCSANOW, &option); /* apply the settings */
tcflush(fd, TCOFLUSH);
log_debug("SerialPort loaded fd %d", fd);
return fd;
}
Following is the read function
static void port_read(port_t *s)
{
uint8_t rxBuffer[20];
char portString[20] = "";
double value = 0.0;
if(s->serialPortFd > 0) {
int amount = read(s->serialPortFd, rxBuffer, 100);
int i = 0;
int charindex = 0;
if(amount > 1 ) {
for (i = 0; i< amount; i++) {
if ( isdigit( rxBuffer[i]) || ( (char)rxBuffer[i] == '-' || (char)rxBuffer[i] == '.') ) {
portString[charindex] = (char)rxBuffer[i];
charindex++;
}
}
portString[charindex] = '\0';
sscanf(portString, "%lf", &value); //value is same ???
}
}
memset(rxBuffer, 0, sizeof rxBuffer);
}

Sometimes I feel experts post, comment in this forum without reading questions carefully. I found the correct solution after reading and doing more experiment and that I was expecting to save time.
My reading goes fine with the following changes in my code:
int amount = read(s->serialPortFd, rxBuffer, 20);
tcflush(s->serialPortFd, TCIOFLUSH);
I was missing flashing the file.

Related

Serial POSIX write to the file descriptor at some point seems to halt the program

I have two different programs where one writes to a message queue via mq_send while the other consumes it via mq_receive.
One issue I'm running into is serial write in the Consumer thread seems to cause a hang after some time of writing to a serial port.
The consumer thread was able to receive 51 times before it seems to get hung. When I comment out the serial write part, the program runs fine without any interruption.
Interestingly, I was able to receive more or less messages after modifying MAX_MSG_SIZE value. Also, the man page only talks about the receive buffer size being greater than mq_msgsize.
Does that mean the serial port is getting clogged somehow particularly if the receiver end of the serial port isn't reading the data?
I don't see any errors from any of the functions.
In the actual code, the producer writes to the message queue based on certain intervals defined in the timer and there are overlapping periods where messages are written with really close priximity.
// common.h
#define MAX_MESSAGES 10
#define MAX_MSG_SIZE 72
#define MSG_BUFFER_SIZE MAX_MSG_SIZE + 10
#define QUEUE_PERMISSIONS 0660
#define COMMON_QUEUE "/MSG_QUEUE"
typedef enum
{
LEFT,
RIGHT
} CmdType;
typedef struct
{
CmdType cmd;
uint16_t length;
uint8_t payload[64];
} Pkt;
Consumer
#include "common.h"
int fd; // file descriptor for serial port
static struct mq_attr attr = {.mq_flags = 0, .mq_maxmsg = MAX_MESSAGES, .mq_msgsize = MAX_MSG_SIZE, .mq_curmsgs = 0};
void *Consumer(void *args)
{
uint8_t rcvBuffer[MSG_BUFFER_SIZE];
mqd_t *mqd = (mqd_t *) args;
int ret;
while(1)
{
ret = mq_receive(*mqd, rcvBuffer, sizeof(rcvBuffer), 0);
if (ret == -1)
{
perror ("mq_receive failed");
}
printf ("Received data: %d\n", *rcvBuffer);
// serial write
int sizeWritten = write(fd, rcvBuffer, sizeof(rcvBuffer));
if (sizeWritten < 0)
{
perror ("Write to serial failed");
}
}
}
int UartInit()
{
fd = open("/dev/ttyUSB4", O_RDWR);
if (fd == -1)
{
perror ("Serial port failed to open");
return -1;
}
if(tcgetattr(fd, &tty) != 0)
{
perror("Error from tcgetattr");
return -1;
}
cfsetspeed(tty, B115200); // baud rate to 115200
tty->c_cflag |= CS8;
tty->c_cflag &= ~CSTOPB;
tty->c_cflag |= CRTSCTS; // HW flow control
tty->c_cflag &= ~PARENB;
tty.c_iflag |= ICRNL; // enable translating carriage return to newline on input
tty.c_iflag |= IGNBRK; // ignore break condition
tty.c_iflag &= ~BRKINT;
tty.c_iflag &= ~INPCK; // disable input parity check
tty.c_iflag &= ~PARMRK; // ignore input bytes with parity or framing errors are marked when passed to the program
tty.c_iflag &= ~ISTRIP; // ignore stripping off the 8th bit
tty.c_oflag |= OCRNL; // Map CR to NL on output.
tty.c_oflag |= ONLCR; // Map NL to CR-NL on output.
tty.c_oflag &= ~OPOST; // Disable implementation-defined output processing
tty.c_lflag &= ~ICANON; // Disable canonical mode
tty.c_lflag &= ~ISIG;
tty.c_lflag &= ~IEXTEN; // Disable implementation-defined input processing
tty.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|ECHOCTL|ECHOPRT|ECHOKE);
// settimg serial read blocking behavior
tty.c_cc[VTIME] = 0;
if (tcsetattr(fd, TCSANOW, &tty) != 0)
{
printf("Error %i from tcsetattr: %s\n", errno, strerror(errno));
return -1;
}
return 1
}
int main()
{
mqd_t mqd;
int ret = UartInit();
if ((mqd = mq_open(COMMON_QUEUE, O_RDWR | O_CREAT, QUEUE_PERMISSIONS, &attr)) == -1)
{
perror ("Message queue failed to instantiate");
return -1;
}
if (pthread_create(&consumerTd, NULL, Consumer, (void *) &mqd) != 0)
{
return -1;
}
pthread_join(consumerTd, 0);
return 0;
}
Your code looks like it's enabling flow control on the serial port. If the other end of the connection hasn't indicated that it's ready to accept data, your serial port won't transmit anything. You'll slowly fill up your serial port's transmit buffer and once there's no more space to buffer data, attempting to write more data will either block and wait for space or return an error (in your case, it's the former).
I recommend checking to make sure that both sides of the connection are using the same flow control settings, that your serial cable actually has the flow control pins wired through (many inexpensive ones only wire up the TX/RX/GND lines), and that your serial port supports hardware flow control (USB-to-serial adapters frequently do not). Disabling flow control would avoid the hangup, but you might transmit data when the other side isn't ready to receive it.

Reading a Hex data array byte value from serial port

I have to read a data from Serial port using C program. I am sending Hex array data and the device will response the corresponding response for the request.
I have tried with the GTK+ Serial port Terminal, For Example, if i write data "FC 05 40 2B 15" the device will resturn the response as "FC 05 50 AA 05".
Someone please guide me to get this, i have been trying for so long.
I have attached my code here.
void main()
{
int fd;
struct termios SerialPortSettings;
char write_buffer[512];
int dispense_card[5] = { 0XFC,0X05,0x40,0x2B,0x15 };
//char dispense[7] = {0x02,0x31,0x35,0x44,0x43,0x03,0x02};
int bytes_read = 0;
FILE* lfp;
time_t now;
time(&now);
//lfp = fopen("carddispense.log","a+");
fd = open("/dev/ttyUSB1",O_RDWR | O_NOCTTY);
if(fd == -1)
{
//fprintf(lfp,"\nError! in Opening ttyUSB0 %s", ctime(&now));
printf("\nError in Opening in ttyUSB0\n");
exit(1);
}
else
{ printf("\nttyUSB0 Opened Successfully\n");
//fprintf(lfp,"Card reader has been used %s", ctime(&now));
tcgetattr(fd, &SerialPortSettings); /* save current serial port settings */
cfsetispeed(&SerialPortSettings,B9600); /* Baud rate for read */
cfsetospeed(&SerialPortSettings,B9600);
SerialPortSettings.c_cflag &= PARENB; // No Parity
SerialPortSettings.c_cflag &= ~CSTOPB; //Stop bits = 1
SerialPortSettings.c_cflag &= ~CSIZE; /* Clears the Mask */
SerialPortSettings.c_cflag |= CS8; /* Set the data bits = 8 */
SerialPortSettings.c_cflag &= ~CRTSCTS; /*Turn off hardware based flow control */
SerialPortSettings.c_cflag |= CREAD | CLOCAL; /* Turn on the receiver of the serial port (CREAD) */
SerialPortSettings.c_iflag &= ~(IXON | IXOFF | IXANY); /*Turn off hardware based flow control */
SerialPortSettings.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /* NON Cannonical mode for serial communication */
SerialPortSettings.c_cc[VMIN] = 100; /* Read 128 characters */
SerialPortSettings.c_cc[VTIME] = 0; /* Wait indefinitely */
tcsetattr(fd,TCSANOW,&SerialPortSettings);
int pos =0,percent_count = 0;
int i;
for(i=0;i<5;i++)
{
printf("number = %x\t",dispense_card[i]);
sprintf(write_buffer+(i),"%c", dispense_card[i]);
}
printf("write_buffer%s\n",write_buffer);
//printf("write_buffer length: %d\n",strlen(write_buffer));
write(fd,write_buffer,strlen(write_buffer));
close(fd);
}
}
Try this
char tx_buf[5];
char rx_buf[5];
sprintf(tx_buf, "%c%c%c%c%c",0XFC,0X05,0x40,0x2B,0x15);
write(fd, tx_buf, 5);
while (1) {
int n = read (fd, rx_buf, 5);
if (n > 0) {
for(int i=0; i<n; i++) {
printf("data i: %02X ", rx_buf[i]); // "FC 05 50 AA 05"
}
}
}
close(fd);

Working with linux serial port in C, Not able to get full data

I am working with Linux Serial port written in C. Below is my UART settings
int fd;
struct termios tty_attributes;
fd = open(comport, O_RDWR | O_NOCTTY | O_SYNC | O_NONBLOCK );
if(fd < 0)
{
perror("open comport error.\n");
exit(EXIT_FAILURE);
}
else
{
if(tcgetattr(fd, &tty_attributes) == -1)
{
perror("tcgetattr termios function error.\n");
exit(EXIT_FAILURE);
}
tty_attributes.c_lflag = 0;
tty_attributes.c_oflag = 0;
tty_attributes.c_iflag = 0;
tty_attributes.c_cflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
tty_attributes.c_cflag |= CS8;
tty_attributes.c_cflag |= CLOCAL;
tty_attributes.c_cflag &= ~CREAD;
tty_attributes.c_oflag &= ~OPOST;
tty_attributes.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
tty_attributes.c_cc[VMIN] = SIZE_STR_FRAME;
cfsetospeed(&tty_attributes, BAUDRATE); //setting communication speed and other attributes
cfsetispeed(&tty_attributes, BAUDRATE);
tcflush(fd, TCIOFLUSH);
tcsetattr(fd, TCSANOW, &tty_attributes); //change immediately
return fd;
}
}
And below is my code for Reading the frame
char* frame_read(int fd)
{
char *ret = NULL;
int read_ret_val;
struct timeval time_val;
if (fd < 0)
{
printf("Before read over comm channel, channel must be initialize\n");
exit(EXIT_FAILURE);
}
memset(frame, 0, SIZE);
fd_set rfds; //read file discriptors
int return_val;
FD_SET(fd, &rfds);
setReceiveMode(fd, TRUE);
tcflush(fd, TCIFLUSH);
tcflush(fd, TCOFLUSH); //flush previous values
return_val = select((fd) + 1, &rfds, NULL, NULL, &time_val);
if (return_val == -1)
{
perror("select");
exit(EXIT_FAILURE);
}
else if (return_val)
{
usleep(100 * 1000);
read_ret_val = read(fd, frame, SIZE);
if (read_ret_val < 0)
{
perror("read");
exit(EXIT_FAILURE);
}
ret = frame;
//printf("inside else if of read\n");
}
}
I have one gps module is connected with the UART and when i check with minicom I am getting full frame but when i receive over uart(using this code) I am getting first 16 bytes only.
Can anyone point my mistake.?
Here baud is 9600 , frame is of 64 bytes and SIZE is of 64 bytes.,buffer i took is also 64 bytes. Please forgive me for formating errors if any.
My main.c file
int main(int argc, char *argv[])
{
int i=0,j=0;
char *readb;
unsigned char data[34];
static int fd = -1;
struct struct_base_gps *gps;
int command=0;
char COMM_PORTNAME[13];
strcpy( COMM_PORTNAME, argv[1] );// give the first port number for GPS receiving
if((fd = init_comm_channel(COMM_PORTNAME)) < 0 )
{
exit(EXIT_FAILURE);
printf("port is not opened\n");
}
else
{
printf("port is open for communication:\n");
readb = frame_read(fd);
for (i=0;i<=34;i++)
{
data[i] = *(readb +j);
printf("the data is %x\n",data[i]);
j++;
}
}
close (fd);
}
for SIZE is
#define SIZE 64
and frame is
char frame[64];
Thank you for feedback, I have updated the code.
Also Updating the Frame pics which I am getting on terminal as well as with program. Might It will clear more.
Received the data from UART by program
minicom recived
Looking at The Man
RETURN VALUE
On success, the number of bytes read is returned (zero indicates end
of file), and the file position is advanced by this number. It is
not an error if this number is smaller than the number of bytes
requested; this may happen for example because fewer bytes are
actually available right now (maybe because we were close to end-of-
file, or because we are reading from a pipe, or from a terminal), or
because read() was interrupted by a signal. See also NOTES.
Emphasis mine
So you cannot expect that a whole frame can be retrieved by a single read.
You should loop until all expected chars are received, for example:
int total_rec = 0;
char temp[SIZE];
while( total_rec < SIZE )
{
read_ret_val = read(fd, temp, SIZE);
if (read_ret_val != -1)
{
if ( (total_rec + read_ret_val) >= SIZE)
{
read_ret_val = SIZE - total_rec;
}
memcpy(&frame[total_rec], temp, read_ret_val);
total_rec += read_ret_val;
}
else
{
perror("error reading serial line: ");
}
}
Try with
memset(&tty_attributes,0,sizeof(tty_attributes));
tty_attributes.c_iflag=0;
tty_attributes.c_oflag=0;
tty_attributes.c_cflag=CS8|CREAD|CLOCAL;
tty_attributes.c_lflag=0;
tty_attributes.c_cc[VMIN]=1;
tty_attributes.c_cc[VTIME]=5;
Most GPS modules and serial interfaces for devices in general send you data line by line. For this you can use canonical mode which you have explicitly disabled.
Canonical mode as stated in manual
In canonical mode:
Input is made available line by line. An input line is available when one of the line delimiters is typed (NL, EOL, EOL2; or EOF at the
start of line).
Except in the case of EOF, the line delimiter is included in the buffer returned by read(2).
I post code to set serial interface speed and parity with canonical mode enabled:
int set_interface_attribs(int fd, int speed, int parity)
{
// setup based on stty < /dev/ttyACM0 (cfg.txt) output which
// worked for ABSniffer in pyserial implementation
// otherwise module responded only once for every two prompts
struct termios tty;
int rc;
memset(&tty, 0, sizeof tty);
if (tcgetattr(fd, &tty) != 0)
{
log_info("error from tcgetattr %s\r\n", strerror(errno));
return -1;
}
rc = cfsetospeed(&tty, speed);
if (rc == - 1) return -1;
rc = cfsetispeed(&tty, speed);
if (rc == - 1) return -1;
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
// disable IGNBRK for mismatched speed tests; otherwise receive break
// as \000 chars
tty.c_cc[VMIN] = 0; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_cflag |= (CLOCAL | CREAD); // ignore modem controls,
// enable reading
tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
tty.c_cflag |= parity;
tty.c_cflag &= ~CSTOPB;
// tty.c_iflag |= ICRNL | BRKINT; //ICRNL
tty.c_iflag |= IGNCR;
tty.c_cflag &= ~CRTSCTS;
// tty.c_oflag |= OPOST | ONLCR;
// tty.c_iflag |= ISIG | ICANON | IEXTEN;
tty.c_lflag |= ISIG | IEXTEN | ICANON;
tty.c_lflag &= ~ECHO;
tty.c_cc[VEOF] = 0x0;
tty.c_cc[VEOL] = 0x0;
if (tcsetattr(fd, TCSANOW, &tty) != 0)
{
log_info("error from tcsetattr %s\r\n", strerror(errno));
return -1;
}
return 0;
}
Here is how you use it:
rc = set_interface_attribs(fd, B9600, 0);
From now on data should be available line by line. All the errors and possible return values are explained in read manual. Assuming there are no errors, reading a buffer of some arbitrary size should return either EAGAIN (Resource temporarily unavailable) with return code -1 or bytes to the newline character '\n'.
Your original code has numerous issues which cause it to "getting first 16 bytes only":
The code (as posted) only performs a single read() syscall (rather than continuously loop to read the data from the device).
The input is obviously ASCII text delimited into lines terminated with carriage return and line feed, yet your program uses non-canonical mode to read rather than canonical mode. The assumption by #pbn is confirmed by the minicom output.
Your program uses the serial terminal in non-blocking mode, rather than blocking mode, and resorts to using select() and usleep() calls to wait for the arrival of data.
The termios initialization (besides not being POSIX compliant) has several errors, including improper iflag symbols applied to the cflag member, the character size bits are not cleared with ~CSIZE, and CREAD is not enabled.
Your read routine unnecessarily flushes (i.e. discards) all received but unread data prior to the select() call.
A revised routine for opening and configuring the serial terminal (for blocking canonical mode):
#define BAUDRATE B9600
int init_comm_channel(char *comport)
{
struct termios tty_attributes;
int fd;
fd = open(comport, O_RDWR | O_NOCTTY);
if (fd < 0) {
perror("open comport error.\n");
return (-2);
}
if (tcgetattr(fd, &tty_attributes) == -1) {
perror("tcgetattr termios function error.\n");
return (-3);
}
tty_attributes.c_cflag |= CLOCAL | CREAD;
tty_attributes.c_cflag &= ~CSIZE;
tty_attributes.c_cflag |= CS8; /* 8-bit characters */
tty_attributes.c_cflag &= ~PARENB; /* no parity bit */
tty_attributes.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
tty_attributes.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */
tty_attributes.c_lflag |= ICANON | ISIG; /* canonical input */
tty_attributes.c_lflag &= ~(ECHO | ECHOE | ECHONL | IEXTEN);
tty_attributes.c_iflag &= ~INPCK;
tty_attributes.c_iflag |= IGNCR;
tty_attributes.c_iflag &= ~(INLCR | ICRNL | IUCLC | IMAXBEL);
tty_attributes.c_iflag &= ~(IXON | IXOFF | IXANY); /* no SW flowcontrol */
tty_attributes.c_oflag &= ~OPOST;
cfsetospeed(&tty_attributes, BAUDRATE); //setting communication speed and other attributes
cfsetispeed(&tty_attributes, BAUDRATE);
tcflush(fd, TCIOFLUSH);
if (tcsetattr(fd, TCSANOW, &tty_attributes) < 0) {
perror("tcsetattr function error.\n");
return (-4);
}
return fd;
}
The revised routine for reading a line per syscall:
#define SIZE 64
unsigned char frame[SIZE];
char *frame_read(int fd)
{
int read_ret_val;
if (fd < 0) {
printf("Before read over comm channel, channel must be initialize\n");
exit (EXIT_FAILURE);
}
read_ret_val = read(fd, frame, SIZE - 1);
if (read_ret_val < 0) {
perror("read");
exit (EXIT_FAILURE);
}
frame[read_ret_val] = 0; /* terminate string */
return (frame);
}
A revised main() routine that loops forever:
int main(int argc, char *argv[])
{
int fd;
char *readb;
char com_portname[13] = {0};
if (argc > 1)
strcpy(com_portname, argv[1]); // give the first port number for GPS receiving
if ((fd = init_comm_channel(com_portname)) < 0) {
printf("port is not opened\n");
exit (EXIT_FAILURE);
}
printf("port is open for communication:\n");
do {
readb = frame_read(fd);
while (*readb > 0)
printf("the data is 0x%x\n", *readb++);
printf("The line is: %s", frame);
} while (1); /* loop for another line */
close(fd);
}

Epoll reads wrong bytes

I'm newbie in linux system programming, so be kind please.
I have to read data from serial port (/dev/ttyX) with baudrate 921600 in 8N1 mode with no parity via RS-422.
stty output signals that this baudrate is supported.
So I've decided to call epoll.
Problem is that epoll returns wrong bytes.
Since I have specified messages format I'm trying to debug by verifying incoming data by hands. So I've drawn this:
All messages have 2 bytes crc on the tail.
11 b5 means message start. Message should be 36 bytes in length.
72 b5 is another message start marker. 112 bytes len.
73 b5 is message marker too. 36 bytes.
Please find blue underline: this is good message.
Tiny red + fat red is a bad one.
It is 37 bytes len. I have one extra byte and crc mismatch.
Next good one goes (green).
And next bad one. It is 114 bytes instead of 112 bytes and crc mismatch of course.
Here is my code:
... All necessary includes
#define SERIAL_BAUD 921600
#define MAXEVENTS 1024
int openSerial()
{
struct termios options;
int fd;
if ((fd = open("/dev/ttyUSB0", O_RDWR)) == -1)
{
return -1;
}
if (tcgetattr(fd, &options) < 0)
{
printf("Unable to get options with tcgetattr\n");
return -1;
}
if (cfsetispeed(&options, SERIAL_BAUD) < 0)
{
printf("Unable to set input speed with cfsetispeed\n");
return -1;
}
if (cfsetospeed(&options, SERIAL_BAUD) < 0)
{
printf("Unable to set output speed with cfsetispeed\n");
return -1;
}
cfmakeraw(&options);
//options.c_cflag |= SERIAL_BAUD; // Set Baudrate first time
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~CRTSCTS;
options.c_cflag &= ~ECHO; // Disable echoing of input characters
options.c_cflag &= ~ECHOE;
// set to 8N1
options.c_cflag &= ~PARENB; // no parity
options.c_cflag &= ~CSTOPB; // 1 stop bit
options.c_cflag &= ~CSIZE; // Mask the character size bits
options.c_cflag |= CS8; // 8 data bits
options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
options.c_oflag = 0;
options.c_cc[VTIME] = 2; // inter-character timer
options.c_cc[VMIN] = 1; // blocking read until
if (tcflush(fd, TCIFLUSH) < 0)
{
printf("Unable to flush fd with tcflush\n");
return -1;
}
if (tcsetattr(fd, TCSANOW, &options) != 0)
{
printf("Unable to set options with tcsetattr\n");
return -1;
}
return fd;
}
int main(void)
{
int fd;
int efd;
struct epoll_event event;
struct epoll_event* events;
int length;
unsigned char buff[512];
if ((fd = openSerial()) < 0)
{
printf("Exiting because of openSerial failure\n");
return 1;
}
efd = epoll_create1(0);
event.data.fd = fd;
event.events = EPOLLIN;
if (epoll_ctl(efd, EPOLL_CTL_ADD, fd, &event) < 0)
{
printf("Epoll_ctl error occured\n");
return 1;
}
events = (epoll_event*) calloc(MAXEVENTS, sizeof(event));
for(;;)
{
int n = epoll_wait(efd, events, MAXEVENTS, 5000);
if (n < 0)
{
// No ready descriptors, so wait a bit longer
continue;
}
if(events[0].events & EPOLLIN)
{
length = read(events[0].data.fd, buff, sizeof(buff) / 2);
if(length > 0)
{
printf("\n------MESSAGE START-------\n");
for (int i = 0 ; i < length ; ++i)
{
if (i && i % 16 == 0)
{
printf("\n");
}
printf("%02x ", buff[i]);
}
printf("\n------MESSAGE FINISH-------\n");
}
}
else if(events[0].events & EPOLLOUT)
{
// TODO Write here to serial
}
else if(events[0].events & EPOLLHUP || events[0].events & EPOLLERR)
{
printf("Error occured on serial port\n");
}
else
{
printf("No data whthin 5 seconds.\n");
}
}
free(events);
close(fd);
return 0;
}
Your problem is that read() returns bytes that fail to meet your expectations. I see no reason to believe that epoll has anything to do with that.
I also see no reason to suppose that read() is delivering different bytes than the system received from device /dev/ttyUSB0. If these are different than you expected then I'm inclined to believe that either the device is malfunctioning or your expectations are incorrect (or at least incomplete).

Error errno 11 Resource temporarily unavailable

I am using USB to Uart converter for transmission and reception for my data.
Here is my code for transmission
void main()
{
int USB = open( "/dev/ttyUSB0", O_RDWR | O_NONBLOCK | O_NDELAY);
struct termios tty;
struct termios tty_old;
memset (&tty, 0, sizeof tty);
/* Set Baud Rate */
cfsetospeed (&tty, (speed_t)B9600);
cfsetispeed (&tty, (speed_t)B9600);
/* Setting other Port Stuff */
tty.c_cflag &= ~PARENB; // Make 8n1
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8;
tty.c_cflag &= ~CRTSCTS; // no flow control
tty.c_cc[VMIN] = 1; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_cflag |= CREAD | CLOCAL; // turn on READ & ignore ctrl lines
/* Make raw */
cfmakeraw(&tty);
/* Flush Port, then applies attributes */
tcflush( USB, TCIFLUSH );
/* WRITE */
unsigned char cmd[] = "YES this program is writing \r";
int n_written = 0,spot = 0;
do {
n_written = write( USB, &cmd[spot], 1 );
spot += n_written;
} while (cmd[spot-1] != '\r' && n_written > 0);
The output of my code is same as expacted
YES this program is writing
Now this is my code for reading from UART
/* READ */
int n = 0,spot1 =0;
char buf = '\0';
/* Whole response*/
char response[1024];
memset(response, '\0', sizeof response);
do {
n = read( USB, &buf, 1 );
sprintf( &response[spot1], "%c", buf );
spot1 += n;
} while( buf != '\r' && n > 0);
if (n < 0) {
printf("Error reading %d %s",errno, strerror(errno));
}
else if (n==0) {
printf("read nothing");
}
else {
printf("Response %s",response);
}
}
This reading from Uart gives error from errno and it is error number 11 which says that Resource is temporary unavailable
I am getting this output
Error reading 11 Resource temporarily unavailable
I am using USB to UART converter. Hope someone could help. Thanks :)
You are getting the error code EAGAIN from your read call and this is causing you to exit your loop and print out the error. Of course EAGAIN means that this was a temporary problem (e.g. there wasn't anything to read at the time you tried to read it, perhaps you'd like to try later?).
You could restructure the read to be similar to:
n = read(USB, &buf, 1)
if (n == 0) {
break;
} else if (n > 0) {
response[spot1++] = buf;
} else if (n == EAGAIN || n == EWOULDBLOCK)
continue;
} else { /*unrecoverable error */
perror("Error reading");
break;
}
You could improve your code by making buf be an array and reading more than one character at a time. Also notice that sprintf was unnecessary, you can just copy the character(s) in to the array.

Resources