summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2003-12-17 22:11:57 +0000
committerLennart Poettering <lennart@poettering.net>2003-12-17 22:11:57 +0000
commitc79399f437e9268203768ab65b32c20f29093b27 (patch)
tree4fdebb22251b0a80faf8011436829a3521e7aad9
parentd918d9b2c4fc9eaa58bcd9a266a6a0330c88391c (diff)
much further work
git-svn-id: file:///home/lennart/svn/public/ivam2/trunk@7 dbf6933d-3bce-0310-9bcc-ed052ba35b35
-rw-r--r--src/buffio.c202
-rw-r--r--src/buffio.h31
-rw-r--r--src/dle.c47
-rw-r--r--src/dle.h7
-rw-r--r--src/modem.c203
-rw-r--r--src/modem.h25
6 files changed, 491 insertions, 24 deletions
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);