NetBSD-Users archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: Help on serial ports



This is my C code for opening the device. All of the termios stuff I wrote by 
looking at code in uucp, which I know to be working on netbsd. I don't know 
anything about tcl on netbsd. I suppose it is possible that you could turn my 
code into a small program which your script uses to connect to the device.

I have attached the whole source file to this email. Hope it helps. Maybe you 
can find a way to set the termios flags in tcl.


/* Open the specified device */
void openDevice(char *deviceName)
{
  struct termios term;
  int result;
  
  file = open(deviceName,O_RDWR|O_NONBLOCK,0);
  fprintf(log_file,"openDevice: file %d\n",file);
  if(file == -1)
  {
    fprintf(log_file,"openDevice: errno %d\n",errno);
  }
  DEBUG(TRUE,"deviceName",deviceName);
  
  memset(&term,0,sizeof(struct termios));
  term.c_iflag = IXON|IXOFF|IXANY|IMAXBEL|BRKINT;
  term.c_oflag = ONLCR|OXTABS|ONOCR|ONLRET;
  term.c_cflag = CREAD|CS8|HUPCL|CLOCAL;
  term.c_lflag = ECHOE|ECHOKE|ECHOCTL;
  term.c_cc[0] = '\0';
  term.c_ispeed = 9600;
  term.c_ospeed = 9600;
  result = tcsetattr(file,TCSADRAIN,&term);
  if(result == -1)
  {
    fprintf(log_file,"tcsetattr: errno %d\n",errno);
  }
}

Regards,
-- 
Michael Smith
+61 416 062 898
http://glitch.tl
#include <stdio.h>
#include <time.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <termios.h>
#include <signal.h>
#include <dirent.h>

#define BUFFERSIZE 1024
#define TRUE 1
#define FALSE 0
#define MAX_MESSAGES 100
#define SPOOL "/var/spool/smsd"

FILE *log_file;

/*
gcc -o smsd smsd.c
/home/smithm/src/smsd/smsd /dev/ugen0.02
*/

int match(char *buffer,char *string)
{
  return(!strncmp(buffer,string,strlen(string)));
}

/* The name of the configuration file */
char configuration[BUFFERSIZE];

#define VERBOSE_MESSAGES 100

int verbose = VERBOSE_MESSAGES;
int activityCount = 0;

