Logo Search packages:      
Sourcecode: smstools version File versions  Download package

modeminit.c

/*
SMS Server Tools
Copyright (C) Stefan Frings

This program is free software unless you got it under another license directly
from the author. You can redistribute it and/or modify it under the terms of
the GNU General Public License as published by the Free Software Foundation.
Either version 2 of the License, or (at your option) any later version.

http://www.meinemullemaus.de/
mailto: smstools@meinemullemaus.de
*/

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <regex.h>
#include "logging.h"
#include "alarm.h"

#ifdef SOLARIS
#include <sys/filio.h>
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <syslog.h>
#include <sys/ioctl.h>
#include <errno.h>
#include "extras.h"
#include "modeminit.h"

// The following functions are for internal use of put_command and therefore not in the modeminit.h.

int write_to_modem(char* command,int timeout)
{  
  int status=0;
  int timeoutcounter=0;
  int x=0;
  
  if (command && command[0])
  {
    if (rtscts)
    {
      ioctl(modem,TIOCMGET,&status);
      while (!(status & TIOCM_CTS))
      {
        usleep(100000);
        timeoutcounter++;
        ioctl(modem,TIOCMGET,&status);
        if (timeoutcounter>timeout)
        {
          writelogfile(LOG_ERR,"Modem is not clear to send");
          alarm_handler(LOG_ERR,"","Modem is not clear to send");
          return 0;
        }
      }
    }
    writelogfile(LOG_DEBUG,"-> %s",command);
    for(x=0;x<strlen(command);x++) 
    {
      if (write(modem,command+x,1)<1)
      {
        writelogfile(LOG_ERR,"Could not send character %c, cause: %s",command[x],strerror(errno));
        alarm_handler(LOG_ERR,"","Could not send character %c, cause: %s",command[x],strerror(errno));
        return 0;
      }
      if (send_delay)
        usleep(send_delay*1000);
      tcdrain(modem);
    }  
  }
  return 1;
}

// Read max characters from modem. The function returns when it received at 
// least 1 character and then the modem is quiet for timeout*0.1s.
// The answer might contain already a string. In this case, the answer 
// gets appended to this string.
int read_from_modem(char* answer,int max,int timeout)
{
  int count=0;
  int got=0;
  int timeoutcounter=0;
  int success=0;
  int toread=0;
  
  // Cygwin does not support TIOC functions, so we cannot use it.
  // ioctl(modem,FIONREAD,&available);    // how many bytes are available to read?

  do 
  {
    // How many bytes do I want to read maximum? Not more than buffer size -1 for termination character.
    count=strlen(answer);
    toread=max-count-1;
    if (toread<=0)
      break;
    // read data
    got=read(modem,answer+count,toread);
    // if nothing received ...
    if (got<=0)
    {
      // wait a litte bit and then repeat this loop
      got=0;
      usleep(100000);
      timeoutcounter++;
    }
    else  
    {
      // restart timout counter
      timeoutcounter=0;
      // append a string termination character
      answer[count+got]=0;
      success=1;      
    }
  }
  while (timeoutcounter < timeout);
  return success;
}

int put_command(char* command,char* answer,int max,int timeout,char* expect)
{
  char loganswer[2048];
  int timeoutcounter=0;
  regex_t re;

  // compile regular expressions
  if (expect && expect[0] && (regcomp(&re,expect, REG_EXTENDED|REG_NOSUB) != 0)) 
  {     
    fprintf(stderr,"Programming error: Modem answer %s is not a valid regepr\n",expect);
    exit(1);
  }  

  // clean input buffer
  // It seems that this command does not do anything because actually it 
  // does not clear the input buffer. However I do not remove it until I 
  // know why it does not work.
  tcflush(modem,TCIFLUSH);
  
  // send command
  if (write_to_modem(command,30)==0)
  {
    writelogfile(LOG_DEBUG,"Waiting 5 seconds");
    sleep(5);
    return 0;
  }
  writelogfile(LOG_DEBUG,"Command is sent, waiting for the answer");

  // wait for the modem-answer 
  answer[0]=0;
  timeoutcounter=0;
  do
  {
    read_from_modem(answer,max,2);  // One read attempt is 200ms

    // check if it's the expected answer
    if (expect && expect[0] && (regexec(&re, answer, (size_t) 0, NULL, 0)==0))
        break;
    timeoutcounter+=2;
  }
  // repeat until timout
  while (timeoutcounter<timeout);

  strncpy(loganswer,answer,sizeof(loganswer));
  cutspaces(loganswer);
  cut_emptylines(loganswer);
  writelogfile(LOG_DEBUG,"<- %s",loganswer);

  // Free memory used by regexp
  regfree(&re);

  return strlen(answer);
}

