MainXMLTagsEditHistoryDiscussion

This program is a small example useful to query a modem. It might be a starting point for serial programming.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/times.h>
#include <sys/ioctl.h>
#include <sys/unistd.h>
#include <getopt.h>
#include <termios.h>

/*  This code started as a streamlined version of
 *  a C++ file that is part of a project which is
 *  is Copyright (c) 2005 Dave Hylands.
 *  http://www.davehylands.com/Software/BootHost/
 *
 *  We might need to restore more options later
 *  to allow 96008N1 and so on.
 */

#define SERIAL_BAD_BAUDRATE -1000
#define SERIAL_BAD_PORT -1001
#define SERIAL_GEN_ERROR -1002

static struct {
    speed_t speed;
    unsigned baudRate;
} BaudTable[] = {
    {
    B50, 50}, {
    B75, 75}, {
    B110, 110}, {
    B134, 134}, {
    B150, 150}, {
    B200, 200}, {
    B300, 300}, {
    B600, 600}, {
    B1200, 1200}, {
    B1800, 1800}, {
    B2400, 2400}, {
    B4800, 4800}, {
    B9600, 9600}, {
    B19200, 19200}, {
    B38400, 38400}, {
    B57600, 57600}, {
    B115200, 115200}, {
    B230400, 230400}
};

#define ARRAY_LEN(x)    ( sizeof( x ) / sizeof( x[ 0 ]))

int serial_open(char *portStr, int try_baud_rate, int verbose)
{
    speed_t baudRate = B0;
    int gPortFd = -1;
    int i;

    struct termios attr;

    for (i = 0; i < ARRAY_LEN(BaudTable); i++) {
       if (BaudTable[i].baudRate == try_baud_rate) {
            baudRate = BaudTable[i].speed;
            break;
        }
    }

    if (baudRate == B0) {
        if (verbose)
          fprintf(stderr, "Unrecognized baud rate: '%d'\n", try_baud_rate);
        return SERIAL_BAD_BAUDRATE;
    }

    if ((gPortFd = open(portStr, O_RDWR | O_EXCL)) < 0) {
        if (verbose)
          fprintf(stderr, "Unable to open serial port '%s': %s\n", portStr,
                strerror(errno));
        return SERIAL_BAD_PORT;
    }

    if (tcgetattr(gPortFd, &attr) < 0) {
        if (verbose)
          fprintf(stderr, "Call to tcgetattr failed: %s\n", strerror(errno));
        return SERIAL_GEN_ERROR;
    }

    attr.c_iflag = 0;
    attr.c_oflag = 0;
    attr.c_cflag = CLOCAL | CREAD | CS8;
    attr.c_lflag = 0;
    attr.c_cc[VTIME] = 0;       /* timeout in tenths of a second */
    attr.c_cc[VMIN] = 1;        /* Only wait for a single char */

    cfsetispeed(&attr, baudRate);
    cfsetospeed(&attr, baudRate);

    if (tcsetattr(gPortFd, TCSAFLUSH, &attr) < 0) {
        if (verbose)
          fprintf(stderr, "Call to tcsetattr failed: %s\n", strerror(errno));
        return SERIAL_GEN_ERROR;
    }

    return gPortFd;
}

/*
 * Tne next two function were written by Nelson Castillo.
 * You should not blame Dave for what he wrote here :-)
 */

int
serial_read (int fd, char *buf, int len, int ms_timeout)
{
  fd_set rfds;
  struct timeval tv;
  int retval;
  int nread = 0;

  FD_ZERO(&rfds);
  FD_SET(fd, &rfds);

  tv.tv_sec = ms_timeout / 1000;
  tv.tv_usec = (ms_timeout % 1000) * 1000;

select_next:

  /* We rely on the value of tv after the select call.
   * This is a Linux-only thing.
   * TODO: Fix. */

  errno = 0;
  retval = select(fd + 1, &rfds, NULL, NULL, &tv);

  if (retval == -1)
  {
    if (errno == EINTR)
      goto select_next;

    perror("select");
    exit(1);
  }
  else if (retval)
  {
    if (len - nread > 0)
    {
      int r;
      r = read(fd, buf + nread, len - nread);
      if (r > 0)
      {
        nread += r;

        if (len - nread >  0)
          goto select_next;
      }
      else
      {
        fprintf(stderr, __FILE__" * read returned %d\n\n", r);
        perror("read");
      }
    }
  }

  return nread;
}

int
main(int argc, char **argv)
{
 int r;
 int len;
 char buf[256];

 r = serial_open("/dev/modem", 57600, 1);
 if (r < 0)
   return 1;

 if (4 != write(r, "ATZ\r", 4)) {
   perror("write");
   return 1;
 }

 len = serial_read (r, buf, 255, 500 /* milliseconds */);
 printf("We got:");
 fwrite(buf, 1, len, stdout);

 return 0;
}

Last update: 2008-12-02 (Rev 497)

svnwiki $Rev: 14844 $