diff options
Diffstat (limited to 'src/modem.c')
-rw-r--r-- | src/modem.c | 203 |
1 files changed, 186 insertions, 17 deletions
diff --git a/src/modem.c b/src/modem.c index 0d47e4d..ef1d7fd 100644 --- a/src/modem.c +++ b/src/modem.c @@ -53,10 +53,14 @@ struct modem *modem_open(const char *dev) { memset(m, 0, sizeof(struct modem)); m->dev = strdup(dev); assert(m->dev); - m->fd = fd; + m->buffio = buffio_new(fd); + assert(m->buffio); m->state = MODEM_STATE_INIT; m->child_pid = -1; + modem_timeout(m, 10); + modem_next_command(m); + return m; fail: @@ -74,27 +78,13 @@ void modem_close(struct modem *m) { if (m->child_pid != -1) child_process_kill(m->child_pid); - - close(m->fd); + + buffio_free(m->buffio); 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); @@ -162,3 +152,182 @@ static void* oop_audio_shbuf_cb(oop_source *source, int fd, oop_event event, voi return OOP_CONTINUE; } + +#define INIT_AT_COMMANDS 12 + +static const char* const init_at_commands[INIT_AT_COMMANDS*2] = { + "\nAT&F\n", + "OK\r\n", + + "ATI\n", + "Linux ISDN\r\nOK\r\n", + + "AT&B16\n", + "OK\r\n", + + "AT+FCLASS=8\n", + "OK\r\n", + + "AT+VSM=6\n", + "OK\r\n", + + "ATS18=1\n", + "OK\r\n", + + "ATS14=4\n", + "OK\r\n", + + "ATS13.4=0\n", + "OK\r\n", + + "ATS13.0=1\n", + "OK\r\n", + + "ATS23=1\n", + "OK\r\n", + + "AT&E%s\n", + "OK\r\n", + + "ATS0=0\n", + "OK\r\n" +}; + + + +static void modem_input_init_cb(struct buffio *b, void *user) { + struct modem *m = user; + assert(b && m && m->buffio == b); + + + switch (m->state) { + + case MODEM_STATE_INIT: { + char *p; + assert(m->command_index < INIT_AT_COMMANDS); + + p = init_at_commands[m->command_index*2+1]; + + if (buffio_find_input(m->buffio, p)) { + m->command_index++; + + if (m->command_index >= INIT_AT_COMMANDS) { + m->state = MODEM_STATE_CALLER_NUMBER_EXPECT; + modem_input_init_cb(b, user); + } else + modem_next_command(m); + } + + break; + } + + case MODEM_STATE_CALLER_NUMBER_EXPECT: + + if (buffio_find_input(m->buffio, "CALLER NUMBER: ")) { + m->state = MODEM_STATE_CALLER_NUMBER; + modem_input_init_cb(b, user); + } + + break; + + case MODEM_STATE_CALLER_NUMBER: { + + char c[64]; + + if (buffio_read_line(m->buffio, c, sizeof(c))) { + free(m->caller_number); + m->caller_number = strdup(c); + assert(m->caller_number); + + m->state = MODEM_STATE_RING_EXPECT; + modem_input_init_cb(b, user); + } + break; + + } + + case MODEM_STATE_RING_EXPECT: + + if (buffio_find_input(m->buffio, "RING/")) { + m->state = MODEM_STATE_RING; + modem_input_init_cb(b, user); + } + break; + + case MODEM_STATE_RING: { + + char c[64]; + + if (buffio_read_line(m->buffio, c, sizeof(c))) { + free(m->ring_number); + m->ring_number = strdup(c); + assert(m->ring_number); + + if (msntab_check_call(m->ring_number, m->caller_number)) { + modem_send_command(m, "ATA\n"); + m->state = MODEM_STATE_ANSWER; + } else { + m->state = MODEM_STATE_CALLER_NUMBER_EXPECT; + modem_input_init_cb(b, user); + } + } + + break; + } + + case MODEM_STATE_ANSWER: + + if (buffio_find_input(m->buffio, "VCON\r\n")) { + + buffio_command(m->buffio, "AT+VTX+VRX"); + m->state = MODEM_STATE_VTXVRX; + } + break; + + case MODEM_STATE_VTXVRX: + + if (buffio_find_input(m->buffio, "CONNECT\r\n\r\nCONNECT\r\n")) { + m->state = MODEM_STATE_CONNECTION; + modem_input_init_cb(b, user); + } + + break; + + case MODEM_STATE_CONNECTION: + break; + + case MODEM_STATE_DONE: + break; + + } + +} + +static void modem_send_command(struct modem *m, const char *p) { + assert(m && m->buffio); + + buffio_input_flush(m->buffio); + m->buffio->input_cb = modem_input_cb; + buffio_print(m->buffio, p); +} + +static void modem_next_command(struct modem *m) { + char *p; + char tmp[64]; + assert(m && m->buffio && (m->state == MODEM_STATE_INIT || m->state == MODEM_STATE_DONE)); + assert(m->command_index < INIT_AT_COMMANDS) + + p = init_at_commands[m->command_index*2]; + + if (m->command_index == 10) { + snprintf(tmp, sizeof(tmp), p, m->local_msn); + p = tmp; + } + + buffio_input_flush(m->buffio); + + m->buffio->input_cb = modem_input_cb; + buffio_command(m->buffio, p); +} + +// { DLE, DC4, DLE, ETX, 'A', 'T', 'H', '\n', "AT&F\n" }, |