Binary data from a serial port in linux using c - c

I am reading binary data from a serial port on Phidget sbc using Linux to get a command from an application running on a PC. I wrote a test program in VB to read the data into a byte array and convert it to decimal to use it but can’t figure out how to do it in c. I am unable to come up with anything with the research I have done on the internet.
Command sent from PC is 0x0F.
To check if I am getting correct data I read the data and send it back. Here is what I get back. Returned data has a carriage return added to it.
Hex Display 0F00 0000 0D
‘\’ Display \0F\00\00\00\r
Normal display just display a strange character.
This tells me that the data is there that I can use, but can’t figure out to extract the value 0F or 15.
How can I convert the incoming data to use it?
I tried converting the received data using strtol, but it returns 0. I also tried setting the port to raw but it did not make any difference.
unsigned char buffer1[1];
int ReadPort1()
{
int result;
result = read(file1, &buffer1,1);
if(result > 0)
{
WritePort1(buffer1);
sprintf(tempstr, "Port1 data %s %d", buffer1, result);
DisplayText(2,tempstr);
}
return result;
}
Port Open/Setup
void OpenPort1()
{
//file1 = open("/dev/ttyUSB1", O_RDWR | O_NOCTTY | O_NONBLOCK);
file1 = open("/dev/ttyUSB1", O_RDWR | O_NOCTTY | O_NODELAY);
if(file1 < 0)
printf("Error opening serial port1.\n");
else
{
SetPort(file1, 115200, 8, 1, 0, 1);
port1open = 1;
}
}
void SetPort(int fd, int Baud_Rate, int Data_Bits, int Stop_Bits, int Parity, int raw)
{
long BAUD; // derived baud rate from command line
long DATABITS;
long STOPBITS;
long PARITYON;
long PARITY;
struct termios newtio;
switch (Baud_Rate)
{
case 115200:
BAUD = B115200;
break;
case 38400:
BAUD = B38400;
break;
case 19200:
BAUD = B19200;
break;
case 9600:
BAUD = B9600;
break;
} //end of switch baud_rate
switch (Data_Bits)
{
case 8:
default:
DATABITS = CS8;
break;
case 7:
DATABITS = CS7;
break;
case 6:
DATABITS = CS6;
break;
case 5:
DATABITS = CS5;
break;
} //end of switch data_bits
switch (Stop_Bits)
{
case 1:
default:
STOPBITS = 0;
break;
case 2:
STOPBITS = CSTOPB;
break;
} //end of switch stop bits
switch (Parity)
{
case 0:
default: //none
PARITYON = 0;
PARITY = 0;
break;
case 1: //odd
PARITYON = PARENB;
PARITY = PARODD;
break;
case 2: //even
PARITYON = PARENB;
PARITY = 0;
break;
} //end of switch parity
newtio.c_cflag = BAUD | DATABITS | STOPBITS | PARITYON | PARITY | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR;
if(raw == 1)
{
newtio.c_oflag &= ~OPOST;
newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
}
else
{
newtio.c_lflag = 0; //ICANON;
newtio.c_oflag = 0;
}
newtio.c_cc[VMIN]=1;
newtio.c_cc[VTIME]=0;
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
}

Are you looking for a hex representation of your data ?
sprintf(tempstr, "Port1 data %s %x", buffer1, buffer1[0]);

Related

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).

Wrong order of bytes received from serial port

