read() in c raspberry pi gsm-module - c

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

Related

read from serial port fails when called twice

Resolved Bellow: Wrong number of characters in read/write
I am attempting to read and write to a serial port, and I don't have much experience in C/C++.
My port is connected to a motion controller/driver that requires the following settings:
Baudrate: 57600
Data bits: 8
Parity: None
Stop bits: 1
Flow control: Xon/Xoff
Terminator CRLF
Problem: The code will write and read my first command,but it hangs on the second read call. I am currently blocking until I receive at least one character, but each written command should generate a return.
Additional information: I can only run the first write/read if I first unplug the remote and plug it back in. Alternatively, I can open a cool term window, setup my serial port and run a few commands. When I close the cool term window I will be able to write/read once.
Current Code:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <time.h>
#include <iostream>
using namespace std;
int open_port(void)
{
int fd;
// open file descriptor
fd = open("/dev/cu.USA19H41P1.1", O_RDWR | O_NOCTTY);
// if unsucessful
if (fd == -1)
{
printf("open_port: unable to open port. \n");
}
else
{
// remains open across executables
fcntl(fd, F_SETFL, 0);
printf("port is open. \n");
}
return (fd);
}
int configure_port(int fd)
{
// store terminal port settings
struct termios port_settings;
memset(&port_settings, 0, sizeof port_settings);
if(tcgetattr(fd, &port_settings) !=0)
{
printf("error tcgetattr \n");
cout << errno;
}
port_settings.c_iflag = 0;
port_settings.c_oflag = 0;
port_settings.c_lflag = 0;
port_settings.c_cflag = 0;
// flush
tcflush(fd, TCIOFLUSH);
// set baud rate
cfsetispeed(&port_settings, B57600);
cfsetospeed(&port_settings, B57600);
// xon/xoff requirment
port_settings.c_iflag |= IXON;
port_settings.c_iflag |= IXOFF;
// no parity requirement
port_settings.c_cflag &= ~PARENB;
// one stop bin requirement
port_settings.c_cflag &= ~CSTOPB;
// turn on read
port_settings.c_cflag |= CREAD;
port_settings.c_cflag |= CLOCAL;
// no character processing and 8 bit input
port_settings.c_cflag &= ~CSIZE;
port_settings.c_cflag |= CS8;
// one character blocking
port_settings.c_cc[VMIN] = 1;
port_settings.c_cc[VTIME] = 5;
// apply above settings
if(tcsetattr(fd,TCSANOW, &port_settings) != 0)
{
printf("error tcsetattr \n");
cout << errno;
}
// flush buffers one more time
tcflush(fd, TCIOFLUSH);
return(fd);
}
int read_write(int fd)
{
// write to serial port
ssize_t size=write(fd, "1va?\r\n", 8);
// wait until output is transmitted
tcdrain(fd);
// read from serial port
char buf[100];
memset(buf, '\0', sizeof buf);
ssize_t size2=read(fd, &buf, sizeof(buf));
cout << buf << endl;
return(fd);
}
int main(void)
{
// open port
int fd = open_port();
// store old settings
struct termios old_settings;
memset(&old_settings, 0, sizeof old_settings);
tcgetattr(fd,&old_settings);
// configure port
configure_port(fd);
// write/read first command ("1va?\r\n")
read_write(fd);
// write read second command ("1pa?\r\n")
ssize_t size=write(fd, "1pa?\r\n", 8);
tcdrain(fd);
char buf[100];
memset(buf, '\0', sizeof buf);
ssize_t size3=read(fd, &buf, sizeof(buf));
cout << buf;
//close serial port
close(fd);
tcsetattr(fd, TCSANOW, &old_settings);
return 0;
}
Here is some example code on working with Serial ports setting the correct flags and the baud rate:
Provide your code and and more thorough explanation for us to resolve your issue. What do you mean by write and read my first command? Is your device still responsive after this command? Isn't the second command sent?

fgets not blocking in descriptor promoted to stream

