How to read character using serial port in Linux - c

I trying to read serial raw bytes from using serial port "/dev/ttyS0".In my program, What i want to do is to press the letter and immediately see the the letter I introduced repeated without pressing ENTER. For example, if I press the letter 'a' I want to see an other 'a' next to it.
My code is here:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
int main()
{
int n = 0, fd = 0;
struct termios term,trm;
printf("%d\n",getpid());
fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1)
{
perror("open");
return 1;
}
else
{
fcntl(fd, F_SETFL, 0);
perror("Port");
}
if (n = tcgetattr(fd, &term) == -1)
{
perror("tcgetattr");
return 1;
}
if (n = cfsetispeed(&term, B115200) == -1)
{
perror("cfsetispeed");
return 1;
}
if (n = cfsetospeed(&term, B115200) == -1)
{
perror("cfsetospeed");
return 1;
}
term.c_cflag |= (CLOCAL | CREAD);
term.c_cflag &= ~PARENB;
term.c_cflag &= ~CSTOPB;
term.c_cflag &= ~CSIZE;
term.c_cflag |= CS8;
term.c_cflag &= ~CRTSCTS;
term.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
term.c_iflag &= ~(IXON | IXOFF | IXANY);
term.c_iflag |= (INPCK | ISTRIP);
term.c_oflag &= ~OPOST;
unsigned char c,d;
ssize_t s=0;
tcflush(fd, TCIOFLUSH);
system("/bin/stty raw");
while((c=getchar()) != 'q')
{
write(fd, &c,1);
term.c_cc[VMIN] = 1;
term.c_cc[VTIME] = 0;
tcsetattr(fd, TCSANOW, &term);
if((s=read(fd, &d,1)) != -1)
{
perror("read");
printf("%c",d);
}
}
system("/bin/stty cooked");
close(fd);
return 0;
}

I don't know if it is the solution you are looking for, but you must disable stdin buffering to make getchar exits each char user enter.
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
int main()
{
int n = 0, fd = 0;
struct termios term, old_stdin, new_stdin;
printf("%d\n",getpid());
fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1)
{
perror("open");
return 1;
}
else
{
fcntl(fd, F_SETFL, 0);
perror("Port");
}
if (n = tcgetattr(fd, &term) == -1)
{
perror("tcgetattr");
return 1;
}
if (n = cfsetispeed(&term, B115200) == -1)
{
perror("cfsetispeed");
return 1;
}
if (n = cfsetospeed(&term, B115200) == -1)
{
perror("cfsetospeed");
return 1;
}
term.c_cflag |= (CLOCAL | CREAD);
term.c_cflag &= ~PARENB;
term.c_cflag &= ~CSTOPB;
term.c_cflag &= ~CSIZE;
term.c_cflag |= CS8;
term.c_cflag &= ~CRTSCTS;
term.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);
term.c_iflag &= ~(IXON | IXOFF | IXANY);
term.c_iflag |= (INPCK | ISTRIP);
term.c_oflag &= ~OPOST;
unsigned char c,d;
ssize_t s=0;
tcflush(fd, TCIOFLUSH);
term.c_cc[VMIN] = 1;
term.c_cc[VTIME] = 0;
tcsetattr(fd, TCSADRAIN, &term);
// get the terminal settings for stdin
tcgetattr(STDIN_FILENO,&old_stdin);
new_stdin = old_stdin;
// disable canonical mode (buffered i/o) and local echo
new_stdin.c_lflag &=(~ICANON & ~ECHO);
// set the new settings
tcsetattr(STDIN_FILENO,TCSANOW,&new_stdin);
while((c=getchar()) != 'q')
{
write(fd, &c,1);
if((s=read(fd, &d,1)) != -1)
{
perror("read");
printf("%c",d);
}
}
close(fd);
// Restore the old stdin setup
tcsetattr(STDIN_FILENO,TCSANOW,&old_stdin);
return 0;
}

You should change the terminal device's mode to "raw", by using
tty.setraw(file_descriptor)

Related

C Programming - read from TTY serial port followed by write response loses data