I have a device with FPGA which sends data via simple UART. The data is a packet of 32 bytes, baudrate is 115200. I connect them to my laptop via UART-TTL/USB adapter, so in system (Ubuntu 14.04) I can read the data from ttyUSB. I've made a simple application in GTK/C to receive the data, make some math and save results in text file. Everything was working fine until I increased frequency of sending 32 bytes packets from 5 times per second to 100 times per second. The problem is one packet in a dozen or several dozen has wrong order of bytes. I've checked with logic analyzer that my FPGA sends data correctly every time.
For example, FPGA sends packet:
1 2 3 4 5 6 7 8 9
But my application sometimes receives:
1 2 7 3 4 5 6 8 9
I'm using this function to open serial port:
int rs232_open(char *com_name, int baudrate, int databits, char *parity, int stopbits)
{
serial_fd = open(com_name, O_RDWR | O_NOCTTY | O_NDELAY); //open port
if(serial_fd==-1)
{
perror("unable to open comport ");
return 1;
}
error = tcgetattr(serial_fd, &old_settings); //save actual port settings
if(error==-1)
{
close(serial_fd);
perror("unable to read portsettings ");
return 2;
}
memset(&new_settings, 0, sizeof(new_settings));
new_settings.c_iflag = 0; //without in processing
new_settings.c_oflag = 0; //without out processing
new_settings.c_lflag = 0; //without line processing
new_settings.c_cflag = CLOCAL | CREAD; //without flow control, receiver active
switch(baudrate) //baudrate
{
case 9600: new_settings.c_cflag |= B9600; break;
case 19200: new_settings.c_cflag |= B19200; break;
case 38400: new_settings.c_cflag |= B38400; break;
case 115200: new_settings.c_cflag |= B115200; break;
default: return 3; break;
}
switch(databits) //number of data bits
{
case 5: new_settings.c_cflag |= CS5; break;
case 6: new_settings.c_cflag |= CS6; break;
case 7: new_settings.c_cflag |= CS7; break;
case 8: new_settings.c_cflag |= CS8; break;
default: return 3;
}
switch(parity[0]) //parity
{
case 'N': new_settings.c_iflag |= IGNPAR; break;
case 'E': new_settings.c_cflag |= PARENB; break;
case 'O': new_settings.c_cflag |= PARENB | PARODD; break;
default: return 3;
}
switch (stopbits) //stop bits
{
case 1: break; //1 bit
case 2: new_settings.c_cflag |= CSTOPB; break; //2 bits
default: return 3;
}
new_settings.c_cc[VMIN] = 1; //1 received char allows to read
new_settings.c_cc[VTIME] = 0;
tcflush(serial_fd, TCIOFLUSH); //clear port buffers
error = tcsetattr(serial_fd, TCSANOW, &new_settings); //save new settings
if(error==-1)
{
close(serial_fd);
perror("unable to set portsettings ");
return 4;
}
return 0;
}
In my GTK/C application clicking on the "OPEN" button calls above function:
rs232_open("ttyUSB0",115200,8,"N",2);
Then, I create a channel for serial port, set its coding and add a handler for receive event:
int serial_fd; //serial port file descriptor
GIOChannel *serial_ch; //serial port channel
serial_ch = g_io_channel_unix_new(serial_fd); //attach channel to serial port
g_io_add_watch(serial_ch, G_IO_IN, read_channel, NULL); //attach read_channel handler function
Function read_channel() looks like this (frame is a struct with table of chars buffer and integer field byte_number):
gboolean read_channel(GIOChannel *channel, GIOCondition condition, gpointer data)
{
unsigned char i;
gsize bytes_read;
gchar chr;
GString *recdata = g_string_new(NULL);
if(g_io_channel_read_chars(channel, &chr, 1, &bytes_read, NULL) == G_IO_STATUS_NORMAL) //if reading a byte is successful
{
if(bytes_read) //1 byte received
{
//
// here I search for 0x55 0x55 sequence (start tag of 32 bytes packet)
// if start tag is received frame buffer is cleared and byte counter zeroed
//
frame.buffer[frame.byte_number++]=chr; //save received byte to buffer
if(frame.byte_number > BUFFER_SIZE-1) //frame buffer full
{
if(frame.buffer[BUFFER_SIZE-1] == 0x0D) //end tag is correct (0x0D is end tag of my 32 bytes packet)
{
//
// here I convert received data (some int16 numbers)
// and save them in readable form to text file
// also as a string of hex numbers for debugging
//
}
else //end tag not correct
{
//
// here I increase error counter
//
}
for(i=0; i<BUFFER_SIZE; i++) frame.buffer[i]=0; //clear the buffer
frame.byte_number=0; //reset byte counter
}
}
}
return TRUE;
}

