1 From 516d67c679101d1503dbd4c0613bcd6ff1b604e4 Mon Sep 17 00:00:00 2001
2 From: Andrzej Zaborowski <balrog@zabor.org>
3 Date: Wed, 19 Sep 2007 14:03:28 +0200
4 Subject: [PATCH] Introduce ports.
7 include/gsmd/atcmd.h | 2 +-
8 include/gsmd/gsmd.h | 7 +-
9 include/gsmd/uart.h | 28 ++++++
10 include/gsmd/vendorplugin.h | 4 +-
11 src/gsmd/Makefile.am | 2 +-
12 src/gsmd/atcmd.c | 177 +++++++++++++++++---------------------
13 src/gsmd/gsmd.c | 64 ++------------
14 src/gsmd/uart.c | 202 +++++++++++++++++++++++++++++++++++++++++++
15 8 files changed, 328 insertions(+), 158 deletions(-)
16 create mode 100644 include/gsmd/uart.h
17 create mode 100644 src/gsmd/uart.c
19 diff --git a/include/gsmd/atcmd.h b/include/gsmd/atcmd.h
20 index 0d6c62a..a1af6a0 100644
21 --- a/include/gsmd/atcmd.h
22 +++ b/include/gsmd/atcmd.h
23 @@ -9,7 +9,7 @@ typedef int atcmd_cb_t(struct gsmd_atcmd *cmd, void *ctx, char *resp);
25 extern struct gsmd_atcmd *atcmd_fill(const char *cmd, int rlen, atcmd_cb_t *cb, void *ctx, u_int16_t id);
26 extern int atcmd_submit(struct gsmd *g, struct gsmd_atcmd *cmd);
27 -extern int atcmd_init(struct gsmd *g, int sockfd);
28 +extern int atcmd_init(struct gsmd *g, struct gsmd_port *port);
29 extern void atcmd_drain(int fd);
32 diff --git a/include/gsmd/gsmd.h b/include/gsmd/gsmd.h
33 index ed334f1..4afdf66 100644
34 --- a/include/gsmd/gsmd.h
35 +++ b/include/gsmd/gsmd.h
37 #include <gsmd/machineplugin.h>
38 #include <gsmd/vendorplugin.h>
39 #include <gsmd/select.h>
40 +#include <gsmd/uart.h>
41 #include <gsmd/state.h>
44 @@ -52,6 +53,7 @@ enum llparse_state {
45 #define MLPARSE_BUF_SIZE 65535
48 + struct gsmd_port *port;
49 enum llparse_state state;
52 @@ -70,7 +72,7 @@ struct gsmd;
55 int interpreter_ready;
56 - struct gsmd_fd gfd_uart;
57 + struct gsmd_uart uart;
58 struct gsmd_fd gfd_sock;
60 struct llist_head users;
61 @@ -81,9 +83,10 @@ struct gsmd {
62 struct gsmd_device_state dev_state;
64 struct llist_head operators; /* cached list of operator names */
65 - unsigned char *mlbuf; /* ml_parse buffer */
66 + char *mlbuf; /* ml_parse buffer */
67 unsigned int mlbuf_len;
73 diff --git a/include/gsmd/uart.h b/include/gsmd/uart.h
75 index 0000000..a006fa7
77 +++ b/include/gsmd/uart.h
79 +#ifndef __GSMD_UART_H
80 +#define __GSMD_UART_H
85 + int (*write)(struct gsmd_port *port, const char data[], int len);
86 + int (*set_break)(struct gsmd_port *port, int state);
87 + /* more parameters here */
88 + int (*newdata_cb)(void *opaque, const char data[], int len);
89 + void *newdata_opaque;
93 + struct gsmd_port port;
100 +extern int set_baudrate(int fd, int baudrate, int hwflow);
101 +extern void uart_drain(int fd);
102 +extern int uart_init(struct gsmd_uart *uart, int sockfd);
104 +#endif /* __GSMD__ */
107 diff --git a/include/gsmd/vendorplugin.h b/include/gsmd/vendorplugin.h
108 index 1911fef..1c82790 100644
109 --- a/include/gsmd/vendorplugin.h
110 +++ b/include/gsmd/vendorplugin.h
111 @@ -11,8 +11,8 @@ struct gsmd_unsolicit;
113 struct gsmd_vendor_plugin {
114 struct llist_head list;
115 - unsigned char *name;
116 - unsigned char *ext_chars;
119 unsigned int num_unsolicit;
120 const struct gsmd_unsolicit *unsolicit;
121 int (*detect)(struct gsmd *g);
122 diff --git a/src/gsmd/Makefile.am b/src/gsmd/Makefile.am
123 index 9ac45ee..110b757 100644
124 --- a/src/gsmd/Makefile.am
125 +++ b/src/gsmd/Makefile.am
126 @@ -13,7 +13,7 @@ sbin_PROGRAMS = gsmd
127 gsmd_CFLAGS = -D PLUGINDIR=\"$(plugindir)\"
128 gsmd_SOURCES = gsmd.c atcmd.c select.c machine.c vendor.c unsolicited.c log.c \
129 usock.c talloc.c timer.c operator_cache.c ext_response.c \
131 + sms_cb.c sms_pdu.c uart.c
133 gsmd_LDFLAGS = -Wl,--export-dynamic
135 diff --git a/src/gsmd/atcmd.c b/src/gsmd/atcmd.c
136 index 2ef6a10..27dfa41 100644
137 --- a/src/gsmd/atcmd.c
138 +++ b/src/gsmd/atcmd.c
139 @@ -159,7 +159,8 @@ static int llparse_byte(struct llparser *llp, char byte)
143 -static int llparse_string(struct llparser *llp, char *buf, unsigned int len)
144 +static int llparse_string(struct llparser *llp, const char *buf,
148 int rc = llparse_byte(llp, *(buf++));
149 @@ -187,6 +188,55 @@ static int llparse_init(struct llparser *llp)
153 +/* See if we can now send more commands to the port */
154 +static void atcmd_wake_queue(struct gsmd *g)
159 + /* write pending commands to UART */
160 + while (g->interpreter_ready && g->clear_to_send) {
161 + struct gsmd_atcmd *pos, *pos2;
162 + llist_for_each_entry_safe(pos, pos2, &g->pending_atcmds, list) {
163 + cr = strchr(pos->cur, '\n');
165 + len = cr - pos->cur;
168 + rc = g->llp.port->write(g->llp.port, pos->cur, len);
170 + gsmd_log(GSMD_ERROR,
171 + "write returns 0, aborting\n");
174 + if (cr && rc == len)
175 + rc ++; /* Skip the \n */
178 + g->llp.port->write(g->llp.port, "\r", 1);
180 + if (!pos->buflen) {
181 + /* success: remove from global list of
182 + * to-be-sent atcmds */
183 + llist_del(&pos->list);
184 + /* append to global list of executing atcmds */
185 + llist_add_tail(&pos->list, &g->busy_atcmds);
187 + /* we only send one cmd at the moment */
188 + g->clear_to_send = 0;
191 + /* The write was short or the atcmd has more
192 + * lines to send after a "> ". */
195 + g->clear_to_send = 0;
202 /* mid-level parser */
204 static int parse_final_result(const char *res)
205 @@ -216,6 +266,7 @@ static int ml_parse(const char *buf, int len, void *ctx)
206 g->interpreter_ready = 1;
207 gsmd_initsettings(g);
209 + atcmd_wake_queue(g);
213 @@ -316,6 +367,7 @@ static int ml_parse(const char *buf, int len, void *ctx)
215 DEBUGP("Calling cmd->cb()\n");
216 cmd->resp = g->mlbuf;
217 + g->mlbuf[g->mlbuf_len] = 0;
218 rc = cmd->cb(cmd, cmd->ctx, cmd->resp);
219 DEBUGP("Clearing mlbuf\n");
221 @@ -370,12 +422,15 @@ static int ml_parse(const char *buf, int len, void *ctx)
223 g->mlbuf[g->mlbuf_len ++] = '\n';
224 DEBUGP("Appending buf to mlbuf\n");
225 - if (len > MLPARSE_BUF_SIZE - g->mlbuf_len)
226 + if (len > MLPARSE_BUF_SIZE - g->mlbuf_len) {
227 len = MLPARSE_BUF_SIZE - g->mlbuf_len;
228 + gsmd_log(GSMD_NOTICE, "g->mlbuf overrun\n");
230 memcpy(g->mlbuf + g->mlbuf_len, buf, len);
233 if (g->mlunsolicited) {
234 + g->mlbuf[g->mlbuf_len] = 0;
235 rc = unsolicited_parse(g, g->mlbuf, g->mlbuf_len,
236 strchr(g->mlbuf, ':') + 1);
238 @@ -422,8 +477,11 @@ final_cb:
240 /* if we're finished with current commands, but still have pending
241 * commands: we want to WRITE again */
242 - if (llist_empty(&g->busy_atcmds) && !llist_empty(&g->pending_atcmds))
243 - g->gfd_uart.when |= GSMD_FD_WRITE;
244 + if (llist_empty(&g->busy_atcmds)) {
245 + g->clear_to_send = 1;
246 + if (!llist_empty(&g->pending_atcmds))
247 + atcmd_wake_queue(g);
252 @@ -433,85 +491,23 @@ static int atcmd_prompt(void *data)
254 struct gsmd *g = data;
256 - g->gfd_uart.when |= GSMD_FD_WRITE;
257 + g->clear_to_send = 1;
258 + atcmd_wake_queue(g);
261 /* callback to be called if [virtual] UART has some data for us */
262 -static int atcmd_select_cb(int fd, unsigned int what, void *data)
263 +static int atcmd_newdata_cb(void *opaque, const char data[], int len)
266 - static char rxbuf[1024];
267 - struct gsmd *g = data;
270 - if (what & GSMD_FD_READ) {
271 - memset(rxbuf, 0, sizeof(rxbuf));
272 - while ((len = read(fd, rxbuf, sizeof(rxbuf)))) {
274 - if (errno == EAGAIN)
276 - gsmd_log(GSMD_NOTICE, "ERROR reading from fd %u: %d (%s)\n", fd, len,
280 - rc = llparse_string(&g->llp, rxbuf, len);
282 - gsmd_log(GSMD_ERROR, "ERROR during llparse_string: %d\n", rc);
288 - /* write pending commands to UART */
289 - if ((what & GSMD_FD_WRITE) && g->interpreter_ready) {
290 - struct gsmd_atcmd *pos, *pos2;
291 - llist_for_each_entry_safe(pos, pos2, &g->pending_atcmds, list) {
292 - cr = strchr(pos->cur, '\n');
294 - len = cr - pos->cur;
296 - len = pos->buflen - 1; /* assuming zero-terminated strings */
297 - rc = write(fd, pos->cur, len);
299 - gsmd_log(GSMD_ERROR, "write returns 0, aborting\n");
301 - } else if (rc < 0) {
302 - gsmd_log(GSMD_ERROR, "error during write to fd %d: %d\n",
306 - if (!cr || rc == len)
307 - rc ++; /* Skip the \n or \0 */
310 - write(fd, "\r", 1);
312 - if (!pos->buflen) {
313 - /* success: remove from global list of
314 - * to-be-sent atcmds */
315 - llist_del(&pos->list);
316 - /* append to global list of executing atcmds */
317 - llist_add_tail(&pos->list, &g->busy_atcmds);
319 - /* we only send one cmd at the moment */
322 - /* The write was short or the atcmd has more
323 - * lines to send after a "> ". */
329 + struct gsmd *g = opaque;
332 - /* Either pending_atcmds is empty or a command has to wait */
333 - g->gfd_uart.when &= ~GSMD_FD_WRITE;
335 + rc = llparse_string(&g->llp, data, len);
337 + gsmd_log(GSMD_ERROR, "ERROR during llparse_string: %d\n", rc);
344 struct gsmd_atcmd *atcmd_fill(const char *cmd, int rlen,
345 atcmd_cb_t cb, void *ctx, u_int16_t id)
347 @@ -544,36 +540,18 @@ int atcmd_submit(struct gsmd *g, struct gsmd_atcmd *cmd)
349 DEBUGP("submitting command `%s'\n", cmd->buf);
351 - if (llist_empty(&g->pending_atcmds))
352 - g->gfd_uart.when |= GSMD_FD_WRITE;
353 + llist_empty(&g->pending_atcmds);
354 llist_add_tail(&cmd->list, &g->pending_atcmds);
355 + atcmd_wake_queue(g);
360 -void atcmd_drain(int fd)
364 - rc = tcflush(fd, TCIOFLUSH);
365 - rc = tcgetattr(fd, &t);
366 - DEBUGP("c_iflag = 0x%08x, c_oflag = 0x%08x, c_cflag = 0x%08x, c_lflag = 0x%08x\n",
367 - t.c_iflag, t.c_oflag, t.c_cflag, t.c_lflag);
368 - t.c_iflag = t.c_oflag = 0;
370 - rc = tcsetattr(fd, TCSANOW, &t);
373 /* init atcmd parser */
374 -int atcmd_init(struct gsmd *g, int sockfd)
375 +int atcmd_init(struct gsmd *g, struct gsmd_port *port)
377 __atcmd_ctx = talloc_named_const(gsmd_tallocs, 1, "atcmds");
379 - g->gfd_uart.fd = sockfd;
380 - g->gfd_uart.when = GSMD_FD_READ;
381 - g->gfd_uart.data = g;
382 - g->gfd_uart.cb = &atcmd_select_cb;
384 INIT_LLIST_HEAD(&g->pending_atcmds);
385 INIT_LLIST_HEAD(&g->busy_atcmds);
387 @@ -581,7 +559,9 @@ int atcmd_init(struct gsmd *g, int sockfd)
390 g->mlunsolicited = 0;
391 + g->clear_to_send = 1;
393 + g->llp.port = port;
394 g->llp.cur = g->llp.buf;
395 g->llp.len = sizeof(g->llp.buf);
396 g->llp.cb = &ml_parse;
397 @@ -589,5 +569,8 @@ int atcmd_init(struct gsmd *g, int sockfd)
399 g->llp.flags = LGSM_ATCMD_F_EXTENDED;
401 - return gsmd_register_fd(&g->gfd_uart);
402 + port->newdata_opaque = g;
403 + port->newdata_cb = atcmd_newdata_cb;
407 diff --git a/src/gsmd/gsmd.c b/src/gsmd/gsmd.c
408 index 51b4f2c..846bd17 100644
409 --- a/src/gsmd/gsmd.c
410 +++ b/src/gsmd/gsmd.c
415 -#include <termios.h>
419 @@ -247,56 +246,6 @@ int gsmd_initsettings(struct gsmd *gsmd)
420 return atcmd_submit(gsmd, cmd);
428 -static struct bdrt bdrts[] = {
434 - { 115200, B115200 },
435 - { 230400, B230400 },
436 - { 460800, B460800 },
437 - { 921600, B921600 },
440 -static int set_baudrate(int fd, int baudrate, int hwflow)
446 - for (i = 0; i < ARRAY_SIZE(bdrts); i++) {
447 - if (bdrts[i].bps == baudrate)
453 - i = tcgetattr(fd, &ti);
457 - i = cfsetispeed(&ti, B0);
461 - i = cfsetospeed(&ti, bd);
466 - ti.c_cflag |= CRTSCTS;
468 - ti.c_cflag &= ~CRTSCTS;
470 - return tcsetattr(fd, 0, &ti);
473 static int gsmd_initialize(struct gsmd *g)
475 INIT_LLIST_HEAD(&g->users);
476 @@ -478,14 +427,19 @@ int main(int argc, char **argv)
478 g.interpreter_ready = !wait;
480 - if (atcmd_init(&g, fd) < 0) {
481 + if (uart_init(&g.uart, fd) < 0) {
482 fprintf(stderr, "can't initialize UART device\n");
486 - write(fd, "\r", 1);
489 + if (atcmd_init(&g, &g.uart.port) < 0) {
490 + fprintf(stderr, "can't initialize AT parser\n");
493 + write(fd, "\r", 1);
498 if (usock_init(&g) < 0) {
499 fprintf(stderr, "can't open unix socket\n");
500 diff --git a/src/gsmd/uart.c b/src/gsmd/uart.c
502 index 0000000..22a4a5c
504 +++ b/src/gsmd/uart.c
506 +/* Wrapper for the physical UART in a struct gsmd_port abstraction.
508 + * Copyright (C) 2007 Openmoko, Inc.
509 + * Written by Andrzej Zaborowski <andrew@openedhand.com>
511 + * This program is free software; you can redistribute it and/or
512 + * modify it under the terms of the GNU General Public License as
513 + * published by the Free Software Foundation; either version 2 of
514 + * the License, or (at your option) any later version.
516 + * This program is distributed in the hope that it will be useful,
517 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
518 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
519 + * GNU General Public License for more details.
521 + * You should have received a copy of the GNU General Public License
522 + * along with this program; if not, write to the Free Software
523 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
524 + * MA 02111-1307 USA
529 +#include <termios.h>
535 +#include <gsmd/gsmd.h>
537 +void uart_drain(int fd)
541 + rc = tcflush(fd, TCIOFLUSH);
542 + rc = tcgetattr(fd, &t);
544 + "c_iflag = 0x%08x, c_oflag = 0x%08x, "
545 + "c_cflag = 0x%08x, c_lflag = 0x%08x\n",
546 + t.c_iflag, t.c_oflag, t.c_cflag, t.c_lflag);
547 + t.c_iflag = t.c_oflag = 0;
549 + rc = tcsetattr(fd, TCSANOW, &t);
557 +static struct bdrt bdrts[] = {
563 + { 115200, B115200 },
564 + { 230400, B230400 },
565 + { 460800, B460800 },
566 + { 921600, B921600 },
569 +int set_baudrate(int fd, int baudrate, int hwflow)
575 + for (i = 0; i < ARRAY_SIZE(bdrts); i++) {
576 + if (bdrts[i].bps == baudrate)
582 + i = tcgetattr(fd, &ti);
586 + i = cfsetispeed(&ti, B0);
590 + i = cfsetospeed(&ti, bd);
595 + ti.c_cflag |= CRTSCTS;
597 + ti.c_cflag &= ~CRTSCTS;
599 + return tcsetattr(fd, 0, &ti);
602 +static int uart_select_cb(int fd, unsigned int what, void *data)
604 + struct gsmd_uart *uart = (struct gsmd_uart *) data;
605 + static char rxbuf[2048];
608 + if ((what & GSMD_FD_READ) && uart->port.newdata_cb) {
609 + while ((len = read(fd, rxbuf, sizeof(rxbuf)))) {
611 + if (errno == EAGAIN || errno == EINTR)
613 + gsmd_log(GSMD_NOTICE, "ERROR reading from "
614 + "fd %u: %d (%s)\n", fd, errno,
619 + rc = uart->port.newdata_cb(
620 + uart->port.newdata_opaque,
628 + /* Write pending data to UART. */
629 + if ((what & GSMD_FD_WRITE) && uart->tx_len) {
630 + while (uart->tx_start + uart->tx_len >= sizeof(uart->txfifo)) {
631 + len = sizeof(uart->txfifo) - uart->tx_start;
632 + rc = write(fd, &uart->txfifo[uart->tx_start], len);
633 + if (rc < 0 && errno != EINTR) {
634 + if (errno == EAGAIN)
636 + gsmd_log(GSMD_NOTICE, "ERROR writing "
637 + "fd %u: %d (%s)\n", fd, errno,
643 + uart->tx_start += rc;
644 + uart->tx_len -= rc;
647 + uart->tx_start &= sizeof(uart->txfifo) - 1;
649 + while (uart->tx_len) {
650 + rc = write(fd, &uart->txfifo[uart->tx_start],
652 + if (rc < 0 && errno != EINTR) {
653 + if (errno == EAGAIN)
655 + gsmd_log(GSMD_NOTICE, "ERROR writing "
656 + "fd %u: %d (%s)\n", fd, errno,
662 + uart->tx_start += rc;
663 + uart->tx_len -= rc;
667 + /* If we reached here, there's no more data for the moment. */
668 + uart->gfd.when &= ~GSMD_FD_WRITE;
674 +static int uart_write(struct gsmd_port *port, const char data[], int len)
676 + struct gsmd_uart *uart = (struct gsmd_uart *) port;
677 + int start = (uart->tx_start + uart->tx_len) &
678 + (sizeof(uart->txfifo) - 1);
679 + int space = sizeof(uart->txfifo) - start;
681 + if (uart->tx_len + len > sizeof(uart->txfifo))
682 + len = sizeof(uart->txfifo) - uart->tx_len;
685 + uart->gfd.when |= GSMD_FD_WRITE;
688 + memcpy(uart->txfifo + start, data, space);
689 + memcpy(uart->txfifo, data + space, len - space);
691 + memcpy(uart->txfifo + start, data, len);
693 + uart->tx_len += len;
697 +int uart_init(struct gsmd_uart *uart, int sockfd)
699 + uart->gfd.fd = sockfd;
700 + uart->gfd.when = GSMD_FD_READ;
701 + uart->gfd.data = uart;
702 + uart->gfd.cb = &uart_select_cb;
704 + uart->port.write = uart_write;
706 + return gsmd_register_fd(&uart->gfd);