I have a simple test program which waits for a set of 3 characters to be sent to the USB port (0x10, 0x04 and 0x02) and then should respond with "Hello World". For some reason, the first character is missed off the response so I only see "ello World".
I am using the USB-OTG port with modprobe g_serial for communication if that makes any difference.
What am I missing?
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include <sys/poll.h>
#include <sys/ioctl.h>
#include <linux/usb/g_printer.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#define ODROID_SERIAL_GADGET "/dev/ttyGS0"
#define BUF_SIZE 1024
int main()
{
struct pollfd fd[0];
struct termios tty;
int timeover=1000;
static char buf[BUF_SIZE];
char obuff[] = ".";
int ox10Found, ox04SeqeunceFound, i;
int bytes_read, retval;
int max_read_time = 2; /* units of 250ms after which incoming data times out - 1 causes larger files to be split */
fd[0].fd = open(ODROID_SERIAL_GADGET, O_RDWR);
if (fd[0].fd < 0) {
printf("Error %d opening %s\n", fd[0].fd, ODROID_SERIAL_GADGET);
close(fd[0].fd);
return(-1);
}
tcgetattr(fd[0].fd,&tty); /* save current serial port settings */
tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); // Enable canonical input - we need to read contorol characters
tty.c_oflag = 0; // no output processing
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
tty.c_cc[VMIN] = 0; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
tty.c_cflag |= (CLOCAL | CREAD);// ignore modem controls,
// enable reading
tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
tty.c_cflag |= 0;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS;
tcsetattr(fd[0].fd,TCSANOW,&tty);
fd[0].events = POLLIN | POLLRDNORM;
ox10Found=0;
ox04SeqeunceFound=0;
while (1) {
/* Wait for up to 1/4 second for data. */
retval = poll(fd, 1, 250);
timeover++;
if (timeover>1000) {
timeover=max_read_time+1;
}
if (retval) {
bytes_read = read(fd[0].fd, buf, BUF_SIZE);
if (bytes_read < 0) {
/* Open device file for serial gadget. */
printf("Error %d reading from %s\n",fd[0].fd, ODROID_SERIAL_GADGET);
close(fd[0].fd);
return(-1);
}
for (i = 0; i < bytes_read; i++) {
if (buf[i]==0x10 && !ox10Found && !ox04SeqeunceFound) {
ox10Found=1;
continue;
} else if (buf[i]==0x04 && ox10Found) {
ox04SeqeunceFound=1;
continue;
} else {
ox10Found=0;
}
if (buf[i]==0x02 && ox04SeqeunceFound) {
write(fd[0].fd, "Hello World", 11);
tcdrain(fd[0].fd); // Wait for output
}
}
}
}
}

How to listen on serial port with C using CRTSCTS

I am trying to listen to a serial port with a C program utilizing CRTSCTS (to prevent an independently powered Arduino from rebooting after the computer it is connected to restarts).
I started with the code from here: Canonical Mode Linux Serial Port
After some adaptations it looks like this:
#define SERIALTERMINAL "/dev/ttyUSB0"
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
int set_interface_attribs(int fd, int speed)
{
struct termios tty;
if (tcgetattr(fd, &tty) < 0) {
printf("Error from tcgetattr: %s\n", strerror(errno));
return -1;
}
cfsetospeed(&tty, (speed_t)speed);
cfsetispeed(&tty, (speed_t)speed);
tty.c_cflag |= CLOCAL | CREAD;
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8; /* 8-bit characters */
tty.c_cflag &= ~PARENB; /* no parity bit */
tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
//tty.c_cflag &= ~CRTSCTS;
tty.c_cflag |= ~CRTSCTS; //trying to turn on CRTSCTS
tty.c_cflag &= ~HUPCL; //trying turning off HUPCL - it works!
tty.c_lflag |= ICANON | ISIG; /* canonical input */
tty.c_lflag &= ~(ECHO | ECHOE | ECHONL | IEXTEN);
tty.c_iflag &= ~IGNCR; /* preserve carriage return */
tty.c_iflag &= ~INPCK;
tty.c_iflag &= ~(INLCR | ICRNL | IUCLC | IMAXBEL);
tty.c_iflag &= ~(IXON | IXOFF | IXANY); /* no SW flowcontrol */
//tty.c_iflag |= ~IXON; //try ixon
tty.c_oflag &= ~OPOST;
tty.c_cc[VEOL] = 0;
tty.c_cc[VEOL2] = 0;
tty.c_cc[VEOF] = 0x04;
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
printf("Error from tcsetattr: %s\n", strerror(errno));
return -1;
}
return 0;
}
int main()
{
char *portname = SERIALTERMINAL;
int fd;
int wlen;
//fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC); original version
fd = open(portname, O_RDONLY | O_NOCTTY);
if (fd < 0) {
printf("Error opening %s: %s\n", portname, strerror(errno));
return -1;
}
/*baudrate 115200, 8 bits, no parity, 1 stop bit */
set_interface_attribs(fd, B115200);
/* simple canonical input */
do {
unsigned char buf[700];
unsigned char *p;
int rdlen;
rdlen = read(fd, buf, sizeof(buf) - 1);
if (rdlen > 0) {
buf[rdlen] = 0;
printf("%s", buf);
} else if (rdlen < 0) {
printf("Error from read: %d: %s\n", rdlen, strerror(errno));
} else { /* rdlen == 0 */
printf("Nothing read. EOF?\n");
}
/* repeat read */
} while (1);
}
When the program is run it doesn't show any output.
Going back out of CRTSCTS mode by swapping:
tty.c_cflag |= ~CRTSCTS;
with
tty.c_cflag &= ~CRTSCTS;
the program will show output but it is then not in the CRTSCTS mode which I need in order to prevent sending a DTR signal which results in an Arduino reset.
I have tried quite a few different options after reading through the Termios documentation: http://man7.org/linux/man-pages/man3/termios.3.html but to no avail.
So the question is what combination of options will allow reading from the serial port without sending a DTR signal?