Linux, failing to read from serial port

I'm trying to connect via RS232 connection.
Communication parameters:
*Transmission rate: 1200 baud
*Character coding: 8-bit ASCII
*Parity: None
*Stop bits: 1
Commands are composed of two byte codes with the following format
Transmit format
CODE + "FFh"
Hex code
Receive format
CODE + "FFh"
Hex code
I tried various initializations but I still fail to read anything from the port the following code is one of them:
//RS232test.c
//Transmission rate: 1200 Baud
//8 bit, no parity 1 stop bits.
//Transmit format: CODE + "FFh"
//Receive format: CODE + "FFh"
//Last edited: 23/08/2014
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#define BAUDRATE B1200
#define MULTI "/dev/ttyS0"
//#define MULTI "/dev/ttyUSB0"
int open_port(struct termios *,struct termios *);
int setDtrRts(int, int);
void close_port(int, struct termios *);
int open_port(struct termios *tty, struct termios *tty_old)
//This opens the tty port for linux saves old port setting
//and saves the new ones
{
int fd; //file descriptor
fd = open(MULTI, O_RDWR | O_NOCTTY);
if (fd < 0) {
perror(MULTI);
printf("failed to open port\n");
exit(-1);
}
//get previous port settings so it can be restored on exit
tcgetattr(fd,tty_old);
//get port settings so they can be set
tcgetattr(fd,tty);
//Set baud rates to 1200
cfsetispeed(tty, BAUDRATE);
cfsetospeed(tty, BAUDRATE);
//ICANON -choosing canonical input.
tty->c_lflag |= (ICANON);
//tty->c_lflag &= ~(ISIG);
//unselecting echo
tty->c_lflag &= ~(ECHO | ECHOE);
//CLOCAL - setting local mode, CREAD - enabling receiver
tty->c_cflag |= (CLOCAL | CREAD);
//close doesn't change signals
tty->c_cflag &= ~HUPCL;
//8N1 no parity 1 stop bit
tty->c_cflag |= CS8;
//tty->c_cflag &= ~(PARENB | CSTOPB | CSIZE);
tty->c_cflag &= ~(PARENB | PARODD /**/| CSIZE);
tty->c_cflag &= ~CSTOPB;
//Raw output mode
tty->c_oflag &= ~OPOST;
//Enable hardware handshaking
//tty->c_cflag &= ~CRTSCTS;
//tty->c_iflag &= ~(IXON | IXOFF | IXANY); //*
//Flushing communication buffer and changing port setting
//tcflush(fd, TCIFLUSH);
//tcsetattr(fd, TCSANOW, tty);
tcsetattr(fd, TCSAFLUSH, tty);
setDtrRts(fd,1);
return fd;
}
int setDtrRts(int fd, int set)
//sets or clears the dtr and rts
//the needs both set during operation
//otherwise it switches off after approx. 20 seconds
{
int setbits;
setbits |= (TIOCM_DTR | TIOCM_RTS);
if(set)
return(ioctl(fd, TIOCMBIC, &setbits));
else
return(ioctl(fd, TIOCMBIS, &setbits));
}
void close_port(int fd, struct termios *tty_old)
//closing port
{
//reset to old options
//tcsetattrb(fd, TCSANOW, tty_old);
setDtrRts(fd,0);
close(fd);
}
int main(void)
{
int fd=0; //system file number
int buff_size; //no of characters in buffer
int bytes; //no of bytes in buffer
int ctr=0; //general counter
char in_buffer[] = "F3\xFF";
char out_buffer[255]; //serial character buffer
//new port setting and a structure to keep the old ones
struct termios tty,tty_old;
//checking if root
if (getuid()){
printf("You must be root to use this program.\n");
exit(-4);
}
printf("fd = %d\n",fd);
//opening port for reading and writing
fd = open_port(&tty,&tty_old);
printf("fd = %d\n",fd);
//flushing
tcflush(fd,TCIOFLUSH);
//sending command to serial port
//strcpy(in_buffer, "F3\xFF"); //placing a command in the buffer
printf("%s",in_buffer);
if((buff_size = write(fd, in_buffer, strlen(in_buffer))) < 0){
printf("Error while sending message\nBuffer contents:\t%s\n",in_buffer);
return -2;
}
usleep(50000); //delay for 50ms
out_buffer[0] = '\0';
ioctl(fd,FIONREAD,&bytes);
printf("\nThere are %d bytes in the buffer\n",bytes);
if(bytes > 0) {
//reading response from serial port
if((buff_size = read(fd, out_buffer,sizeof(out_buffer))) < 0){
printf("Error while reading message\n");
return -3;
}
//printing the decimal ASCII values of the response
printf("Multimeter response:\t");
while(out_buffer[ctr] != '\0')
{
printf("%i ",out_buffer[ctr]);
ctr++;
}
printf("\n%s\n",out_buffer);
} else printf("Buffer Empty\n");
//wrap things up
close_port(fd, &tty_old);
exit(0);
}
The programs output is as follows:
fd = 0
fd = 3
F3�h
There are 0 bytes in the buffer
Buffer Empty
Toyed around with several suggestions in previous posts but did not succeed.
The protocol you describe is not line oriented, so using canonical input mode is wrong. You should use the good old raw mode, defined as :
tty->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
| INLCR | IGNCR | ICRNL | IXON);
tty->c_oflag &= ~OPOST;
tty->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
tty->c_cflag &= ~(CSIZE | PARENB);
tty->c_cflag |= CS8;
In canonical mode, characters are only made available for a read after the eol has been received to allow line edition, which is not what you want here. (reference : man termios)
following code is written by myself, and it's working on my embedded system all the time.
int wrap_uart_init(char *port, int baudrate, int datab, int parity, int stopb){
int fd=open_and_init_tty(port);
if (fd==-1) {
perror("cannot open device");
return fd;
}
set_baudrate(fd,baudrate);
set_dataformat(fd,datab,parity,stopb);
swflow_ctrl(fd);
return fd;
}
call this function like this:
int fd = wrap_uart_init("/dev/ttyUSB0", 1200, 8, 'N', 1);
super easy to use. it's even not important that what the physical layer protocol is, as long as Linux has masked the device into a tty file.
#define _BSD_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
static struct termios origin_attrs;
static struct termios old_attrs;
int open_tty(const char *dev){
int fd=open(dev, O_RDWR | O_NOCTTY | O_NDELAY | O_SYNC);
if (fd==-1)
perror(FILE_OPEN_ERROR);
if (fcntl(fd, F_SETFL, 0)<0){
perror("fcntl error!");
close(fd);
fd=-1;
}
if (!isatty(STDIN_FILENO)){
perror("standard input error! ");
close(fd);
fd=-1;
}
return fd;
}
void close_tty(int fd){
if (tcsetattr(fd,TCSANOW,&old_attrs)) {
perror(GET_ATTR_ERROR);
}
close(fd);
}
int open_and_init_tty(const char *dev){
int fd=open_tty(dev);
if (fd==-1){
perror(FILE_OPEN_ERROR);
return -1;
}
if (tcgetattr(fd,&old_attrs)) {
perror(GET_ATTR_ERROR);
return -1;
}
struct termios opt;
int br=B9600;
cfsetispeed(&opt, br);
cfsetospeed(&opt, br);
opt.c_cflag = (CS8 | CLOCAL | CREAD);
opt.c_iflag = (IGNPAR | IXON | IXOFF | IXANY);
opt.c_lflag = 0;
opt.c_oflag = 0;
opt.c_cc[VTIME] = 30;
opt.c_cc[VMIN] = 5;
tcflush(fd, TCIOFLUSH);
if (tcsetattr(fd,TCSANOW,&opt) != 0) {
perror(SET_ATTR_ERROR);
return -1;
}
return fd;
}
int set_baudrate(int fd, int baud){
int br;
int status;
struct termios opt;
if (tcgetattr(fd, &opt)) {
perror(GET_ATTR_ERROR);
return -1;
}
switch (baud) {
case 115200: br=B115200;break;
// case 76800: br=B76800; break;
case 57600: br=B57600; break;
case 38400: br=B38400; break;
case 19200: br=B19200; break;
case 9600: br=B9600; break;
case 4800: br=B4800; break;
case 2400: br=B2400; break;
case 1200: br=B1200; break;
case 600: br=B600; break;
case 300: br=B300; break;
default: perror("Wrong Baud rate!");
return -1;
}
tcflush(fd, TCIOFLUSH);
cfsetispeed(&opt, br);
cfsetospeed(&opt, br);
status = tcsetattr(fd, TCSANOW, &opt);
if (status) {
perror(BAUD_RATE_ERROR);
return -2;
}
tcflush(fd,TCIOFLUSH);
return 0;
}
int set_dataformat(int fd,int databits,int parity,int stopbits){
struct termios options;
if (tcgetattr(fd,&options)) {
perror(GET_ATTR_ERROR);
return -1;
}
options.c_cflag &= ~CSIZE;
switch (databits) {
case 5:
options.c_cflag |= CS5;
break;
case 6:
options.c_cflag |= CS6;
break;
case 7:
options.c_cflag |= CS7;
break;
case 8:
options.c_cflag |= CS8;
break;
default:
perror("Unsupported data size");
return -2;
}
switch (parity) {
case 'n': //no parity check
case 'N':
options.c_cflag &= ~PARENB;
options.c_iflag &= ~INPCK;
break;
case 'o': //odd check
case 'O':
options.c_cflag |= (PARODD | PARENB);
options.c_iflag |= (INPCK | ISTRIP);
break;
case 'e': //even check
case 'E':
options.c_cflag |= PARENB;
options.c_cflag &= ~PARODD;
options.c_iflag |= (INPCK | ISTRIP);
break;
default:
perror("Unsupported parity");
return -3;
}
switch (stopbits) {
case 1: //1 stop bit
options.c_cflag &= ~CSTOPB;
break;
case 2: //2 stop bits
options.c_cflag |= CSTOPB;
break;
default:
perror("Unsupported stop bits");
return -4;
}
tcflush(fd,TCIFLUSH);
options.c_cc[VTIME] = 50;
options.c_cc[VMIN] = 1;
if (tcsetattr(fd,TCSANOW,&options) != 0) {
perror(SET_ATTR_ERROR);
return -1;
}
return 0;
}
int set_databit(int fd, int databits){
struct termios options;
if (tcgetattr(fd,&options)) {
perror(GET_ATTR_ERROR);
return -1;
}
options.c_cflag &= ~CSIZE;
switch (databits) {
case 5:
options.c_cflag |= CS5;
break;
case 6:
options.c_cflag |= CS6;
break;
case 7:
options.c_cflag |= CS7;
break;
case 8:
options.c_cflag |= CS8;
break;
default:
perror("Unsupported data size");
return -1;
}
tcflush(fd,TCIFLUSH);
if (tcsetattr(fd,TCSANOW,&options) != 0) {
perror(SET_ATTR_ERROR);
return -2;
}
return 0;
}
int set_parity(int fd, int parity) {
struct termios options;
if (tcgetattr(fd,&options)) {
perror(GET_ATTR_ERROR);
return -1;
}
options.c_cflag &= ~CSIZE;
switch (parity) {
case 'n': //no parity check
case 'N':
options.c_cflag &= ~PARENB;
options.c_iflag &= ~INPCK;
break;
case 'o': //odd check
case 'O':
options.c_cflag |= (PARODD | PARENB);
options.c_iflag |= (INPCK | ISTRIP);
break;
case 'e': //even check
case 'E':
options.c_cflag |= PARENB;
options.c_cflag &= ~PARODD;
options.c_iflag |= (INPCK | ISTRIP);
break;
default:
perror("Unsupported parity");
return -1;
}
tcflush(fd,TCIFLUSH);
if (tcsetattr(fd,TCSANOW,&options) != 0) {
perror(SET_ATTR_ERROR);
return -2;
}
return 0;
}
int set_stopbit(int fd, int stopbits) {
struct termios options;
if (tcgetattr(fd,&options)) {
perror(GET_ATTR_ERROR);
return -1;
}
options.c_cflag &= ~CSIZE;
switch (stopbits) {
case 1: //1 stop bit
options.c_cflag &= ~CSTOPB;
break;
case 2: //2 stop bits
options.c_cflag |= CSTOPB;
break;
default:
perror("Unsupported stop bits");
return -1;
}
tcflush(fd,TCIFLUSH);
if (tcsetattr(fd,TCSANOW,&options) != 0) {
perror(SET_ATTR_ERROR);
return -2;
}
return 0;
}
int hwflow_ctrl(int fd){
struct termios options;
if (tcgetattr(fd,&options)) {
perror(GET_ATTR_ERROR);
return -1;
}
options.c_cflag |= CRTSCTS;
options.c_iflag &= ~(IXON | IXOFF | IXANY);
tcflush(fd,TCIFLUSH);
if (tcsetattr(fd,TCSANOW,&options) != 0) {
perror(SET_ATTR_ERROR);
return -2;
}
return 0;
}
int swflow_ctrl(int fd){
struct termios options;
if (tcgetattr(fd,&options)) {
perror(GET_ATTR_ERROR);
return -1;
}
options.c_cflag &= ~CRTSCTS;
options.c_iflag |= (IXON | IXOFF | IXANY);
tcflush(fd,TCIFLUSH);
if (tcsetattr(fd,TCSANOW,&options) != 0) {
perror(SET_ATTR_ERROR);
return -2;
}
return 0;
}
int store_termios(int fd){
if (tcgetattr( fd,&origin_attrs)) {
perror(GET_ATTR_ERROR);
return -1;
}
return 0;
}
int recover_termios(int fd){
tcflush(fd, TCIOFLUSH);
if (tcsetattr(fd,TCSANOW,&origin_attrs)) {
perror(SET_ATTR_ERROR);
return -1;
}
tcflush(fd, TCIOFLUSH);
return 0;
}

