#include "modem.h" #include "lock.h" /* Baudrate for the TTY. Should be greater the 64000. */ #define BAUD_RATE B115200 struct modem *modem_open(const char *dev) { struct modem *m; int fd = -1, n; struct termios ts, ts2; assert(dev); if (device_lock(dev) != 0) return -1; if ((fd = open(dev, O_RDWR|O_NDELAY)) < 0) { daemon_log(LOG_ERR, "Failed to open device <%s>: %s", dev, strerror(errno)); goto fail; } if ((n = fcntl(fd, F_GETFL, 0)) < 0 || fcntl(fd, F_SETFL, n & ~O_NDELAY) < 0) { daemon_log(LOG_ERR, "Failed to remove O_NDELAY flag from device: %s", strerror(errno)); goto fail; } memset(&ts, 0, sizeof ts); ts.c_cflag = CRTSCTS | IGNPAR | HUPCL | CS8; ts.c_iflag = IGNPAR; ts.c_oflag = 0; ts.c_lflag = 0; ts.c_cc[VMIN] = 1; ts.c_cc[VTIME] = 0; cfsetospeed(&ts, BAUD_RATE); cfsetispeed(&ts, BAUD_RATE); tcflush(fd, TCIFLUSH); if (tcsetattr(fd, TCSANOW, &ts) < 0) { daemon_log(LOG_ERR, "Failed to set TTY attributes: %s", strerror(errno)); goto fail; } if (tcgetattr(fd, &ts2) < 0 || memcmp(&ts, &ts2) != 0) { daemon_log(LOG_ERR, "Failed to set TTY attributes"); goto fail; } m = malloc(sizeof(struct modem)); assert(m); memset(m, 0, sizeof(struct modem)); m->dev = strdup(dev); assert(m->dev); m->fd = fd; m->state = MODEM_STATE_INIT; m->child_pid = -1; return m; fail: if (fd >= 0) close(fd); device_unlock(dev); return NULL; } void modem_close(struct modem *m) { assert(m); if (m->child_pid != -1) child_process_kill(m->child_pid); close(m->fd); device_unlock(m->dev); free(m->dev); free(m); } static int modem_read(struct modem *m) { char *p; ssize_t s; assert(m && m->input_buf); p = m->input_buf+m->input_buf_len; if ((s = read(m->fd, &p, MODEM_BUF_LEN-m->input_buf_len)) <= 0) { daemon_log(LOG_ERR, "Failed to read() from modem: %s", !s ? "EOF" : strerror(errno)); return -1; } m->input_buf_len += s; } static void* oop_timeout_cb(oop_source *source,struct timeval tv,void *user) { struct modem *m = (struct modem*) user; assert(source && user); daemon_log(LOG_ERR, "Timeout reached for device <%s>", m->device); return OOP_HALT; } static void modem_timeout(struct modem *m, int t) { struct timeval tv = { t, 0 }; assert(m); assert(event_source && event_source->on_time); event_source->cancel_time(event_source, m->timeout, oop_timeout_cb, m); if (t > 0) { gettimeofday(&m->timeout); m->tv_sec += t; assert(event_source && event_source->on_time); event_source->on_time(event_source, m->timeout, oop_timeout_cb, m); } } static void* oop_init_cb(oop_source *source, int fd, oop_event event, void *user) { struct modem *m = (struct modem*) user; assert(source && user); assert(m && m->fd == fd && m->mode == MODEM_STATE_INIT); if (event == OOP_READ) { if (modem_read(m) < 0) return OOP_HALT; } else if (event == OOP_WRITE) { modem_write(m); } return OOP_CONTINUE; } static void* oop_audio_simple_cb(oop_source *source, int fd, oop_event event, void *user) { struct modem *m = (struct modem*) user; assert(source && user); assert(m && m->mode == MODEM_STATE_AUDIO_SIMPLE); if (event == OOP_READ) { modem_read(m); } else if (event == OOP_WRITE) { modem_write(m); } return OOP_CONTINUE; } static void* oop_audio_shbuf_cb(oop_source *source, int fd, oop_event event, void *user) { struct modem *m = (struct modem*) user; assert(source && user); assert(m && m->mode == MODEM_STATE_AUDIO_SHBUF); if (event == OOP_READ) { modem_read(m); } else if (event == OOP_WRITE) { modem_write(m); } return OOP_CONTINUE; }