Accessing the Serial Port in Linux in C

I am trying to write and read data through serial port to a USB device in linux.I am able to write the data but I am not read the complete data that the USB device is sending to me.The underlying code is mine.Please do point out any mistake if so.
#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
#include<fcntl.h>
#include<termios.h>
#include<unistd.h>
#define SERIAL_PORT_PATH "/dev/ttyACM0"
struct termios SerialPortSettings;
unsigned char Buffer[256] = {0X01,0X04,0X00,0X4B,0x01,0XB1};
int Serial_Port_Descriptor = 0;
int Open_flag = O_RDWR | O_NOCTTY | O_NDELAY;
int Set_Nonblock_Open_flag();
int Serial_Port_Configuring();
int Read_Serial_Port();
int main()
{
Serial_Port_Descriptor = open(SERIAL_PORT_PATH,Open_flag);
if(Serial_Port_Descriptor > 0)
{
printf("Serial_Port has been Opened \n");
Set_Nonblock_Open_flag();
}
else
{
perror("Error:");
}
Serial_Port_Configuring();
write(Serial_Port_Descriptor,&Buffer,sizeof(Buffer));
sleep(2);
while(1)
{
Read_Serial_Port();
}
close(Serial_Port_Descriptor);
return 0;
}
int Set_Nonblock_Open_flag()
{
Open_flag = fcntl(Serial_Port_Descriptor,F_GETFL,Open_flag);
if(Open_flag == -1)
{
return -1;
}
else if (0)
{
Open_flag |= O_NONBLOCK;
printf("The Flag is set to Nonblock \n");
}
else
{
Open_flag &= ~O_NONBLOCK;
}
return fcntl(Serial_Port_Descriptor,F_SETFL,Open_flag);
}
int Serial_Port_Configuring()
{
tcgetattr(Serial_Port_Descriptor,&SerialPortSettings);
cfsetispeed(&SerialPortSettings,B115200);
cfsetospeed(&SerialPortSettings,B115200);
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 &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXOFF | IXANY);
SerialPortSettings.c_lflag &= ~(ICANON | ECHO | ECHONL | ISIG | IEXTEN);
SerialPortSettings.c_oflag &= ~OPOST; /* No Ouptut Processing */
SerialPortSettings.c_cc[VMIN] = 1; /* Read atleast 1 character */
SerialPortSettings.c_cc[VTIME] = 0; /* Wait Indefinitely */
tcflush(Serial_Port_Descriptor,TCIOFLUSH);
if(tcsetattr(Serial_Port_Descriptor,TCSANOW,&SerialPortSettings) != 0)
{
printf("Error: The Settings are not been Configured \n");
return -1;
}
else
{
printf("Settings have been Configured \n");
}
return 0;
}
int Read_Serial_Port()
{
int Serial_Port_Read = read(Serial_Port_Descriptor,&Buffer,sizeof(Buffer));
if(Serial_Port_Read < 0)
{
fputs("Read of bytes() has failed \n",stderr);
return -1;
}
else if(Serial_Port_Read > 0)
{
printf("%d bytes has been read \n",Serial_Port_Read);
for(int i=0;i <= Serial_Port_Read;i++)
{
printf("%02X",(unsigned char)Buffer[i]);
}
}
return 0;
}

