调制解调器控制范例程序

     /* 发出一些简单调制解调器命令
      * 需要串行设备的设备名 (最好是拨出设备,
      * 或者是非调制解调器控制设备) 作为它唯一的参数.
      * 如果你没有可共使用的拨出设备, 那么以CFLAGS_TO_SET取代CLOCAL。
      */
    
     #include <stdio.h>
     #include <stdlib.h>
     #include <fcntl.h>
     #include <unistd.h>
     #include <sys/types.h>
     #include <sys/time.h>
     #include <sys/ioctl.h>   /* 也许需要;和系统有关 */
     #include <termios.h>
     #include <errno.h>
     #include <string.h>
     #include <ctype.h>
    
     #define CFLAGS_TO_SET (CREAD | HUPCL)
     #define CFLAGS_TO_CLEAR (CSTOPB | PARENB | CLOCAL)
    
     enum flowmode { NoFlow, HardFlow, SoftFlow };
    
     /* 和系统有关 */
     #define CFLAGS_HARDFLOW (CRTSCTS)
    
    
     #define EXAMPLE_BAUD B19200
     #define EXAMPLE_FLOW HardFlow
    
    
     static void die(const char *msg)
     {
         fprintf(stderr, "%s\n", msg);
         exit(1);
     }
    
     static int close_and_complain(int fd, const char *msg, int err)
     {
         fprintf(stderr, "%s: %s\n", msg, strerror(err));
         if (fd >= 0)
             close(fd);
         errno = err;
         return -1;
     }
    
    
     int open_port(const char *name, speed_t baud, enum flowmode flow)
     {
         int flags;
         struct termios attr;
    
         int fd = open(name, O_RDWR | O_NONBLOCK | O_NOCTTY);
    
         if (fd < 0)
             return close_and_complain(-1, "open", errno);
    
         /* 设定一些不明确是否敏感的值 */
    
         if (tcgetattr(fd, &attr) < 0)
             return close_and_complain(fd, "tcgetattr", errno);
    
         /* 无特殊输入或输出处理 */
    
         attr.c_iflag = (flow == SoftFlow) ? (IXON | IXOFF) : 0;
         attr.c_oflag = 0;
    
         /* 设定8位字符宽和一些杂项控制模式 */
    
         attr.c_cflag &= ~(CSIZE | CFLAGS_TO_CLEAR | CFLAGS_HARDFLOW);
         attr.c_cflag |= (CS8 | CFLAGS_TO_SET);
         if (flow == HardFlow)
             attr.c_cflag |= CFLAGS_HARDFLOW;
    
         /* 本机模式 */
    
         attr.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ISIG);
    
         /* 特殊字符 -- 许多已被先前的设定取消 */
    
         {
             int i;
     #ifdef _POSIX_VDISABLE
             attr.c_cc[0] = _POSIX_VDISABLE;
     #else
             attr.c_cc[0] = fpathconf(fd, _PC_VDISABLE);
     #endif
             for (i = 1; i < NCCS; i++)
                 attr.c_cc[i] = attr.c_cc[0];
         }
    
         attr.c_cc[VSTART] = 0x11;
         attr.c_cc[VSTOP] = 0x13;
    
         /* 对read()函数的计时控制 */
    
         attr.c_cc[VMIN] = 1;
         attr.c_cc[VTIME] = 0;
    
         /* 波特律 */
    
         cfsetispeed(&attr, baud);
         cfsetospeed(&attr, baud);
    
         /* 写入设定 */
    
         if (tcsetattr(fd, TCSANOW, &attr) < 0)
             return close_and_complain(fd, "tcsetattr", errno);
    
         /* 如果系统记住了先前的O_NONBLOCK设定,就取消它 */
    
         flags = fcntl(fd, F_GETFL, 0);
         if (flags < 0)
             return close_and_complain(fd, "fcntl(GETFL)", errno);
         if (fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) < 0)
             return close_and_complain(fd, "fcntl(SETFL)", errno);
    
         return fd;
     }
    
     /* 一些简单的计时工具函数 */
    
     /* 向*TV加 SECS 和USECS */
    
     static void timeradd(struct timeval *tv, long secs, long usecs)
     {
         tv->tv_sec += secs;
         if ((tv->tv_usec += usecs) >= 1000000)
         {
             tv->tv_sec += tv->tv_usec / 1000000;
             tv->tv_usec %= 1000000;
         }
     }
    
     /* 设定 *RES = *A - *B, 返回结果的符号 */
    
     static int timersub(struct timeval *res,
                         const struct timeval *a, const struct timeval *b)
     {
         long sec = a->tv_sec - b->tv_sec;
         long usec = a->tv_usec - b->tv_usec;
    
         if (usec < 0)
             usec += 1000000, --sec;
    
         res->tv_sec = sec;
         res->tv_usec = usec;
    
         return (sec < 0) ? (-1) : ((sec == 0 && usec == 0) ? 0 : 1);
     }
    
    
     /* 这个函数不试图处理非正常的字符串 (比如 ababc)
      * 超时以微妙计
      * 一个更通常的做法是使用alarm()函数处理超时.
      * 这个函数为简便起见不使用信号处理并试图提供一种替换方法
      */
    
     int expect(int fd, const char *str, int timeo)
     {
         int matchlen = 0;
         int len = strlen(str);
         struct timeval now,end,left;
         fd_set fds;
         char c;
    
         gettimeofday(&end, NULL);
         timeradd(&end, timeo/1000, timeo%1000);
    
         while (matchlen < len)
         {
             gettimeofday(&now, NULL);
             if (timersub(&left, &end, &now) <= 0)
                 return -1;
    
             FD_ZERO(&fds);
             FD_SET(fd, &fds);
             if (select(fd+1, &fds, NULL, NULL, &left) <= 0)
                 return -1;
    
             if (read(fd, &c, 1) != 1)
                 return -1;
    
             if (isprint((unsigned char)c) || c == '\n' || c == '\r')
                 putchar(c);
             else
                 printf("\\x%02x", c);
    
             if (c == str[matchlen])
                 ++matchlen;
             else
                 matchlen = 0;
         }
    
         return 0;
     }
    
    
     int main(int argc, char **argv)
     {
         int fd;
         unsigned char c;
    
         if (argc < 2)
             die("no port specified");
    
         setvbuf(stdout, NULL, _IONBF, 0);
    
         fd = open_port(argv[1], EXAMPLE_BAUD, EXAMPLE_FLOW);
         if (fd < 0)
             die("cannot open port");
    
         write(fd, "AT\r", 3);
         if (expect(fd, "OK", 5000) < 0)
         {
             write(fd, "AT\r", 3);
             if (expect(fd, "OK", 5000) < 0)
             {
                 tcflush(fd, TCIOFLUSH);
                 close(fd);
                 die("no response to AT");
             }
         }
    
         write(fd, "ATI4\r", 5);
         expect(fd, "OK", 10000);
    
         putchar('\n');
    
         tcflush(fd, TCIOFLUSH);
         close(fd);
    
         return 0;
     }