Not able to get the attributes of serial port config

Helo, I have been trying to retrieve the configuration of serial port using tcgetattr and I am able to get the correct values at first instance. When I change the values of corresponding parameters return values I get are repeat of previous returns. If ayone knows please help. I tried this when serial port connection was active and working.
#include<termios.h>
#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
char *baudQuery(speed_t speed){
static char SPEED[20];
switch (speed){
case B4800:
strcpy(SPEED, "B4800");
return SPEED;
break;
case B9600:
strcpy(SPEED, "B9600");
return SPEED;
break;
case B19200:
strcpy(SPEED, "B19200");
return SPEED;
break;
case B38400:
strcpy(SPEED, "B38400");
return SPEED;
break;
case B57600:
strcpy(SPEED, "B57600");
return SPEED;
break;
case B115200:
strcpy(SPEED, "B115200");
return SPEED;
break;
default :
strcpy(SPEED, "ERROR");
return SPEED;
}
}
main() {
int fd;
struct termios term;
speed_t speed;
term.c_cflag = B38400 | ~CSIZE | CS5 | PARENB | (~PARODD);
term.c_lflag = ~(ICANON | ECHO | ECHOE);
if((fd = open("/dev/ttyS1",O_RDWR)) <0)
printf("Failed to open file\n");
tcsetattr(fd,TCSANOW,&term);
if (tcgetattr(fd, &term) != 0)
perror("tcgetatt() error");
else {
speed = cfgetospeed(&term);
printf("cfgetispeed() says the speed of stdin is %s\n",
baudQuery(speed));
tcgetattr(fd, &term);
switch(term.c_cflag & CSIZE){
case CS5:
puts("Data Bits = 5");
break;
case CS6:
puts("Data Bits = 6");
break;
case CS7:
puts("Data Bits = 7");
break;
case CS8:
puts("Data Bits = 8");
break;
}
tcgetattr(fd, &term);
if(term.c_cflag & (~PARENB))
puts("No parity is used");
if (term.c_cflag & (PARENB & (~PARODD)) )
puts("Even parity is used");
if (term.c_cflag & (PARODD & PARENB))
puts("Odd parity is used");
//Get the mode (Only part working correct!)
if(term.c_lflag & ICANON)
puts("Mode is canonical");
else
puts("Mode is non canonical");
}
close(fd);
}

