From c79399f437e9268203768ab65b32c20f29093b27 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 17 Dec 2003 22:11:57 +0000 Subject: much further work git-svn-id: file:///home/lennart/svn/public/ivam2/trunk@7 dbf6933d-3bce-0310-9bcc-ed052ba35b35 --- src/buffio.c | 202 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/buffio.h | 31 +++++++++ src/dle.c | 47 ++++++++++++++ src/dle.h | 7 +++ src/modem.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----- src/modem.h | 25 +++++--- 6 files changed, 491 insertions(+), 24 deletions(-) create mode 100644 src/buffio.c create mode 100644 src/buffio.h create mode 100644 src/dle.c create mode 100644 src/dle.h diff --git a/src/buffio.c b/src/buffio.c new file mode 100644 index 0000000..1e13b4d --- /dev/null +++ b/src/buffio.c @@ -0,0 +1,202 @@ +#include "buffio.h" + +#define BUFSIZE 10240 + +static void buffio_set_callbacks(struct buffio *b); +static void* buffio_read_cb(oop_source *source, int fd, oop_event event, void *user); +static void* buffio_write_cb(oop_source *source, int fd, oop_event event, void *user); + +struct buffio buffio_new(int fd) { + struct buffio *b; + assert(b >= 0); + + b = malloc(sizeof(struct buffio)); + assert(b); + memset(b, 0, sizeof(struct buffio)); + + b->fd = fd; + b->input_buf = malloc(BUFSIZE); + assert(b->input_buf); + b->input_buf_len = 0; + + b->output_buf = malloc(BUFSIZE); + assert(b->output_buf); + b->output_buf_len = 0; + + buffio_set_callbacks(b); + + return b; +} + +static void buffio_close_fd(struct buffio *b) { + assert(b); + + if (b->b_read_cb) + event_source->cancel_fd(event_source, b->fd, OOP_READ, buffio_read_cb, b); + + if (b->b_write_cb) + event_source->cancel_fd(event_source, b->fd, OOP_WRITE, buffio_write_cb, b); + + if (b->fd >= 0) + close(b->fd); + + b->b_read_cb = b->b_write_cb = 0; + b->fd = -1; +} + + +void buffio_free(struct buffio *b) { + buffio_close_fd(b); + free(b->output_buf); + free(b->input_buf); + free(b); +} + +static void* buffio_read_cb(oop_source *source, int fd, oop_event event, void *user) { + struct buffio *b = user; + assert(source && b && b->fd == fd && event == OOP_READ); + + if (b->input_length < BUFSIZE) { + ssize_t s; + size_t m, l; + + i = (b->input_index + b->input_length) % BUFSIZE; + + m = BUFSIZE-b->input_length; + if (m > BUFSIZE-i) + m = BUFSIZE-i; + + if ((s = read(fd, b->input_buf+i, m)) < 0) { + daemon_log(LOG_ERR, "Failed to read from file descriptor: %s", strerror(errno)); + return OOP_HALT; + } + + if (!s) { + buffio_close_fd(b); + if (b->eof_cb) + b->eof_cb(b, b->user); + return OOP_CONTINUE; + } + + assert(s <= m); + b->input_length += s; + } + + buffio_set_callbacks(b); + return OOP_CONTINUE; +} + +static void* buffio_write_cb(oop_source *source, int fd, oop_event event, void *user) { + struct buffio *b = user; + assert(source && b && b->fd == fd && event == OOP_WRITE); + + if (b->output_buf > 0) { + ssize_t s; + size_t m; + + m = b->output_length; + if (m > BUFSIZE-b->output_index) + m = BUFSIZE-b->output_index; + + if ((s = write(fd, b->output_buf+b->output_index, m)) < 0) { + daemon_log(LOG_ERR, "Failed to write to file descriptor: %s", strerror(errno)); + return OOP_HALT; + } + + if (!s) { + buffio_close_fd(b); + if (b->eof_cb) + b->eof_cb(b, b->user); + return OOP_CONTINUE; + } + + assert(s <= m); + b->output_index = (b->output_index + s) % BUFSIZE; + b->ouput_length -= s; + } + + buffio_set_callbacks(b); + return OOP_CONTINUE; + +} + +static void buffio_set_callbacks(struct buffio *b) { + assert(b && b->fd >= 0 && event_source); + + if (b->input_length < BUFSIZE) { + if (!b->b_read_cb) { /* Enable the callback */ + event_source->on_fd(event_source, b->fd, OOP_READ, buffio_read_cb, b); + b->b_read_cb = 1; + } + } else { + if (b->read_cb) { /* Disable the callback */ + event_source->cancel_fd(event_source, b->fd, OOP_READ, buffio_read_cb, b); + b->read_cb = 0; + } + } + + if (b->output_length > 0) { + if (!b->b_write_cb) { /* Enable the callback */ + event_source->on_fd(event_source, b->fd, OOP_WRITE, buffio_write_cb, b); + b->b_write_cb = 1; + } + } else { + if (b->b_write_cb) { /* Disable the callback */ + event_source->cancel_fd(event_source, b->fd, OOP_WRITE, buffio_write_cb, b); + b->b_write_cb = 0; + } + } + +} + +int buffio_write(struct buffio *b, const uint8_t *d, size_t l) { + assert(b && s && l); + + if (l < BUFFSIZE - b->output_length) { + daemon_log(LOG_ERR, "buffio_write() with too much data called"); + return -1; + } + + + while (l >= 0) { + i = (b->ouput_index + b->ouput_length) % BUFSIZE; + + m = BUFSIZE-b->output_length; + if (m > BUFSIZE-i) + m = BUFSIZE-i; + + memcpy(b->output_buf+i, d, m); + + l -= m; + b->output_length += m; + } + + buffio_set_callbacks(b); + + return 0; +} + +int buffio_print(struct buffio *b, const char *s) { + assert(b && s); + return buffio_write(b, (uint8_t*) s, strlen(s)); +} + +int buffio_command(struct buffio *b, const char *c) { + assert(b && c); + + buffio_flush_input(b); + return buffio_print(b, c); +} + +void buffio_flush_input(struct buffio *b) { + assert(b); + + b->input_length = b->input_index = 0; + buffio_set_callbacks(b); +} + +int buffio_find_input(struct buffio *b, const char *c) { + assert(b && c); + + +} diff --git a/src/buffio.h b/src/buffio.h new file mode 100644 index 0000000..461bff9 --- /dev/null +++ b/src/buffio.h @@ -0,0 +1,31 @@ +#ifndef foobuffiohfoo +#define foobuffiohfoo + +struct buffio { + int fd; + + uint8_t *input_buf; + size_t input_index, input_length; + + uint8_t *output_buf; + size_t output_index, output_length; + + int b_read_cb, b_write_cb; + + void *user; + void (*eof_cb) (struct buffio *b, void *user); + void (*output_cb) (struct buffio *b, void *user); + void (*input_cb) (struct buffio *b, void *user); +}; + +struct buffio buffio_new(int fd); +void buffio_free(struct buffio *b); + +int buffio_write(struct buffio *b, const uint8_t *d, size_t l); +int buffio_print(struct buffio *b, const char *s); + +int buffio_command(struct buffio *b, const char *c); +void buffio_flush_input(struct buffio *b); +int buffio_find_input(struct buffio *b, const char *c); + +#endif diff --git a/src/dle.c b/src/dle.c new file mode 100644 index 0000000..51b3c75 --- /dev/null +++ b/src/dle.c @@ -0,0 +1,47 @@ +#include "dle.h" + +/* Those nifty DLE-sequences */ +#define DLE 0x10 +#define ETX 0x03 +#define DC4 0x14 + +size_t dle_decode(uint8_t* s, size_t ls, uint8_t* d, size_t *ld, void (*dle_func) (uint8_t c, void *user), void *user, int *dle_flag) { + size_t ns, nd; + assert(s && ls && d && ld && *ld && dle_flag); + + for (ns = nd = 0; ns < ls && nd < *ld; ns++) { + + if (*dle_flag) { + if (s[ns] == DLE) + d[nd++] = DLE; + else { + if (dle_func) + dle_func(s[ns], user); + } + + *dle_flag = 0; + } else { + if (s[ns] == DLE) + *dle_flag = 1; + else + d[nd++] = s[ns]; + } + } + + *ld = nd; + return ns; +} + +size_t dle_encode(uint8_t* s, size_t ls, uint8_t* d, size_t *ld) { + size_t ns, nd; + + for (ns = nd = 0; ns < ls && nd < *ld; ns++) { + if (s[ns] == DLE) + d[nd++] = DLE; + + d[nd++] = s[ns]; + } + + *ld = nd; + return ns; +} diff --git a/src/dle.h b/src/dle.h new file mode 100644 index 0000000..2e0e453 --- /dev/null +++ b/src/dle.h @@ -0,0 +1,7 @@ +#ifndef foodlehfoo +#define foodlehfoo + +size_t dle_decode(uint8_t* s, size_t ls, uint8_t* d, size_t *ld, void (*dle_func) (uint8_t c, void *user), void *user, int *dle_flag); +size_t dle_encode(uint8_t* s, size_t ls, uint8_t* d, size_t *ld); + +#endif 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" }, diff --git a/src/modem.h b/src/modem.h index 7383d1c..308d656 100644 --- a/src/modem.h +++ b/src/modem.h @@ -1,25 +1,36 @@ #ifndef foomodemhfoo #define foomodemhfoo -enum modem_state { MODEM_STATE_INIT, MODEM_STATE_AUDIO_SIMPLE, MODEM_STATE_AUDIO_SHBUF, MODEM_STATE_DONE }; +#include "buffio.h" + +enum modem_state { + MODEM_STATE_INIT, + MODEM_STATE_CALLER_NUMBER_EXPECT, + MODEM_STATE_CALLER_NUMBER, + MODEM_STATE_RING_EXPECT, + MODEM_STATE_RING, + MODEM_STATE_ANSWER, + MODEM_STATE_VTXVRX, + MODEM_STATE_CONNECTION, + MODEM_STATE_CONNECTION_SHBUF, + MODEM_STATE_DONE +}; #define MODEM_BUF_LEN (10*1024) struct modem { char *dev; - int fd; - char *ouput_buf; - size_t output_buf_len; - - char *input_buf; - size_t input_buf_len; + struct buffio *buffio; enum modem_state state; + int command_index; pid_t child_pid; struct timeval timeout; + + int dle_flag; }; struct modem *modem_open(const char *dev); -- cgit