| | /* issue some simple modem commands
* requires the name of a serial device (preferably a dial-out device,
* or a non-modem-control device) as its only parameter.
* If you don't have functional dial-out devices, then move CLOCAL
* to CFLAGS_TO_SET instead.
*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h> /* maybe; system-dependent */
#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 };
/* system-dependent */
#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);
/* set vaguely sensibe settings */
if (tcgetattr(fd, &attr) < 0)
return close_and_complain(fd, "tcgetattr", errno);
/* no special input or output processing */
attr.c_iflag = (flow == SoftFlow) ? (IXON | IXOFF) : 0;
attr.c_oflag = 0;
/* set 8-bit character size and miscellanous control modes */
attr.c_cflag &= ~(CSIZE | CFLAGS_TO_CLEAR | CFLAGS_HARDFLOW);
attr.c_cflag |= (CS8 | CFLAGS_TO_SET);
if (flow == HardFlow)
attr.c_cflag |= CFLAGS_HARDFLOW;
/* local modes */
attr.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ISIG);
/* special characters -- most disabled by prior settings anyway */
{
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;
/* timing controls for read() */
attr.c_cc[VMIN] = 1;
attr.c_cc[VTIME] = 0;
/* baud rate */
cfsetispeed(&attr, baud);
cfsetospeed(&attr, baud);
/* write settings */
if (tcsetattr(fd, TCSANOW, &attr) < 0)
return close_and_complain(fd, "tcsetattr", errno);
/* turn off O_NONBLOCK if the device remembered it */
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;
}
/* some simple timing utilities */
/* add SECS and USECS to *TV */
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;
}
}
/* Set *RES = *A - *B, returning the sign of the result */
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);
}
/* this doesn't try and cope with pathological strings (e.g. ababc)
* timeout is in millisecs
* A more usual approach to this is to use alarm() for the timeout.
* This example avoids signal handling for simplicity and to illustrate
* an alternative approach
*/
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;
}
|