Read /dev/ttyUSB0 with a c program on LINUX

I want to read data frames sent by a GPS XBee protocol. The USB XStick receives the following data:
CHARS : 15931 SENTENCES = 0 CHECKSUM : 58
Heading : 55 Tilt: -46 Roll:2
CHARS : ....
and so on ... I can read by typing in the terminal control :
$ screen /dev/ttyUSB0
I'd like to see these details in the same way, but with a program written in C. Here's what I do :
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <sys/fcntl.h>
#include <unistd.h>
#include "serial_port.h"
void read_Serial_Port(const char* DEVICE_PORT)
{
int file;
struct termios options;
char message[100];
unsigned int nCountMax = 60;
bool b;
file = open(DEVICE_PORT, O_RDONLY | O_NOCTTY | O_NDELAY);
if(file == -1){perror("Unable to open the serial port\n");}
printf("Serial port open successful\n");
tcgetattr(file, &options);
cfsetispeed(&options, B9600);
cfsetospeed(&options, B9600);
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag |= PARENB; //No parity
options.c_cflag |= PARODD;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8; //8 bits
options.c_iflag |= (INPCK | ISTRIP);
tcsetattr(file, TCSANOW, &options);
fcntl(file, F_SETFL, FNDELAY);
printf("Reading serial port ...\n\n");
b = readMessage(file, message, nCountMax);
if (b == 0){printf("Error while reading serial port\n");}
else printf("Serial port read successful\n");
close(file);
printf("Serial port closed\n");
};
bool readMessage(int file, char *message, unsigned int nCountMax)
{
int nbCharToRead;
char data[100];
int i;
if (file != 0)
{
i = 0;
while (i<nCountMax && data != ".")
{
if (read(file,&data,1) == -1)
{
printf("reception error\n");
return false;
}
else
{
message[i] = *data;
printf("%c", message[i]);
i++;
}
}
message[i] = 0;
return true;
}
}
But it does not work, I get "reception error", corresponding to:
read(file,&data,1) == -1
Where am I going wrong?
My program is the following:
bool readMessage(int file, unsigned int nCountMax)
{
int i;
size_t nbytes;
ssize_t bytes_read;
if (file != -1)
{
i = 0;
char message[100];
char data[100];
while (i<nCountMax && data != ".")
{
if (read(file, data, 1) == -1)
{
printf("reception error\n");
printf("code errno = %d\n", errno);
return false;
}
else
{
nbytes = sizeof(data);
bytes_read = read(file, data, nbytes);
message[i] = *data;
printf("%c", message[i]);
i++;
}
}
message[i] = 0;
return true;
}
}
This time there are no more errors, but the characters shown are wrong:
$$$$QUC
U$C
$$$$JQMJ' J$Cz(HSQ'Q'y
UKUNiQUMJ
the dollar signs $$$$ represent numbers in groups of four... I repeat that what I would like to have is
CHARS : 15931 SENTENCES = 0 CHECKSUM : 58
Heading : 55 Tilt: -46 Roll:2
CHARS : .....
I have tried using %c, %d, %x in the format string, but obviously none of them worked properly ...
Thank you!
In my code, I only change c_cflag, as follows:
// Enable the receiver and set local mode...
options.c_cflag |= (CLOCAL | CREAD);
// Set 8-bit mode
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
I'll post more code tomorrow, but give that a shot (and don't modify c_iflag).

Resources