Not able to get the attributes of serial port config - c

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);
}

Related

Raspberry Pi SPI Connection: transition diagram malfunctioning

I am working with the raspberry pi and atmega 32 to use and learn SPI. it should follow a transition diagram but somewhere in the atmega it goes wrong, I don't know where it is going wrong.
this is the raspberry code
#include <wiringPi.h>
#include <stdio.h>
#include <wiringPiSPI.h>
#define SELECTADC 6
#define READY 8
#define GIVEADC 32
#define NOTREADY 0x10
#define DUMMY 0x55
#define ACK 10
#define IDLE 1
#define POLL 2
#define ADCSTART 3
#define ADCSTATE 4
#define ADCRESULT 5
main() {
int tellerPoll=0;
int teller=0;
int adcStatusTeller=0;
int status=0;
unsigned char data[4];
wiringPiSetup();
int kanaal = 0;
int adc;
int adcHigh=0;
int error=0;
if( wiringPiSPISetup (0, 500000)==-1)
{
printf("Could not initialise SPI\n");
status=0;
return;
} else {
status = IDLE;
printf("succesful initialised\n");
}
for(;;)
{
delay(20);
//wiringPiSPIDataRW(0,data,1);
switch(status){
case 0 :
exit(0);
case IDLE :
teller +=1;
if((teller % 2 == 1)&&1){
data[0] = POLL;
wiringPiSPIDataRW(0,data,1);
status = POLL;
//teller=0;
printf("Poll\n");
}
else if ((teller % 2 == 0)&&1){
status = ADCSTART;
}
break;
case POLL :
data[0] = DUMMY;
wiringPiSPIDataRW(0,data,1);
printf("Poll result: %x\n", data[0]);
if(data[0]==ACK){
status=IDLE;
printf("Poll succesfull\n");
tellerPoll=0;
}
else{
tellerPoll+=1;
if(tellerPoll>20){
status=0;
printf("No device found\n");
tellerPoll=0;
}
}
break;
case ADCSTART :
data[0]=ADCSTART;
wiringPiSPIDataRW(0,data,1);
status = ADCSTATE;
printf("ADCSTART\n");
break;
case ADCSTATE :
// printf("ADCSTATE\n");
data[0]=ADCSTATE;
wiringPiSPIDataRW(0,data,1);
//printf("%x\n",data[0]);
if(data[0]==READY){
status=ADCRESULT;
printf("Ready\n");
break;
}
else if(data[0]==NOTREADY){
printf("NOTREADY\n");
status=ADCSTATE;
adcStatusTeller+=1;
if(adcStatusTeller==100){
status=IDLE;
adcStatusTeller=0;
printf("no ADC result\n");
}
}
else{
adcStatusTeller+=1;
status =ADCSTATE;
printf("Weird result: %x\n", data[0]);
if (adcStatusTeller==100){
status=IDLE;
adcStatusTeller=0;
printf("no Results: %x \n", data[0]);
}
}
break;
case ADCRESULT :
data[0]=GIVEADC;
wiringPiSPIDataRW(0,data,1);
data[0]=DUMMY;
wiringPiSPIDataRW(0,data,1);
adc = data[0];
delay(10);
data[0]=DUMMY;
wiringPiSPIDataRW(0,data,1);
adcHigh=data[0];
//adcHigh &= 0b11000000;
//adcHigh <<=2;
//adc += adcHigh;
printf("ADC %d heeft waarde %x %x \n",kanaal, adcHigh, adc);
status=IDLE;
break;
case SELECTADC :
data[0]=SELECTADC;
wiringPiSPIDataRW(0,data,1);
data[0]=DUMMY;
wiringPiSPIDataRW(0,data,1);
if(data[0]==ACK){
delay(10);
data[0]=kanaal;
wiringPiSPIDataRW(0,data,1);
printf("ADC %s is succesfully selected",kanaal);
status=POLL;
}
else{
printf("There was an error selecting the ADC");
status=SELECTADC;
error+=1;
if(error==20){
status=POLL;
error=0;
printf("No ADC selected");
break;
}
}
break;
default :
printf("default\n");
break;
}
kanaal=0;
}
}
And Atmega32
#include <stdlib.h>
#include <avr/io.h>
void adc_init(void);
void SPI_SlaveInit(void);
unsigned char SPI_SlaveReceive(unsigned char);
void leesADC(char);
#define IDLE 1
#define POLL 2
#define ADCSTART 3
#define ADCSTATE 4
#define SELECTADC 6
#define READY 8
#define ACK 10
#define GIVEADC 32
#define NOTREADY 0x10
#define DUMMY 0x55
void SPI_SlaveInit(void)
{
/* Set MISO output, all others input */
DDRB = (1<<PB6);
/* Enable SPI */
SPCR = (1<<SPE);
}
unsigned char SPI_SlaveReceive(unsigned char data)
{
SPDR = data;
/* Wait for reception complete */
while(!(SPSR & (1<<SPIF) ));
/* Return data register */
return SPDR;
}
//starADC
void leesADC(char kanaal)
{
ADMUX &= 0b11100000;
ADMUX |= kanaal & 7;
ADCSRA |= (1<<ADSC);
}
void adc_init(void)
{
ADMUX=(1<<REFS0)|(1<<ADLAR); //voedings U als referentie, links uitlijnen in de 10bit
ADCSRA=(1<<ADEN); // adc enablen, start conversion, auto trigger enable
}
int main(void)
{
DDRC= 0b11111111;
DDRD= 0b11111111;
SPI_SlaveInit();
adc_init();
int kanaal=0;
leesADC(kanaal);
char stap;
char status;
while(1)
{
switch(stap){
case IDLE :
stap = SPI_SlaveReceive(status);
break;
case POLL :
status = ACK;
stap=IDLE;
PORTD=15;
break;
case ADCSTART :
status = ADCSTART;
leesADC(kanaal);
PORTD=255;
break;
case ADCSTATE :
if ((ADCSRA & (1<<ADIF)) == 0){
status = NOTREADY;
} else{
status = READY;
}
stap=IDLE;
break;
case GIVEADC :
stap= ADCH;
break;
case SELECTADC :
kanaal = SPI_SlaveReceive(DUMMY);
stap=DUMMY;
break;
default : ;
}
}
}
Thanks in advance.
You don't initialize the stap variable, which means its value will be indeterminate. Attempting to use it in the switch statement will lead to undefined behavior.
I suppose you should be initializing it to IDLE:
int stap = IDLE;

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;
}

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

Binary data from a serial port in linux using 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]);

Resources