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);
Related
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.
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.
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);
}
Dear Colleagues.
I'm trying write C program for Linux to write serial port (Arduino) and wait for answer. I know, there was many Q about it on forum, but all I tried have the same problem - successfully write - but not read answer. For example, here and here.
I have found two separate files for write and for read.
I'm compile and run read file in one terminal window, and write file in other. Works great. But I can't merge them in one file to write and then wait for answer. The same problem - write, but not read.
Here is like I tried:
#include <stdio.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>
void main(void)
{
int fd;
fd = open("/dev/ttyS0",O_RDWR | O_NOCTTY | O_SYNC);
if(fd == -1)
printf("\n Error! in Opening ttyUSB0 ");
else
printf("\n ttyS0 Opened Successfully ");
struct termios SerialPortSettings;
tcgetattr(fd, &SerialPortSettings);
cfsetispeed(&SerialPortSettings,B9600);
cfsetospeed(&SerialPortSettings,B9600);
/* 8N1 Mode */
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;/*No Output Processing*/
/* Setting Time outs */
SerialPortSettings.c_cc[VMIN] = 10; /* Read at least 10 characters */
SerialPortSettings.c_cc[VTIME] = 0; /* Wait indefinetly */
if((tcsetattr(fd,TCSANOW,&SerialPortSettings)) != 0)
printf("\n ERROR ! in Setting attributes");
else
printf("\n BaudRate = 9600 \n StopBits = 1 \n Parity = none");
char write_buffer[] = "Hello/n";
int bytes_written = 0;
printf("\n %s written to ttyUSB0",write_buffer);
printf("\n %d Bytes written to ttyUSB0", bytes_written);
printf("\n +----------------------------------+\n\n");
//tcflush(fd, TCIFLUSH); /* Discards old data in the rx buffer */
char read_buffer[32];
int bytes_read = 0;
int i = 0;
write(fd,write_buffer,sizeof(write_buffer));/* use write() to send data to port */
usleep ((8 + 25) * 100); /* Delay */
read(fd,&read_buffer,32); /* Read the data */
printf("\n\n Bytes Rxed -%d", bytes_read); /* Print the number of bytes read */
printf("\n\n ");
for(i=0;i<bytes_read;i++) /*printing only the received characters*/
printf("%c",read_buffer[i]);
printf("\n +----------------------------------+\n\n\n");
close(fd); /* Close the serial port */
}
Thanks for your help, Have a nice day.
You have a variable called bytes_read that is initialized to 0. Nothing in the code changes that value.
– user3386109
The statement read(fd,&read_buffer,32) should be corrected to bytes_read = read(fd, read_buffer, 32) …
– sawdust
I am trying to read some data from serial port using usb/rs232 converter. I am sending data from atmega and it is received properly in minicom. But trying to read sth in my program ends up with an error "Resource temporarily unavailable". I know that this is caused by O_NDELAY, but removing that gives me plenty of empty messages which also isn't good.
Actually, what I want to achieve is a program, which every second will transmit some char to atmega and wait for a response. Depending on a response it will do different actions. Also after few unanswered transmissions program will indicate an error with communication.
But for now I'd like to at least receive something properly.
Here is my code:
#include <unistd.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
int fd; //file descriptor
int bytes; // bytes to read
int PortOpen(void)
{
fd = open("/dev/ttyUSB1", O_RDWR | O_NOCTTY | O_NDELAY);
if(fd < 0)
{
//opening error
printf("Port opening error\r\n");
}
else
{
printf("Port opened\r\n");
//port config
struct termios options;
tcgetattr(fd, &options);
cfsetispeed(&options, B9600);
cfsetospeed(&options, B9600);
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
options.c_cflag |= CLOCAL;
options.c_cflag |= CREAD;
options.c_cflag &= ~CRTSCTS;
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = 5;
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
//Modifying c_iflag by bitwise OR and AND
options.c_iflag &= ~(ICRNL | INLCR | IGNCR | IUCLC);
options.c_iflag &= ~(IXON | IXOFF | IXANY);
//Modifying c_oflag by bitwise OR and AND
options.c_oflag &= ~OPOST;
tcflush(fd, TCIFLUSH);
//Setting the new settings for the port immediately
tcsetattr(fd, TCSANOW, &options);
}
return 1;
}
int PortRead(void)
{
int n = 0, spot = 0;
char buf = '\0';
/* Whole response*/
char response[1024];
memset(response, '\0', sizeof response);
do {
n = read( fd, &buf, 1 );
sprintf( &response[spot], "%c", buf );
spot += n;
} while( buf != '\r' && n > 0);
if (n < 0)
{
printf("Error reading: %s\r\n",strerror(errno));
}
else if (n == 0)
{
printf("Read nothing!\r\n");
}
else
{
printf("Response: %s", response);
}
return 1;
}
int main(void)
{
PortOpen();
int j;
for(j=0; j<100; j++) //just testing
{
PortRead();
}
return 0;
}
In my program I read from the serial device (Linux, 8N1) without any problem. But in the case I want to write out a single byte, I get nothing out on the interface. I assume that my serial output settings are wrong. But there aren't that many ways how to set c_oflag...
My code:
#define TTYDEVICE "/dev/ttyS0"
#define BAUDRATE B9600
int openSerialDevice(const char* devTTY, struct termios oldTio) {
//----< Open serial device >----------------------------------
int fileDescriptor;
// fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
fileDescriptor = open(devTTY, O_RDWR | O_NOCTTY);
//fileDescriptor = open(devTTY, O_RDWR | O_NOCTTY /*| OPOST*/);
if (fileDescriptor == -1) {
perror("Error while opening serial interface occurred!");
return -99;
}
// set new parameters to the serial device
struct termios newtio;
bzero(&newtio, sizeof(newtio));
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
// set to 8N1
newtio.c_cflag &= ~PARENB;
newtio.c_cflag &= ~CSTOPB;
newtio.c_cflag &= ~CSIZE;
newtio.c_cflag |= CS8;
newtio.c_iflag = IGNPAR;
// output mode to
//newtio.c_oflag = 0;
newtio.c_oflag |= OPOST;
/* set input mode (non-canonical, no echo,...) */
newtio.c_lflag = 0;
newtio.c_cc[VTIME] = 10; /* inter-character timer 1 sec */
newtio.c_cc[VMIN] = 0; /* blocking read disabled */
tcflush(fileDescriptor, TCIFLUSH);
if (tcsetattr(fileDescriptor, TCSANOW, &newtio)) {
perror("could not set the serial settings!");
return -99;
}
//----< / Open serial device >----------------------------------
return fileDescriptor;
}
int ACK[1] = { 6 };
int main() {
// old termios to restablish
struct termios oldTIO;
// filedescriptor
int fd;
fd = openSerialDevice(TTYDEVICE, oldTIO);
if ((fd == -1) | (fd == -99)) {
perror("Could not open TTY-Device. Exit on failure!");
return EXIT_FAILURE;
}
write(fd, ACK, 1); // Problem !!
return 0:
}
Now, if I use
screen /dev/ttyS1 9600 8n1
to verify what's coming out on /dev/ttyS0. I can't see anything. Same if I sniff with Docklight 1.8.
Any suggestions? thanks
How do you verify nothing is coming out ?
You can try to drop the RTSCTS, and try again. Infact, if you want minimal interference from the tty layer, you should set your terminal to raw, using this :
cfmakeraw(&newtio);
You're giving write() the data argument of ACK, which is a pointer to int. This is probably not what you mean. Depending on the endianness of the computer you're on, this means write() will "see" a buffer containing the chars { 6, 0, 0, 0 } (little-endian) or { 0, 0, 0, 6 } (big-endian). This assumes that sizeof (int) == 4 is true, adjust for other sizes as needed, the problem remains.
You should very probably make the buffer unsigned char instead. Also, if you had made the call like this:
int wrote = write(fd, ACK, sizeof ACK);
printf("Wrote %d bytes\n", wrote);
You would have gotten direct feedback. You should test something like this, to see that the write actually succeeds.
The activated Hardware-Flow-Control (CRTSCTS) was the reason why write() blocked and finally nothing has appeared on the serial output.
thanks!
Code snap which works:
int openSerialDevice(const char* devTTY, struct termios oldTio) {
//----< Open serial device >----------------------------------
int fileDescriptor;
// fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
fileDescriptor = open(devTTY, O_RDWR | O_NOCTTY);
//fileDescriptor = open(devTTY, O_RDWR | O_NOCTTY /*| OPOST*/);
if (fileDescriptor == -1) {
perror("Error while opening serial interface occurred!");
return -99;
}
// set new parameters to the serial device
struct termios newtio;
fcntl(fileDescriptor, F_SETFL, 0);
// set everything to 0
bzero(&newtio, sizeof(newtio));
// again set everything to 0
bzero(&newtio, sizeof(newtio));
newtio.c_cflag |= BAUDRATE; // Set Baudrate first time
newtio.c_cflag |= CLOCAL; // Local line - do not change "owner" of port
newtio.c_cflag |= CREAD; // Enable receiver
newtio.c_cflag &= ~ECHO; // Disable echoing of input characters
newtio.c_cflag &= ~ECHOE;
// set to 8N1
newtio.c_cflag &= ~PARENB; // no parentybyte
newtio.c_cflag &= ~CSTOPB; // 1 stop bit
newtio.c_cflag &= ~CSIZE; // Mask the character size bits
newtio.c_cflag |= CS8; // 8 data bits
// output mode to
newtio.c_oflag = 0;
//newtio.c_oflag |= OPOST;
// Set teh baudrate for sure
cfsetispeed(&newtio, BAUDRATE);
cfsetospeed(&newtio, BAUDRATE);
newtio.c_cc[VTIME] = 10; /* inter-character timer */
newtio.c_cc[VMIN] = 0; /* blocking read until */
tcflush(fileDescriptor, TCIFLUSH); // flush pending data
// set the new defined settings
if (tcsetattr(fileDescriptor, TCSANOW, &newtio)) {
perror("could not set the serial settings!");
return -99;
}
//----< / Open serial device >----------------------------------
return fileDescriptor;
}