serial port getting stuck at read() data

I have connected an HC-05 bluetooth module to microZed board and trying to send and receive data via uart in Linux, Now the the send code is working when I send data from my board to the app it works perfectly given below is my code for sending
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <pthread.h> /* for threads */
#include <termios.h> /* uart */
#include <fcntl.h> /* uart */
#include <unistd.h> /* uart */
#define MODEMDEVICE "/dev/ttyPS1"
int main()
{
printf("Opening %s\n", MODEMDEVICE);
int portfd = open(MODEMDEVICE, O_RDWR | O_NOCTTY);
if (portfd < 0) {
printf("ERROR coultn't open %s\n", MODEMDEVICE);
return -1;
}
/* set terminal settings */
struct termios tty;
tcgetattr(portfd, &tty);
cfsetospeed(&tty, (speed_t)B9600);
cfsetispeed(&tty, (speed_t)B9600);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
tty.c_iflag = IGNBRK;
tty.c_lflag = ICANON;
tty.c_oflag = 0;
tty.c_cflag |= CLOCAL | CREAD;
tty.c_cc[VTIME] = 0;
tty.c_cc[VMIN] = 1;
tty.c_iflag &= ~(IXON | IXOFF | IXANY);
tty.c_cflag &= ~(PARENB | PARODD);
tty.c_cflag |= PARENB;
tty.c_cflag &= ~CSTOPB;
tcsetattr(portfd, TCSANOW, &tty);
/* sleep a bit */
usleep(200000);
/* flush possible characters in the input buffer */
tcflush(portfd, TCIOFLUSH);
char buf;
int i;
while(1) {
buf++;
write(portfd, &buf, 1);
write(portfd, "\r\n", 2);
usleep(200000);
}
return 0;
}
Now the problem arises when I try send data from the app to the Bluetooth module , sometimes the program stops and says "random nonblocking pool initialized" or it gets stuck at i = read(portfd, buf, 20); in the code given below
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <pthread.h> /* for threads */
#include <termios.h> /* uart */
#include <fcntl.h> /* uart */
#include <unistd.h> /* uart */
#define MODEMDEVICE "/dev/ttyPS1"
int main()
{
printf("Opening %s\n", MODEMDEVICE);
int portfd = open(MODEMDEVICE, O_RDWR | O_NOCTTY);
if (portfd < 0) {
printf("ERROR coultn't open %s\n", MODEMDEVICE);
return -1;
}
printf("hello1\n\r");
/* set terminal settings */
struct termios tty;
tcgetattr(portfd, &tty);
cfsetospeed(&tty, (speed_t)B9600);
cfsetispeed(&tty, (speed_t)B9600);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8;
tty.c_iflag = IGNBRK;
tty.c_lflag = ICANON;
tty.c_oflag = 0;
tty.c_cflag |= CLOCAL | CREAD;
tty.c_cc[VTIME] = 0;
tty.c_cc[VMIN] = 1;
tty.c_iflag &= ~(IXON | IXOFF | IXANY);
tty.c_cflag &= ~(PARENB | PARODD);
tty.c_cflag |= PARENB;
tty.c_cflag &= ~CSTOPB;
tcsetattr(portfd, TCSANOW, &tty);
/* sleep a bit */
printf("hello2\n\r");
usleep(200000);
/* flush possible characters in the input buffer */
tcflush(portfd, TCIOFLUSH);
char buf[20];
printf("hello3\n\r");
int i;
while(1) {
i = read(portfd, buf, 20);
printf("hello\n\r");
buf[i] = 0;
printf("%s", buf);
printf("\n\r");
}
return 0;
}
Any suggestions how can I fix this ?
I found the solution , first mistake was pointed out by this post .
I should have set time to wait for character read to greater than 0 and minimum number of characters to read to zero
tty.c_cc[VTIME] = 5;
tty.c_cc[VMIN] = 0;
and I needed to set the tty.c_lflag flag to 0 to enable raw input instead of canonical, now the code is reading the data constantly

Linux - reading from serial port error in C (Resource temporarily unavaliable)

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

Resources