void setmodemparams() /* setup serial port */
{
  struct termios newtio;
  bzero(&newtio, sizeof(newtio));
  newtio.c_cflag = CRTSCTS | CS8 | CLOCAL | CREAD | O_NDELAY | O_NONBLOCK;
  if (! rtscts)
    newtio.c_cflag &= ~CRTSCTS;
  newtio.c_iflag = IGNPAR;
  newtio.c_oflag = 0;
  newtio.c_lflag = 0;
  newtio.c_cc[VTIME]    = 0;
  newtio.c_cc[VMIN]     = 0;
  cfsetispeed(&newtio,baudrate);
  cfsetospeed(&newtio,baudrate);
  tcsetattr(modem,TCSANOW,&newtio);
}

void initmodem()
{
  char command[100];
  char answer[500];
  int retries=0;
  int success=0;

  writelogfile(LOG_INFO,"Checking if modem is ready");
  retries=0;
  do
  {
    retries++;
    put_command("AT\r",answer,sizeof(answer),50,"(OK)|(ERROR)");
    if ( strstr(answer,"OK")==NULL && strstr(answer,"ERROR")==NULL)
    {
      // if Modem does not answer, try to send a PDU termination character
      put_command("\x1A\r",answer,sizeof(answer),50,"(OK)|(ERROR)");
    }
  }
  while ((retries<=10) && (! strstr(answer,"OK")));
  if (! strstr(answer,"OK"))
  {
    writelogfile(LOG_ERR,"Modem is not ready to answer commands");
    alarm_handler(LOG_ERR,"","Modem is not ready to answer commands");
    exit(3);
  }

  if (pin[0])
  {
    writelogfile(LOG_INFO,"Checking if modem needs PIN");
    put_command("AT+CPIN?\r",answer,sizeof(answer),50,"(\\+CPIN:.*OK)|(ERROR)");
    if (strstr(answer,"+CPIN: SIM PIN"))
    {
      writelogfile(LOG_NOTICE,"Modem needs PIN, entering PIN...");
      sprintf(command,"AT+CPIN=\"%s\"\r",pin);
      put_command(command,answer,sizeof(answer),300,"(OK)|(ERROR)");
      put_command("AT+CPIN?\r",answer,sizeof(answer),50,"(\\+CPIN:.*OK)|(ERROR)");
      if (strstr(answer,"+CPIN: SIM PIN"))
      {
        writelogfile(LOG_ERR,"Modem did not accept this PIN");
        alarm_handler(LOG_ERR,"","Modem did not accept this PIN");
        exit(2);
      }
      else if (strstr(answer,"+CPIN: READY"))
        writelogfile(LOG_INFO,"PIN Ready");
    }
    if (strstr(answer,"+CPIN: SIM PUK"))
    {
      writelogfile(LOG_CRIT,"Your PIN is locked. Unlock it manually");
      alarm_handler(LOG_CRIT,"","Your PIN is locked. Unlock it manually");
      exit(2);
    }
  }

  if (initstring[0])
  {
    writelogfile(LOG_INFO,"Initializing modem");
    put_command(initstring,answer,sizeof(answer),100,"(OK)|(ERROR)");
    if (strstr(answer,"ERROR"))
    {
      writelogfile(LOG_INFO,"Initializing modem (retry)");
      put_command(initstring,answer,sizeof(answer),100,"(OK)|(ERROR)");  
    } 
    if (strstr(answer,"OK")==0)
    {
      writelogfile(LOG_ERR,"Modem did not accept the init string");
      alarm_handler(LOG_ERR,"","Modem did not accept the init string");
      exit(3);
    }
  }

  if (initstring2[0])
  {
    writelogfile(LOG_INFO,"Continue initializing modem");
    put_command(initstring2,answer,sizeof(answer),100,"(OK)|(ERROR)");
    if (strstr(answer,"OK")==0)
    {
      writelogfile(LOG_ERR,"Modem did not accept the second init string");
      alarm_handler(LOG_ERR,"","Modem did not accept the second init string");
      exit(3);
    }
  }

  if ((strcmp(mode,"digicom")!=0))
  {
    writelogfile(LOG_INFO,"Checking if Modem is registered to the network");
    success=0;
    retries=0;
    do
    {
      retries++;
      put_command("AT+CREG?\r",answer,sizeof(answer),100,"(\\+CREG:.*OK)|(ERROR)");
      if (strstr(answer,"1"))
      {
        writelogfile(LOG_INFO,"Modem is registered to the network");
        success=1;
      }
      else if (strstr(answer,"5"))
      {
            // added by Thomas Stoeckel
            writelogfile(LOG_INFO,"Modem is registered to a roaming partner network");
      success=1;
      }
      else if (strstr(answer,"ERROR"))
      {
        writelogfile(LOG_INFO,"Ignoring that modem does not support +CREG command.");
      success=1;
      }
      else if (strstr(answer,"+CREG:"))
      {
        writelogfile(LOG_NOTICE,"Modem is not registered, waiting %i sec. before retrying",errorsleeptime);
        sleep(errorsleeptime);
      success=0;
      }
      else
      {
        writelogfile(LOG_ERR,"Error: Unexpected answer from Modem after +CREG?, waiting %i sec. before retrying",errorsleeptime);
      alarm_handler(LOG_ERR,"","Error: Unexpected answer from Modem after +CREG?, waiting %i sec. before retrying",errorsleeptime);
      sleep(errorsleeptime);
      success=0;
      }
    }
    while ((success==0)&&(retries<10));
  }

  if (success==0)
  {
    writelogfile(LOG_ERR,"Error: Modem is not registered to the network");
    alarm_handler(LOG_ERR,"","Error: Modem is not registered to the network");
    exit(3);
  }


  if ((strcmp(mode,"ascii")==0) || (strcmp(mode,"digicom")==0))
  {
    writelogfile(LOG_INFO,"Selecting ASCII mode 1");
    strcpy(command,"AT+CMGF=1\r");
  }
  else
  {
    writelogfile(LOG_INFO,"Selecting PDU mode 0");
    strcpy(command,"AT+CMGF=0\r");
  }

  retries=0;
  success=0;
  do
  {
    retries++;
    put_command(command,answer,sizeof(answer),50,"(OK)|(ERROR)");
    if (strstr(answer,"ERROR"))
    {
      writelogfile(LOG_NOTICE,"Waiting %i sec. before retrying",errorsleeptime);
      sleep(errorsleeptime);
    }
    else
      success=1;
  }
  while ((success==0)&&(retries<3));

  if (success==0)
  {
    writelogfile(LOG_ERR,"Error: Modem did not accept PDU mode");
    alarm_handler(LOG_ERR,"","Error: Modem did not accept PDU mode");
    exit(3);
  }

  if (smsc[0])
  {
    writelogfile(LOG_INFO,"Changing SMSC");
    sprintf(command,"AT+CSCA=\"+%s\"\r",smsc);
    put_command(command,answer,sizeof(answer),50,"(OK)|(ERROR)");
  }
}

void openmodem()
{
  modem = open(device, O_RDWR | O_NOCTTY | O_NONBLOCK);
  if (modem <0)
  {
    writelogfile(LOG_ERR,"Cannot open serial port, cause: %s",strerror(errno));
    alarm_handler(LOG_ERR,"","Cannot open serial port, error: %s",strerror(errno));
    exit(1);
  }

  tcgetattr(modem,&oldtio);
}


Generated by  Doxygen 1.6.0   Back to index