void trace(int important,char *file,int line,char *identify,char *desc)
{
  char buffer[BUFFERSIZE];
  char timestamp[BUFFERSIZE];
  char *ch;
  time_t now;
  
  if(verbose || important)
  {
    if(verbose) verbose--;
    for(ch = buffer; *desc; desc++)
    {
      if(*desc == '\n' || *desc == '\r')
      {
        *ch = '\\';
        ch++;
        *ch = *desc == '\n' ? 'n' : 'r';
      }
      else
      {
        *ch = *desc;
      }
      ch++;
    }
    *ch = '\0';
    time(&now);
    strftime(timestamp,BUFFERSIZE,"%Y-%m-%d %T",gmtime(&now));
    fprintf(log_file,"%s: %s:%d (%s) %s 
[%s]\n",timestamp,file,line,VERSION,identify,buffer);
    fflush(log_file);
  }
}

#define DEBUG(important,identify,desc) 
trace(important,__FILE__,__LINE__,identify,desc)

int file;

void writeLine(char *string)
{
    int result;
    
    DEBUG(FALSE,"writeLine",string);
    result = write(file,string,strlen(string));
    if(result == -1)
    {
      fprintf(log_file,"writeLine: errno %d\n",errno);
    }
}

char scheduledDestination[BUFFERSIZE];
char scheduledMessage[BUFFERSIZE];
int messageScheduled = FALSE;
unsigned int messagesSent = 0;

void sendMessage()
{
  char buffer[BUFFERSIZE];
  
  sprintf(buffer,"AT+CMGS=\"%s\"\r%s",scheduledDestination,scheduledMessage);
  writeLine(buffer);
  buffer[0] = 26;
  buffer[1] = 0;
  writeLine(buffer);
  messageScheduled = FALSE;
  if(messagesSent++ > MAX_MESSAGES)
  {
    exit(0);
  }
}

void scheduleMessage(char *destination,char *message)
{
  DEBUG(TRUE,"scheduleMessage",destination);
  DEBUG(TRUE,"scheduleMessage",message);
  if(!destination[0] == '+')
  {
    DEBUG(TRUE,"Address must start with a + character",destination);
    return;
  }
  if(!strlen(destination) == 12)
  {
    DEBUG(TRUE,"Address must be characters long",destination);
    return;
  }
  if(!strlen(message) <= 140)
  {
    DEBUG(TRUE,"Message can not be longer than 140 characters",message);
    return;
  }
  strcpy(scheduledDestination,destination);
  strcpy(scheduledMessage,message);
  messageScheduled = TRUE;
  activityCount = 0;
}

int currentMessage;
int messageToDelete = 0;
int expectMessageText = FALSE;
char message[BUFFERSIZE];
char messageOrigin[BUFFERSIZE];

/* Transmit a CMGR command to retrieve a message */
void writeCMGR(int messageIndex)
{
  char buffer[BUFFERSIZE];
  
  currentMessage = messageIndex;
  message[0] = '\0';
  sprintf(buffer,"AT+CMGR=%d\n",messageIndex);
  writeLine(buffer);
}

#define MISSES  3
char currentAlarm[BUFFERSIZE] = "clear";
char alarmRecipient[BUFFERSIZE] = "+61416062898";

struct Host
{
  struct host *next;
  char hostName[BUFFERSIZE];
  int gracePeriod;
  time_t lastDetection;
};

struct Host *hosts = NULL;

/*
s5# stty -f /dev/tty00 -e
speed 9600 baud; 0 rows; 0 columns;
lflags: -icanon -isig -iexten -echo echoe -echok echoke -echonl echoctl
        -echoprt -altwerase -noflsh -tostop -flusho -pendin -nokerninfo
        -extproc
iflags: -istrip -icrnl -inlcr -igncr ixon ixoff ixany imaxbel -ignbrk
        brkint -inpck -ignpar -parmrk
oflags: -opost onlcr -ocrnl oxtabs onocr onlret
cflags: cread cs8 -parenb -parodd hupcl clocal -cstopb -crtscts -mdmbuf
        -cdtrcts
discard dsusp   eof     eol     eol2    erase   intr    kill    lnext   
^O      ^Y      ^D      <undef> <undef> ^?      ^C      ^U      ^V      
min     quit    reprint start   status  stop    susp    time    werase  
1       ^\      ^R      ^Q      ^T      ^S      ^Z      0       ^W      
*/
/* Open the specified device */
void openDevice(char *deviceName)
{
  struct termios term;
  int result;
  
  file = open(deviceName,O_RDWR|O_NONBLOCK,0);
  fprintf(log_file,"openDevice: file %d\n",file);
  if(file == -1)
  {
    fprintf(log_file,"openDevice: errno %d\n",errno);
  }
  DEBUG(TRUE,"deviceName",deviceName);
  
  memset(&term,0,sizeof(struct termios));
  term.c_iflag = IXON|IXOFF|IXANY|IMAXBEL|BRKINT;
  term.c_oflag = ONLCR|OXTABS|ONOCR|ONLRET;
  term.c_cflag = CREAD|CS8|HUPCL|CLOCAL;
  term.c_lflag = ECHOE|ECHOKE|ECHOCTL;
  term.c_cc[0] = '\0';
  term.c_ispeed = 9600;
  term.c_ospeed = 9600;
  result = tcsetattr(file,TCSADRAIN,&term);
  if(result == -1)
  {
    fprintf(log_file,"tcsetattr: errno %d\n",errno);
  }
}

/* Close the device */
void closeDevice()
{
  DEBUG(TRUE,"closing",deviceName);
  close(file);
}

/* Read the configuration file */
void readConfigurationFile(char *fileName)
{
  FILE *fin;
  char keyword[BUFFERSIZE];
  char line[BUFFERSIZE];
  
  fin = fopen(fileName,"r");
  while(fscanf(fin,"%s %s",keyword,line) != EOF)
  {
    if(!strcmp(keyword,"host"))
    {
      struct Host *host = (struct Host *) calloc(1,sizeof(struct Host));
      
      host->next = hosts;
      hosts = host;
      sscanf(line,"%s %d",host->hostName,&host->gracePeriod);
      time(&host->lastDetection);
      DEBUG(TRUE,"hostName",host->hostName);
    }
    if(!strcmp(keyword,"recipient"))
    {
      strcpy(alarmRecipient,line);
      DEBUG(TRUE,"recipient",alarmRecipient);
    }
    if(!strcmp(keyword,"device"))
    {
      openDevice(line);
    }
    if(!strcmp(keyword,"log"))
    {
      log_file = fopen(line,"a");
      DEBUG(TRUE,"logFile",line);
    }
  }
  fclose(fin);
}

/* Free the linked list of hosts */
void freeHosts(struct Host *host)
{
  if(host->next)
  {
    freeHosts(host->next);
  }
  free(host);
}

/* Close the configuration */
void closeConfiguration()
{
    freeHosts(hosts);
    hosts = NULL;
    closeDevice();
    DEBUG(TRUE,"Closing log file");
    fclose(log_file);
}

/* Check for alarms */
void checkForAlarms()
{
  char message[BUFFERSIZE];
  char command[BUFFERSIZE];
  int result;
  struct Host *host;
  time_t now;
  
  time(&now);
  message[0] = '\0';
  for(host = hosts; host; host = host->next)
  {
    sprintf(command,"ping -q -c 1 %s > /dev/null",host->hostName);
    DEBUG(TRUE,"checkForAlarms",command);
    result = system(command);
    if(result)
    {
      DEBUG(TRUE,"checkForAlarms:missed",host->hostName);
    }
    else
    {
      host->lastDetection = now;
    }
    if(now - host->lastDetection > host->gracePeriod)
    {
      strcat(message,host->hostName);
      strcat(message," ");
    }
  }
  if(strlen(message) == 0)
  {
    strcpy(message,"clear");
  }
  if(strcmp(message,currentAlarm))
  {
    verbose = VERBOSE_MESSAGES;
    strcpy(currentAlarm,message);
    scheduleMessage(alarmRecipient,currentAlarm);
  }
}

int stopScheduled = FALSE;
int rebootScheduled = FALSE;
int commOK = FALSE;
int heartBeatIndex = 21;

void update()
{
  if(!commOK)
  {
    writeLine("AT\r\n");
    return;
  }
  switch(heartBeatIndex++)
  {
    case 0: writeLine("ATE0\n"); break;
    case 1: writeLine("AT+CMEE=1\n"); break;
    case 2: writeLine("AT+CPIN?\n"); break;
    case 3: writeLine("AT+CMGL\n"); break;
    case 4: writeLine("AT+CGMI\n"); break;
    case 5: writeLine("AT+CGMM\n"); break;
    case 6: writeLine("AT+CGMR\n"); break;
    case 7: writeLine("AT+CGSN\n"); break;
    case 8: writeLine("AT+CREG?\n"); break;
    case 9: writeLine("AT+COPS?\n"); break;
    case 10: writeLine("AT+CSQ\n"); break;
    case 11: writeCMGR(1); break;
    case 12: writeCMGR(2); break;
    case 13: writeCMGR(3); break;
    case 14: writeCMGR(4); break;
    case 15: writeCMGR(5); break;
    case 16: writeCMGR(6); break;
    case 17: writeCMGR(7); break;
    case 18: writeCMGR(8); break;
    case 19: writeCMGR(9); break;
    case 20: writeCMGR(10); break;
    case 21: checkForAlarms(); break;
      default:
      heartBeatIndex = 0;
      break;
  }
  if(stopScheduled)
  {
    exit(0);
  }
  if(rebootScheduled)
  {
    system("/sbin/reboot");
  }
}

void processCMGR(char *buffer)
{
  char *comma;
  char *ch;
  
  messageOrigin[0] = '\0';
  comma = strchr(buffer,',');
  if(comma)
  {
    comma++;
    if(*comma == '"')
    {
      comma++;
      ch = messageOrigin;
      while(*comma && *comma != '"')
      {
        *ch++ = *comma++;
      }
      *ch = '\0';
    }
    DEBUG(TRUE,"processCMGR",messageOrigin);
  }
  expectMessageText = TRUE;
}

void processMessage(char *message)
{
  DEBUG(TRUE,"processMessage",message);
  if(match(message,"status"))
  {
    strcpy(alarmRecipient,messageOrigin);
    currentAlarm[0] = '\0';
    checkForAlarms();
  }
  if(match(message,"stop"))
  {
    stopScheduled = TRUE;
  }
  if(match(message,"reboot"))
  {
    rebootScheduled = TRUE;
  }
}

void handleMessageText(char *buffer)
{
  DEBUG(TRUE,"handleMessageText",message);
  if(match(buffer,"OK"))
  {
    if(strlen(message))
    {
      expectMessageText = FALSE;
      processMessage(message);
      messageToDelete = currentMessage;
    }
  }
  else
  {
    strcat(message,buffer);
  }
}

void processPrompt()
{
}

/*
  +CMTI: "SM",1\n
*/
void processCMTI(char *buffer)
{
  char *comma;
  char number[BUFFERSIZE];
  char *ch;
  int messageNumber;
  
  verbose = VERBOSE_MESSAGES;
  comma = strchr(buffer,',');
  if(comma)
  {
    comma++;
    ch = number;
    while(*comma && *comma != '\n')
    {
      *ch++ = *comma++;
    }
    *ch = '\0';
    DEBUG(TRUE,"processCMTI",number);
    sscanf(number,"%d",&messageNumber);
    writeCMGR(messageNumber);
  }
}

// Process an error message
void processCmsError(char *buffer)
{
  int errorNumber;

  sscanf(buffer,"%d",&errorNumber);
  switch(errorNumber)
  {
    case 301: DEBUG(FALSE,"processCmsError","SMS service of ME reserved"); 
break;
    case 302: DEBUG(FALSE,"processCmsError","Operation not allowed"); break;
    case 303: DEBUG(FALSE,"processCmsError","Operation not supported"); break;
    case 305: DEBUG(FALSE,"processCmsError","Invalid text mode parameter"); 
break;
    case 311:
      DEBUG(FALSE,"processCmsError","SIM PIN required");
      writeLine("AT+CPIN=57429\n");
      break;
    case 313: DEBUG(FALSE,"processCmsError","SIM failure"); break;
    case 321: DEBUG(FALSE,"processCmsError","Invalid memory index"); break;
    case 322: DEBUG(FALSE,"processCmsError","SIM memory full"); break;
    case 330: DEBUG(FALSE,"processCmsError","SC address unknown"); break;
    default:
      DEBUG(FALSE,"processCmsError",buffer);
      return;                           
  }
}
        
// Process an error message
void processCmeError(char *buffer)
{
  int errorNumber;

  sscanf(buffer,"%d",&errorNumber);
  switch(errorNumber)
  {
    case 0: DEBUG(FALSE,"processCmeError","Phone failure"); break;
    case 3: DEBUG(FALSE,"processCmeError","Operation not allowed"); break;
    case 4: DEBUG(FALSE,"processCmeError","Operation not supported"); break;
    case 8: DEBUG(FALSE,"processCmeError","Operator determined barring"); break;
    case 10: DEBUG(FALSE,"processCmeError","SIM not inserted"); break;
    case 11: DEBUG(FALSE,"processCmeError","SIM PIN required"); break;
    case 12: DEBUG(FALSE,"processCmeError","SIM PUK required"); break;
    case 13: DEBUG(FALSE,"processCmeError","SIM failure"); break;
    case 16: DEBUG(FALSE,"processCmeError","Incorrect password"); break;
    case 22: DEBUG(FALSE,"processCmeError","Not found"); break;
    case 24: DEBUG(FALSE,"processCmeError","Text string too long"); break;
    case 26: DEBUG(FALSE,"processCmeError","Dial string too long"); break;
    case 30: DEBUG(FALSE,"processCmeError","No network service"); break;
    case 256: DEBUG(FALSE,"processCmeError","protocol stack bad state"); break;
    case 257: DEBUG(FALSE,"processCmeError","Bad cell ( not in the synchronised 
ones)"); break;
    case 258: DEBUG(FALSE,"processCmeError","Lost cell"); break;
    default:
      DEBUG(FALSE,"processCmeError",buffer);
  }
}
        
void deleteMessage(int messageToDelete)
{
  char buffer[BUFFERSIZE];
  
  sprintf(buffer,"AT+CMGD=%d\n",messageToDelete);
  writeLine(buffer);
}

void processInputSegment(char *buffer)
{
  DEBUG(FALSE,"processInputSegment",buffer);
  if(expectMessageText)
  {
    handleMessageText(buffer);
  }
  if(match(buffer,"OK"))
  {
    commOK = TRUE;
    if(messageScheduled)
    {
      sendMessage();
      return;
    }
    if(messageToDelete)
    {
      deleteMessage(messageToDelete);
      messageToDelete = 0;
      return;
    }
  }
  if(match(buffer,"+CME ERROR:"))
  {
    processCmeError(&buffer[12]);
  }
  if(match(buffer,"+CMS ERROR:"))
  {
    processCmsError(&buffer[12]);
  }
  if(match(buffer,"+CSQ:"))
  {
//    processCsq();
  }
  if(match(buffer,"+CREG:"))
  {
//    processCREG();
  }
  if(match(buffer,"\nERROR\n"))
  {
    writeLine("AT+CMEE=1\n");
  }
  if(match(buffer,"+CMTI:"))
  {
    processCMTI(buffer);
  }
  if(match(buffer,"+CMGR"))
  {
    processCMGR(buffer);
  }
  if(match(buffer,">"))
  {
    processPrompt();
  }
  if(match(buffer,"+CPIN: SIM PIN"))
  {
    writeLine("AT+CPIN=57429\n");
  }
}

void processInput(char buffer[])
{
  int indx;
  int msgindx;
  char message[BUFFERSIZE];
  
  DEBUG(FALSE,"processInput",buffer);
  msgindx = 0;
  for(indx = 0; indx < strlen(buffer); indx++)
  {
    if(buffer[indx] == '\n' || buffer[indx] == '\r')
    {
      if(msgindx > 0)
      {
        message[msgindx] = '\0';
        processInputSegment(message);
        msgindx = 0;
      }
    }
    else
    {
      message[msgindx] = buffer[indx];
      msgindx++;
    }
  }
}

/* Look for spooled messages to send */
void sendSpooledMessages()
{
  DIR *directoryStream;

  directoryStream = opendir(SPOOL);
  if(directoryStream != NULL)
  {
    struct dirent *directory;
    
    directory = readdir(directoryStream);
    if(directory != NULL && directory->d_name[0] != '.')
    {
      FILE *file;
      char filename[BUFFERSIZE];
      char address[BUFFERSIZE];
      char message[BUFFERSIZE];
      
      sprintf(filename,"%s/%s",SPOOL,directory->d_name);
      DEBUG(TRUE,"reading spooled message",filename);
      file = fopen(filename,"r");
      fgets(address,BUFFERSIZE,file);
      fgets(message,BUFFERSIZE,file);
      fclose(file);
      remove(filename);
      scheduleMessage(address,message);
    }
  }
}

/* Handle SIGUSR1 */
void handleSIGUSR1(int sig)
{
  DEBUG(TRUE,"handleSIGUSR1","Reloading configuration");
  closeConfiguration();
  readConfigurationFile(configuration);
  activityCount = 0;
  verbose = VERBOSE_MESSAGES;
  sendSpooledMessages();
}

/* Handle SIGUSR1 */
void handleSIGUSR2(int sig)
{
  DEBUG(TRUE,"handleSIGUSR2","Waking up");
  activityCount = 0;
  verbose = VERBOSE_MESSAGES;
}

/* Entry point */
int main(int argc,char *argv[])
{
  struct bufferevent *bufferEvent;
  struct event_base *base;
  char buffer[BUFFERSIZE];
  int bytes;
  
  log_file = stdout;
  signal(SIGUSR1,handleSIGUSR1);
  signal(SIGUSR1,handleSIGUSR1);
  strcpy(configuration,argv[1]);
  readConfigurationFile(configuration);
  writeLine("\n\n\n\n\n\n\n\n\n\nAT\n");
  while(1)
  {
    sleep(1);
    if(activityCount++ % (verbose ? 10 : 100) == 0)
    {
      update();
    }
    do
    {
      bytes = read(file,buffer,BUFFERSIZE-1);
      if(errno != 35 && errno != 0)
      {
        fprintf(log_file,"errno: %d\n",errno);
      }
      if(bytes > 0)
      {
        buffer[bytes] = '\0';
        if(strlen(buffer))
        {
          processInput(buffer);
        }
      }
    }
    while(bytes > 0);
  }
}


Home | Main Index | Thread Index | Old Index