From 51c0330ea15a28d2d7c83a746458dfd5cf1770bc Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 18 Dec 2003 22:22:24 +0000 Subject: further work git-svn-id: file:///home/lennart/svn/public/ivam2/trunk@8 dbf6933d-3bce-0310-9bcc-ed052ba35b35 --- src/buffio.c | 100 +++++++++++++++++++++++++++++++++++++++++++---------------- src/buffio.h | 9 +++--- src/modem.c | 59 ++++++++++++++++++++++++++++++----- 3 files changed, 130 insertions(+), 38 deletions(-) diff --git a/src/buffio.c b/src/buffio.c index 1e13b4d..2c3a7fb 100644 --- a/src/buffio.c +++ b/src/buffio.c @@ -15,13 +15,16 @@ struct buffio buffio_new(int fd) { memset(b, 0, sizeof(struct buffio)); b->fd = fd; - b->input_buf = malloc(BUFSIZE); + + b->input_buf = malloc(b->input_max_length = BUFSIZE); assert(b->input_buf); - b->input_buf_len = 0; - - b->output_buf = malloc(BUFSIZE); + b->input_buf_len = b->input_index = 0; + b->input_watermark = 2; /* Read some more data if 2 or less bytes are in the input buffer */ + + b->output_buf = malloc(b->output_max_length = BUFSIZE); assert(b->output_buf); - b->output_buf_len = 0; + b->output_length = b->output_index = 0; + b->output_watermark = 1; /* Write some data if 1 or more bytes are in the output buffer */ buffio_set_callbacks(b); @@ -56,15 +59,15 @@ static void* buffio_read_cb(oop_source *source, int fd, oop_event event, void *u struct buffio *b = user; assert(source && b && b->fd == fd && event == OOP_READ); - if (b->input_length < BUFSIZE) { + if (b->input_length < b->input_max_length) { ssize_t s; size_t m, l; - i = (b->input_index + b->input_length) % BUFSIZE; + i = (b->input_index + b->input_length) % b->input_max_length; - m = BUFSIZE-b->input_length; - if (m > BUFSIZE-i) - m = BUFSIZE-i; + m = b->input_max_length-b->input_length; + if (m > b->input_max_length-i) + m = b->input_max_length-i; if ((s = read(fd, b->input_buf+i, m)) < 0) { daemon_log(LOG_ERR, "Failed to read from file descriptor: %s", strerror(errno)); @@ -82,7 +85,12 @@ static void* buffio_read_cb(oop_source *source, int fd, oop_event event, void *u b->input_length += s; } - buffio_set_callbacks(b); + buffio_normalize(b); + buffio_set_input_callbacks(b); + + if (b->input_length && b->input_ready_cb) + b->input_ready_cb(b, b->user); + return OOP_CONTINUE; } @@ -95,8 +103,8 @@ static void* buffio_write_cb(oop_source *source, int fd, oop_event event, void * size_t m; m = b->output_length; - if (m > BUFSIZE-b->output_index) - m = BUFSIZE-b->output_index; + if (m > b->output_max_length-b->output_index) + m = b->output_max_length-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)); @@ -111,19 +119,24 @@ static void* buffio_write_cb(oop_source *source, int fd, oop_event event, void * } assert(s <= m); - b->output_index = (b->output_index + s) % BUFSIZE; + b->output_index = (b->output_index + s) % b->output_max_length; b->ouput_length -= s; } + + buffio_normalize(b); + buffio_set_output_callbacks(b); + + if (!b->output_length && b->output_empty_cb) + b->output_empty_cb(b, b->user); - buffio_set_callbacks(b); return OOP_CONTINUE; } -static void buffio_set_callbacks(struct buffio *b) { +static void buffio_set_input_callbacks(struct buffio *b) { assert(b && b->fd >= 0 && event_source); - if (b->input_length < BUFSIZE) { + if (b->input_length <= b->input_watermark) { 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; @@ -134,8 +147,12 @@ static void buffio_set_callbacks(struct buffio *b) { b->read_cb = 0; } } +} - if (b->output_length > 0) { +static void buffio_set_output_callbacks(struct buffio *b) { + assert(b && b->fd >= 0 && event_source); + + if (b->output_length >= b->output_watermark) { 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; @@ -146,24 +163,23 @@ static void buffio_set_callbacks(struct buffio *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) { + if (l < b->output_max_length - 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; + i = (b->ouput_index + b->ouput_length) % b->ouput_max_length; - m = BUFSIZE-b->output_length; - if (m > BUFSIZE-i) - m = BUFSIZE-i; + m = b->ouput_max_length-b->output_length; + if (m > b->output_max_length-i) + m = b->output_max_length-i; memcpy(b->output_buf+i, d, m); @@ -171,7 +187,8 @@ int buffio_write(struct buffio *b, const uint8_t *d, size_t l) { b->output_length += m; } - buffio_set_callbacks(b); + buffio_set_output_callbacks(b); + buffio_normalize(); return 0; } @@ -195,8 +212,39 @@ void buffio_flush_input(struct buffio *b) { buffio_set_callbacks(b); } + +static void buffio_normalize(struct buffio *b) { + assert(b); + + assert(b->input_index < b->input_max_length); + assert(b->input_length <= b->input_max_length); + + if (!b->input_length) /* This will optimize throughput a bit */ + b->input_index = 0; +} + int buffio_find_input(struct buffio *b, const char *c) { - assert(b && c); + size_t l, cl, j; + assert(b && c && *c); + cl = strlen(c); + + for (i = b->input_index, l = b->input_length; l >= cl; i = (i+1) % b->input_max_length, l--) { + char *p; + size_t i; + + for (j = i, p = c; *p && *p == b->input_buf[j]; p++, j = (j+1) % b->input_max_length); + + if (!*p) { /* Found! */ + b->input_index = j; + b->input_length = l-cl; + + buffio_normalize(b); + return 1; + } + } + + return 0; } + diff --git a/src/buffio.h b/src/buffio.h index 461bff9..a340385 100644 --- a/src/buffio.h +++ b/src/buffio.h @@ -5,17 +5,18 @@ struct buffio { int fd; uint8_t *input_buf; - size_t input_index, input_length; + size_t input_max_length, input_index, input_length; uint8_t *output_buf; - size_t output_index, output_length; + size_t output_max_length, 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); + void (*output_empty_cb) (struct buffio *b, void *user); + void (*input_ready_cb) (struct buffio *b, void *user); }; struct buffio buffio_new(int fd); diff --git a/src/modem.c b/src/modem.c index ef1d7fd..1269fbb 100644 --- a/src/modem.c +++ b/src/modem.c @@ -55,11 +55,12 @@ struct modem *modem_open(const char *dev) { assert(m->dev); m->buffio = buffio_new(fd); assert(m->buffio); - m->state = MODEM_STATE_INIT; + m->buffio->output_empty_cb = modem_output_empty_cb; + m->buffio->input_ready_cb = modem_output_ready_cb; + m->child_pid = -1; - modem_timeout(m, 10); - modem_next_command(m); + modem_init(m); return m; @@ -195,11 +196,10 @@ static const char* const init_at_commands[INIT_AT_COMMANDS*2] = { -static void modem_input_init_cb(struct buffio *b, void *user) { +static void modem_input_ready_cb(struct buffio *b, void *user) { struct modem *m = user; assert(b && m && m->buffio == b); - switch (m->state) { case MODEM_STATE_INIT: { @@ -213,6 +213,7 @@ static void modem_input_init_cb(struct buffio *b, void *user) { if (m->command_index >= INIT_AT_COMMANDS) { m->state = MODEM_STATE_CALLER_NUMBER_EXPECT; + modem_timeout(m, 0); modem_input_init_cb(b, user); } else modem_next_command(m); @@ -294,15 +295,49 @@ static void modem_input_init_cb(struct buffio *b, void *user) { break; case MODEM_STATE_CONNECTION: + + m->state = MODEM_STATE_HANGUP; break; - case MODEM_STATE_DONE: + case MODEM_STATE_HANGUP: { + + modem_send_command(m, { DLE, DC4, DLE, ETX, 0 }); + m->state = MODEM_STATE_FORCE_HANGUP; break; + } + } +} + + +static void modem_output_empty_cb(struct buffio *b, void *user) { + struct modem *m = user; + assert(b && m && m->buffio == b); + + switch (m->state) { + case MODEM_STATE_FORCE_HANGUP: + modem_force_hangup(m); + modem_init(m); + break; } - } +void modem_force_hangup(struct modem *m) { + struct termios pts; + assert(m && m->buffio); + + tcgetattr(m->buffio->fd, &pts); + cfsetospeed(&pts, B0); + cfsetispeed(&pts, B0); + tcsetattr(m->buffio->fd, TCSANOW, &pts); + + tcgetattr(m->buffio->fd, &pts); + cfsetospeed(&pts, BAUD_RATE); + cfsetispeed(&pts, BAUD_RATE); + tcsetattr(m->buffio->fd, TCSANOW, &pts); +} + + static void modem_send_command(struct modem *m, const char *p) { assert(m && m->buffio); @@ -328,6 +363,14 @@ static void modem_next_command(struct modem *m) { m->buffio->input_cb = modem_input_cb; buffio_command(m->buffio, p); + } -// { DLE, DC4, DLE, ETX, 'A', 'T', 'H', '\n', "AT&F\n" }, +static void modem_init(struct modem *m) { + assert(m); + m->state = MODEM_STATE_INIT; + m->command_index = 0; + + modem_timeout(m, 10); + modem_next_command(m); +} -- cgit