I'm trying to read from serial port, but always get 0 (zero) characters back. Already read the "Serial Programming Guide for POSIX Operating Systems", but can't find out why the program not waiting (blocking).
The code:
#include <stdio.h> /* Standard input/output definitions */
#include <string.h> /* String function definitions */
#include <unistd.h> /* UNIX standard function definitions */
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
void main()
{
printf("Hello world\n");
int fd; /* File descriptor for the port */
int n;
int bytes;
char c;
char buffer[10];
char *bufptr;
struct termios options;
fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1) {
perror("open_port: Unable to open /dev/ttyUSB0 - ");
}
else {
fcntl(fd, F_SETFL, FNDELAY);
}
tcgetattr( fd, &options );
/* SEt Baud Rate */
cfsetispeed( &options, B9600 );
cfsetospeed( &options, B9600 );
//I don't know what this is exactly
options.c_cflag |= ( CLOCAL | CREAD );
// Set the Charactor size
options.c_cflag &= ~CSIZE; /* Mask the character size bits */
options.c_cflag |= CS8; /* Select 8 data bits */
// Set parity - No Parity (8N1)
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
// Disable Hardware flowcontrol
// options.c_cflag &= ~CNEW_RTSCTS; -- not supported
// Enable Raw Input
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
// Disable Software Flow control
options.c_iflag &= ~(IXON | IXOFF | IXANY);
// Chose raw (not processed) output
options.c_oflag &= ~OPOST;
if ( tcsetattr( fd, TCSANOW, &options ) == -1 )
printf ("Error with tcsetattr = %s\n", strerror ( errno ) );
else
printf ( "%s\n", "tcsetattr succeed" );
fcntl(fd, F_SETFL, 0);
// Write to the port
n = write(fd, "1", 1);
if (n < 0) {
fputs("write() of 1 bytes failed!\n", stderr);
}
// Read from the port
//fcntl(fd, F_SETFL, FNDELAY);
bytes = read(fd, &buffer, sizeof(buffer));
printf("number of bytes read is %d\n", bytes);
printf("%s\n", buffer);
//perror ("read error:");
close(fd);
}
This information was originally from the Serial Programming Guide1.
The reason you are getting a 0 return value is because of this line:
fcntl(fd, F_SETFL, FNDELAY);
If you want a normal blocking read, unset that flag.
1. http://www.easysw.com/~mike/serial/serial.html#2_5_4 (now defunct)
You are using O_NDELAY
O_NONBLOCK or O_NDELAY
When possible, the file is opened in non-blocking mode. Neither the open() nor any subsequent operations on the file
descriptor which is returned will cause the calling process to
wait. For the handling of FIFOs (named pipes), see also fifo(7). For
a discussion of the effect of O_NONBLOCK in conjunction with mandatory
file locks and with file leases, see fcntl(2).
EDIT: You're doing the same thing in your fcntl() call, as well.
Related
The C read() function frequently get blocked, especially if there is nothing connected on the Gpio pins (tx / rx), but I just hoped it would stop for itself when there is no conection, the same when there is wire conection but no data to read, but it just get blocked until I force it to finish.
Open
fd = open("/dev/serial0", O_RDWR | O_NDELAY | O_NOCTTY | O_NONBLOCK);
Read
n = read( fd, value, 1 );
if (n < 0) {
printf ( "Error = %s\n", strerror( errno ) );
}
else if (n == 0) {
printf ( "Read Nothing...\n");
}
Set attribs
int setAttr(int fd)
{
//Read the configureation of the port
struct termios options;
tcgetattr( fd, &options );
//Set Baud Rate
cfsetispeed( &options, B9600 );
cfsetospeed( &options, B9600 );
//Setting other Port Stuff
options.c_cflag &= ~PARENB; /*Make 8n1 */
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE; /* Mask the character size bits */
options.c_cflag |= CS8; /* Select 8 data bits */
options.c_cflag &= ~CRTSCTS; /* No flow control */
options.c_cc[VMIN] = 0; /*READ doesn't block */
options.c_cc[VTIME] = 1; /* 0.1 seconds read timout */
options.c_cflag |= CREAD | CLOCAL; /* Turn on READ & ignore crtl lines */
//Make raw
cfmakeraw(&options);
//Flush port, then applies attributes
tcflush(fd, TCIOFLUSH);
return tcsetattr( fd, TCSANOW, &options );
}
For a UART port with nothing but tx/rx pins, there is no distinct "nothing connected" status. For the functionality you want, the port would need DCE/DTR pins and the CLOCAL flag (ignore modem control lines) would have to be removed from the termios settings.
I just add the code below, after open() and it's not blocked anymore when tx/rx pins are not connected. Probably the port was going blocked after open().
if (fd == -1)
{
/*
* Could not open the port.
*/
perror("open_port: Unable to open /dev/serial0 - ");
}
else fcntl(fd, F_SETFL, O_NONBLOCK);
I am working on a project where i can send sms with my raspberry pi thats connected to a sim300s module thrue a usb to serial connection.
problem:
sim300 doesnt detect the simcard , harware malfunction, i have ordered a new one. Until then i want to check if the connection works between the 2.
Now i want to send at command and receive OK(or something like that) Here is my code:
the value that is stored in string buf is TATATATAT.... etc.. etc..
Can someone explain why i am not getting OK back? Am i doing something wrong?
#include <stdio.h> /* Standard input/output definitions */
#include <string.h> /* String function definitions */
#include <unistd.h> /* UNIX standard function definitions */
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
/*
* 'open_port()' - Open serial port 1.
*
* Returns the file descriptor on success or -1 on error.
*/
int main(int argc, char* argv[])
{
puts("start open_port");
open_port();
puts("open_port started ");
}
int
open_port(void)
{
char reply;//not shure if its gonna be used
struct termios options;
int n=0;
int fd; /* File descriptor for the port */
char buf[50];
int valueBytes;
int x = 0;
fd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY ); //| O_NDELAY);
if (fd == -1)
{//could not open port
fprintf(stderr, "open_port: Unable to open /dev/ - %s\n",
strerror(errno));
}
printf("%d",fd);
tcgetattr(fd, &options); //get current options for port
puts("test1");
cfsetispeed(&options, B9600);//set baud rate
cfsetospeed(&options, B9600);//set baud rate
puts("\n2");
options.c_cflag |= (CLOCAL | CREAD | CRTSCTS);//enable the receiver and set local mode
puts("\n3");
options.c_cflag &= ~PARENB;//disable parity generation and detection
options.c_cflag &= ~CSTOPB;//Use one stop bit per character
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;//use 8 bits to send or receive characters
options.c_lflag &= ~(ICANON | /* Enable canonical input (else raw) */
ECHO | /*Enable echoing of input characters */
ECHOE | /*Echo erase character as BS-SP-BS*/
ISIG); /*Enable SIGINTR, SIGSUSP, SIGDSUSP, and SIGQUIT signals*/
tcsetattr(fd, TCSANOW, &options);//TCSANOW change values immediately
puts("4");
n = write(fd, "AT\r", 4); // n = write(fd, "AT+CMGF=1\r", 10);
if (n < 0){
puts("write() of 4 bytes failed!");}
if(read(fd, buf, 2) < 0){
puts("it doesnt work"); }
fcntl(fd, F_SETFL, FNDELAY);
valueBytes=read(fd, buf,50);
printf("%d",valueBytes);
if(valueBytes < 0){
printf(strerror(errno));}
puts("6.3");
for(x; x<50;x++){
printf("%c",buf[x]);
}
close(fd);
puts("7");
return (fd);
puts("8");
}
So I searched around, and couldn't exactly find what I needed. I need help reading and writing binary data over a serial port, and would appreciate any advice you may have. Please note, I asked a question similar to this earlier when I was at a different stage of this project.
Below are programs. The first program opens a file "test.jpg", reads it in binary mode and stores the result in a buffer. It then closes the file, and is supposed to send that file over a serial port.
The second program creates a file called "testout.jpg", and is supposed to read in the data sent from the previous program.
I have a hunch that the problem in my code lies in the second program. Perhaps I need to use fread for that too? I tried, but I cannot figure out how to implement it for a serial port as I am relatively new to programming.
Many thanks for your time.
Serial write:
#include <stdio.h> /* Standard input/output definitions */
#include <string.h> /* String function definitions */
#include <unistd.h> /* UNIX standard function definitions */
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
#include <stdlib.h>
int main()
{
//writing
int writeport = open_port("/dev/ttyUSB0");
//open file
FILE *file;
char *buffer;
int fileLen;
file = fopen("test.jpg", "rb");
//get file size
fseek(file, 0, SEEK_END);
fileLen = ftell(file);
fseek(file, 0, SEEK_SET);
buffer = (char *)malloc(fileLen + 1);
//read file contents
fread(buffer, fileLen, 1, file);
fclose(file);
int n = write(writeport, buffer, fileLen + 1);
if (n < 0)
fputs("write() of bytes failed!\n", stderr);
//closing ports
close(writeport);
}
int open_port(char str[])
{
int fd = open(str, O_RDWR | O_NOCTTY | O_NONBLOCK); // ?? NDELAY or NONBLOCK?
if (fd == -1)
{
perror("open_port: Unable to open /dev/ttyS0 - ");
}
else
fcntl(fd, F_SETFL, 0);
struct termios options;
tcgetattr(fd, &options); //this gets the current options set for the port
// setting the options
cfsetispeed(&options, B9600); //input baudrate
cfsetospeed(&options, B9600); // output baudrate
options.c_cflag |= (CLOCAL | CREAD); // ?? enable receicer and set local mode
//options.c_cflag &= ~CSIZE; /* mask the character size bits */
options.c_cflag |= CS8; /* select 8 data bits */
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // choosing raw input
options.c_iflag &= ~INPCK; // disable parity check
options.c_iflag &= ~(IXON | IXOFF | IXANY); // disable software flow control
options.c_oflag |= OPOST; // ?? choosing processed output
options.c_cc[VMIN] = 0; // Wait until x bytes read (blocks!)
options.c_cc[VTIME] = 0; // Wait x * 0.1s for input (unblocks!)
// settings for no parity bit
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
tcsetattr(fd, TCSANOW, &options); //set the new options ... TCSANOW specifies all option changes to occur immediately
return (fd);
}
Serial read:
#include <stdio.h> /* Standard input/output definitions */
#include <string.h> /* String function definitions */
#include <unistd.h> /* UNIX standard function definitions */
#include <fcntl.h> /* File control definitions */
#include <errno.h> /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */
int main()
{
//reading
int readport = open_port("/dev/ttyUSB1");
//open resultant file
FILE *file;
//system("rm testout.jpg");
file = fopen("testout.jpg", "wb");
//trying to read one character at a time
char buff;
int n = 1;
while (n > 0)
{
n = read(readport, &buff, 1);
//printf("%c", buff, buff);
**//I tried these three methods, with little success**
//fprintf(file, "%c", buff);
//fwrite(&buff, 1, 1, file);
//write(file, &buff, 1);
}
//closing ports
close(readport);
fclose(file);
}
int open_port(char str[])
{
int fd = open(str, O_RDWR | O_NOCTTY | O_NONBLOCK); // ?? NDELAY or NONBLOCK?
if (fd == -1)
{
perror("open_port: Unable to open /dev/ttyS0 - ");
}
else
fcntl(fd, F_SETFL, 0);
struct termios options;
tcgetattr(fd, &options); //this gets the current options set for the port
// setting the options
cfsetispeed(&options, B9600); //input baudrate
cfsetospeed(&options, B9600); // output baudrate
options.c_cflag |= (CLOCAL | CREAD); // ?? enable receicer and set local mode
//options.c_cflag &= ~CSIZE; /* mask the character size bits */
options.c_cflag |= CS8; /* select 8 data bits */
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); // choosing raw input
options.c_iflag &= ~INPCK; // disable parity check
options.c_iflag &= ~(IXON | IXOFF | IXANY); // disable software flow control
options.c_oflag |= OPOST; // ?? choosing processed output
options.c_cc[VMIN] = 0; // Wait until x bytes read (blocks!)
options.c_cc[VTIME] = 0; // Wait x * 0.1s for input (unblocks!)
// settings for no parity bit
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
tcsetattr(fd, TCSANOW, &options); //set the new options ... TCSANOW specifies all option changes to occur immediately
return (fd);
}
file = fopen( "zname.jpg", "wb" );
while (1) {
n = read(readport, &buff, 1);
if (n == -1) switch(errno) {
case EAGAIN: /* sleep() */
continue;
...
default: goto quit;
}
if (n ==0) break;
fputc(buff, file);
}
quit:
fclose (file);
...
Even better than sleep() and loop, would be to use select/poll. (You'd still have to check for EAGAIN)
I'm trying to learn how to program the ttyS0 serial port in Linux using C. I have another machine connected to my serial port sending alternating hex values of 5f and 6f about every two seconds. I've verified with other port monitoring apps that these values are appearing at the port. In my code I'm using a blocking read() into a 10 char length buffer. Even though my other machine is still sending data, read() blocks forever. If I include the line fcntl(fd, F_SETFL, FNDELAY); which sets read() to non-blocking read() always returns with a value of -1, meaning no data was in the UART buffer, and my for loop code just prints out random values that are in the buffer. So in short my assumption is that my code is not reading ttyS0 and I have no idea why. Below is my code, hopefully someone will see what's causing my problem and set me straight. By the way, I'm using Scientific Linux, I believe ttyS0 is com port 1, as it is in RedHat and Fedora. Aslo below is the output when i run the code. It seems to be writing to the COM port with no problems, but for a read it says its unavailable. Also it's clear that the buffer I'm printing out is just random values not data that's been read in. Thanks
console output
hello world
hi again
write error: : Success
wrote 4 bytes
number of bytes read is -1
read error:: Resource temporarily unavailable
4 8 120 -99 -73 -65 41 -120 4 8
should of put something out
Code
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
int main()
{
printf("hello world\n");
int n;
int fd;
char c;
int bytes;
char buffer[10];
char *bufptr;
int nbytes;
int tries;
int x;
struct termios options;
fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
if(fd == -1)
{
perror("open_port: Unable to open:");
}
else
{
fcntl(fd, F_SETFL, 0);
printf("hi again\n");
}
tcgetattr(fd, &options);
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
options.c_cflag &= ~( ICANON | ECHO | ECHOE |ISIG );
options.c_iflag &= ~(IXON | IXOFF | IXANY );
options.c_oflag &= ~OPOST;
tcsetattr(fd, TCSANOW, &options);
write(fd, "ATZ\r",4);
printf(" wrote\n");
bufptr = buffer;
fcntl(fd, F_SETFL, FNDELAY);
bytes = read(fd, bufptr, sizeof(buffer));
printf("number of bytes read is %d\n", bytes);
perror ("read error:");
for (x = 0; x < 10 ; x++)
{
c = buffer[x];
printf("%d ",c);
}
close(fd);
//puts(buffer[0]);
printf("\nshould of put something out \n");
return (0);
}
Try setting MIN and/or TIME values:
/*...*/
options.c_cc[VMIN] = 1; //read() will return after receiving 1 character
options.c_cc[VTIME] = 0; // == 0 - infinite timeout, != 0 - sets timeout in deciseconds
/*...*/
tcsetattr(fd, TCSANOW, &options);
The given example will set your read() to return after getting any symbol and to wait indefinitely for input. Naturally, you may play with these parameters as you see fit (e.g. set MIN to 10 if you want).
You may want to remove fcntl(fd, F_SETFL, FNDELAY); call for this to work though.
It is also wise to save previous termios settings and restore them before leaving your program.
I'm trying to learn how to program the ttyS0 serial port in Linux using C. I have another machine connected to my serial port sending alternating hex values of 5f and 6f about every two seconds. I've verified with other port monitoring apps that these values are appearing at the port. In my code I'm using a blocking read() into a 10 char length buffer. Even though my other machine is still sending data, read() blocks forever. If I include the line fcntl(fd, F_SETFL, FNDELAY); which sets read() to non-blocking read() always returns with a value of -1, meaning no data was in the UART buffer, and my for loop code just prints out random values that are in the buffer. So in short my assumption is that my code is not reading ttyS0 and I have no idea why. Below is my code, hopefully someone will see what's causing my problem and set me straight. By the way, I'm using Scientific Linux, I believe ttyS0 is com port 1, as it is in RedHat and Fedora. Aslo below is the output when i run the code. It seems to be writing to the COM port with no problems, but for a read it says its unavailable. Also it's clear that the buffer I'm printing out is just random values not data that's been read in. Thanks
console output
hello world
hi again
write error: : Success
wrote 4 bytes
number of bytes read is -1
read error:: Resource temporarily unavailable
4 8 120 -99 -73 -65 41 -120 4 8
should of put something out
Code
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
int main()
{
printf("hello world\n");
int n;
int fd;
char c;
int bytes;
char buffer[10];
char *bufptr;
int nbytes;
int tries;
int x;
struct termios options;
fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);
if(fd == -1)
{
perror("open_port: Unable to open:");
}
else
{
fcntl(fd, F_SETFL, 0);
printf("hi again\n");
}
tcgetattr(fd, &options);
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
options.c_cflag |= (CLOCAL | CREAD);
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
options.c_cflag &= ~( ICANON | ECHO | ECHOE |ISIG );
options.c_iflag &= ~(IXON | IXOFF | IXANY );
options.c_oflag &= ~OPOST;
tcsetattr(fd, TCSANOW, &options);
write(fd, "ATZ\r",4);
printf(" wrote\n");
bufptr = buffer;
fcntl(fd, F_SETFL, FNDELAY);
bytes = read(fd, bufptr, sizeof(buffer));
printf("number of bytes read is %d\n", bytes);
perror ("read error:");
for (x = 0; x < 10 ; x++)
{
c = buffer[x];
printf("%d ",c);
}
close(fd);
//puts(buffer[0]);
printf("\nshould of put something out \n");
return (0);
}
The following line will cause problems:
options.c_cflag &= CSTOPB;
It will reset all other bits of the c_cflag.
If you want to use 1 stop bit, then use:
options.c_cflag &= ~CSTOPB;
If you want to use 2 stop bits, then use:
options.c_cflag |= CSTOPB;
EDIT:
Also the following line cause problems:
fcntl(fd, F_SETFL, 0);
It will reset several important flags.