0

I'm trying to write a program that communicates with serial port which is connected to GSM modem. Using AT command to communicate with modem. Here's my code. Got it from http://tldp.org/HOWTO/Serial-Programming-HOWTO/x115.html - Canonical Input Processing.

It works fine when output returns single line. For example:

AT returns OK

And my problem is If i send AT+CPIN? which returns several lines for example:
+CPIN: SIM PIN
OK

but my program reads only +CPIN: SIM PIN and breaks.How to fix it ?

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>

#define BAUDRATE B38400            
#define dev "/dev/ttyUSB0"
#define _POSIX_SOURCE 1

#define FALSE 0
#define TRUE 1

volatile int STOP=FALSE; 

main()
{
  char pinn[20];
  char buf[255];
  int fd,res=0;
  printf("%s\n", dev);
  struct termios oldtio,newtio;
  fd = open(dev, O_RDWR | O_NOCTTY ); 
  if (fd <0) {perror(dev); exit(-1); }
  bzero(&newtio, sizeof(newtio));
  newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
  newtio.c_iflag = IGNPAR | ICRNL;
  newtio.c_oflag = 0;
  newtio.c_lflag = ICANON;
  newtio.c_cc[VMIN]     = 1;
  tcflush(fd, TCIFLUSH);
  tcsetattr(fd,TCSANOW,&newtio);


  if (fd < 0)
  {
      printf("Error opening serial port\n");
      exit(1);
  }
  while(1){

    scanf("%s",pinn);
    strcat(pinn,"\r");

    if (write(fd, pinn, strlen(pinn)) < strlen(pinn)) printf("Write error - %s \n", strerror(errno));
    pinn[strlen(pinn)-1]=0;
    while(1){
      res = read(fd,buf,255);
      buf[res]=0;
      buf[res-1]=0;
      if (res>1&&NULL==strstr(buf,pinn)) break;
    }
    printf("\"%s\"\n", buf);
  }
  close(fd);
}

code UPDATE removed duplicate read

Odko
  • 151
  • 1
  • 1
  • 8

1 Answers1

1

Besides other minor deficiencies of the code, your receiving while() loop will terminate if the returned string does not contain the command you initially sent (NULL==strstr(buff, pinn)).

This condition is obviously not met when you receive multiline results (as only the first line contains the AT command you sent).

You need to change that if you don't want it.

mfro
  • 3,286
  • 1
  • 19
  • 28
  • I actually don't understand that part. Originial code was `if (buf[0]=='z') STOP=TRUE;` (It's in url). How should i change it to receive multiline results ? – Odko Apr 13 '15 at 13:26
  • If you don't understand it, why did you change it? And why did you chage it the way it is now? Anyway, change that line to `if (res == 0) break;`. And while you are at it, change `buf[res - 1] = 0;` to `if (res > 0) buf[res - 1] = '\0'`. Not nice, but fixes a possible crash. – mfro Apr 13 '15 at 13:32
  • Your termios settings set the serial port to blocking (wait until data arrives). This is where your `read()` call is stuck now. Try adding `newtio.c_cc[VMIN] = 0;` and `newtio.c_cc[VTIME] = 5;` to your terminal settings. This will set the port to nonblocking (wait for half a second for data to arrive, then return). You must be prepared for `read()` to return 0 then, however. – mfro Apr 13 '15 at 13:51
  • changed `newtio.c_cc[VMIN] = 1;` to `newtio.c_cc[VMIN] = 0;` `newtio.c_cc[VTIME] = 5;` but same :( BTW when i send anything it returns next line. which means returning `OK` of `+CPIN: SIM PIN` `OK` . Just in case u might need this :) – Odko Apr 13 '15 at 14:05
  • That was clear - I told you, didn't I? Regarding the blocking: add `| O_NONBLOCK` to your `open()` options at the top. Forgot this before. – mfro Apr 13 '15 at 14:09