I am using fgets in a small C program - running under Ubuntu - to read data coming from Arduino via its FTDI USB/Serial converter.
I am using low level I/O function from GNU libc (since I want - in the future - be able to control baud rate etc) and then promoting from descriptor to stream in order to use higher leve I/O functions.
The observed behaviour of my program suggests that the fgets function does not block until the line terminator is acquired (as in my opinion it should do).
Any explanation?
The codes of my programs are here
-> PC side:
#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 */
#define bufLen 81
int main(void) {
int fd; /* File descriptor for the port */
FILE * f; /* port will be identified also as stream 'f'*/
char buf[bufLen];
fd = open("/dev/ttyACM0", O_RDWR | O_NOCTTY);
if (fd == -1) {perror(""); return errno;}
else {
f = fdopen(fd, "r+t");
while (1) {
if (fgets(buf,bufLen,f)) {
printf("{%s}\n",buf);
sleep(1);
} else {
{perror("ahhhh! ");}
}
}
}
return 0;
}
-> Arduino side:
char ar[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ ";
int k1 = 0, k2 = 0;
void setup() {
// initialize serial:
Serial.begin(9600);
}
void loop() {
Serial.print(ar[k1]);
k1 = (++k1) % 26;
k2 = (++k2) % 5;
if (k2==0) {Serial.println();}
delay(300);
}
And the result of run..
xxx#RevoR3600:~/CProg$ ./SerialPort
ahhhh! : Success
ahhhh! : Success
ahhhh! : Success
...
... (many identical lines...)
...
ahhhh! : Success
ahhhh! : Success
{AP}
{A}
{BCD}
{E
}
{FGHIJ
}
^C
xxx#RevoR3600:~/CProg$
After sleeping one night on it and two more hours of digging this site (and testing) I finally came across a solution right here; sorry I was not able to find it before posting (I can't figure out why); now it is matter for me to study exactly why the found solution is working (and why there is still a minor problem: some strange characters acquired on starting).
Thanks (and apology) to everybody has read my post.
Here is the working (test) code:
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<unistd.h>
#include<fcntl.h>
#include<termios.h>
#define bufLen 81
int main() {
char buf[bufLen];
struct termios tty;
FILE * f;
int fd=open("/dev/ttyACM0",O_RDWR | O_NOCTTY);
if(fd == -1) {
perror("Unable to open /dev/ttyACM1\n");
return -1;
} else {
if(tcgetattr(fd, &tty)!=0) {perror("tcgetatt() error"); return -1;}
else {
cfsetospeed(&tty, B9600);
cfsetispeed(&tty, B9600);
tty.c_cflag &= ~PARENB;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8;
tty.c_cflag &= ~CRTSCTS;
tty.c_cflag |= CLOCAL | CREAD;
tty.c_iflag |= IGNPAR | IGNCR;
tty.c_iflag &= ~(IXON | IXOFF | IXANY);
tty.c_lflag |= ICANON;
tty.c_oflag &= ~OPOST;
tcsetattr(fd, TCSANOW, &tty);
if (!(f = fdopen(fd, "r+t"))) {perror("fdopen() error"); return -1;}
while (1) {
fgets(buf,bufLen,f);
printf("%s--\n",buf);
}
}
}
close(fd);
return 0;
}

Read from serial port linux

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.

Can write to, but can't read from serial port ttyS0 in linux C 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);
}
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.

Reading and writing from serial port,through loopback in c in linux

I am on a program to read and write from and to serial port using serial crosscable and loopback by soring 2nd and 3rd pin of cable. I am able to write but not able to read.
in read output it is showing 0 as the no. of bytes read by it. It is not showing error as -1 .
#include <stdio.h> // standard input / output functions
#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 definitionss
#include <time.h> // time calls
#include <sys/ioctl.h>
int open_port(void)
{
int fd; // file description for the serial port
fd = open("/dev/ttyS1", O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
if(fd == -1) // if open is unsucessful
{
perror("open_port: Unable to open /dev/ttyS0 - ");
}
else
{
fcntl(fd, F_SETFL, 0);
}
printf("%d",fd);
return(fd);
}
int configure_port(int fd) // configure the port
{
struct termios port_settings; // structure to store the port settings in
cfsetispeed(&port_settings, B9600); // set baud rates
cfsetospeed(&port_settings, B9600);
port_settings.c_cflag |= ( CLOCAL | CREAD );
port_settings.c_cflag &= ~PARENB; // set no parity, stop bits, data bits
port_settings.c_cflag &= ~CSTOPB;
port_settings.c_cflag &= ~CSIZE;
port_settings.c_cflag |= CS8;
tcflush( fd, TCIOFLUSH );
tcsetattr(fd, TCSANOW, &port_settings); // apply the settings to the port
return(fd);
}
int main()
{
int fd= open_port();
int d=configure_port(fd);
printf("%d",d);
int bytes;
char mk[10];
scanf("%s",&mk);
int w=write(fd,mk,strlen(mk));
int y=ioctl(fd,FIONREAD,&bytes);
printf("%d\n",w);
perror("write");
printf("%d",y);
char buffer[80];
char *data;
int nbytes;
data=buffer;
nbytes=read(fd,data,5);
printf("the outputis \n%d\n\n",nbytes);
perror("read");
while(nbytes > 0)
{printf("datmukun %d\n\n",nbytes);
data+=nbytes;
if (data[-1]=='\n'||data[-1]=='\r')
break;
}
return 0;
}
Depending on your TTY-driver the O_NDELAY and O_NONBLOCK can cause read to behave in a non-blocking manner. Therefore, it is very likely that the data has not been received by the time you call read. If you remove those flags, you should block in read until at least one character is available.
you must wait for a while for the data to become available. you can do this like the following:
very simply and just for test purpose by creating a small delay using a while loop and a sleep() function inside it and possibly a counter to try for a number of times.
you can use select() function on your file descriptor to let your process go to sleep for a while and get notified when the data is available or the timeout has reached.

Resources