From 23dfcf4ff925f61bcb2c3bdd712ff0f70bde4fcb Mon Sep 17 00:00:00 2001 From: laforge Date: Tue, 24 Oct 2006 13:07:08 +0000 Subject: - clean up header files (all in include/gmsd now) - finish vendor plugin support - add call progress indicator and signal quality unsolicited support to vendor_ti.c git-svn-id: http://svn.openmoko.org/trunk/src/target/gsm@120 99fdad57-331a-0410-800a-d7fa5415bdb3 --- include/gsmd/atcmd.h | 17 ++++++ include/gsmd/gsmd.h | 88 +++++++++++++++++++++++++++++++ include/gsmd/select.h | 26 ++++++++++ include/gsmd/unsolicited.h | 18 +++++++ include/gsmd/usock.h | 41 ++++++++++++++- include/gsmd/vendorplugin.h | 27 ++++++++++ src/gsmd/Makefile.am | 3 +- src/gsmd/atcmd.c | 10 ++-- src/gsmd/atcmd.h | 13 ----- src/gsmd/gsmd.c | 24 ++++++--- src/gsmd/gsmd.h | 84 ------------------------------ src/gsmd/log.c | 2 + src/gsmd/select.c | 5 +- src/gsmd/select.h | 22 -------- src/gsmd/unsolicited.c | 58 +++++++++++++-------- src/gsmd/unsolicited.h | 9 ---- src/gsmd/usock.c | 117 ++++++++++++++++++++++++++++++++++++++++-- src/gsmd/usock.h | 16 ------ src/gsmd/vendor.c | 39 ++++++++++++++ src/gsmd/vendor_ti.c | 91 +++++++++++++++++++++++++++++--- src/gsmd/vendorplugin.h | 4 ++ src/libgsmd/libgsmd.c | 6 ++- src/libgsmd/libgsmd_network.c | 4 ++ src/util/atcmd.c | 2 + src/util/event.c | 15 ++++-- 25 files changed, 544 insertions(+), 197 deletions(-) create mode 100644 include/gsmd/atcmd.h create mode 100644 include/gsmd/select.h create mode 100644 include/gsmd/unsolicited.h create mode 100644 include/gsmd/vendorplugin.h delete mode 100644 src/gsmd/atcmd.h delete mode 100644 src/gsmd/gsmd.h delete mode 100644 src/gsmd/select.h delete mode 100644 src/gsmd/unsolicited.h delete mode 100644 src/gsmd/usock.h create mode 100644 src/gsmd/vendor.c diff --git a/include/gsmd/atcmd.h b/include/gsmd/atcmd.h new file mode 100644 index 0000000..0d6c62a --- /dev/null +++ b/include/gsmd/atcmd.h @@ -0,0 +1,17 @@ +#ifndef __GSMD_ATCMD_H +#define __GSMD_ATCMD_H + +#ifdef __GSMD__ + +#include + +typedef int atcmd_cb_t(struct gsmd_atcmd *cmd, void *ctx, char *resp); + +extern struct gsmd_atcmd *atcmd_fill(const char *cmd, int rlen, atcmd_cb_t *cb, void *ctx, u_int16_t id); +extern int atcmd_submit(struct gsmd *g, struct gsmd_atcmd *cmd); +extern int atcmd_init(struct gsmd *g, int sockfd); +extern void atcmd_drain(int fd); + +#endif /* __GSMD__ */ + +#endif diff --git a/include/gsmd/gsmd.h b/include/gsmd/gsmd.h index f5b61d5..9b99a15 100644 --- a/include/gsmd/gsmd.h +++ b/include/gsmd/gsmd.h @@ -1,4 +1,92 @@ #ifndef _GSMD_H #define _GSMD_H +#ifdef __GSMD__ + +#include + +#include + +#include +#include + +/* Refer to 3GPP TS 07.07 v 7.8.0, Chapter 4.1 */ +#define LGSM_ATCMD_F_EXTENDED 0x01 /* as opposed to basic */ +#define LGSM_ATCMD_F_PARAM 0x02 /* as opposed to action */ + +struct gsmd_atcmd { + struct llist_head list; + void *ctx; + int (*cb)(struct gsmd_atcmd *cmd, void *ctx, char *resp); + char *resp; + int32_t ret; + u_int32_t buflen; + u_int16_t id; + u_int8_t flags; + char buf[]; +}; + +enum llparse_state { + LLPARSE_STATE_IDLE, /* idle, not parsing a response */ + LLPARSE_STATE_IDLE_CR, /* CR before response (V1) */ + LLPARSE_STATE_IDLE_LF, /* LF before response (V1) */ + LLPARSE_STATE_RESULT, /* within result payload */ + LLPARSE_STATE_RESULT_CR, /* CR after result */ + LLPARSE_STATE_ERROR, /* something went wrong */ + /* ... idle again */ +}; + +/* we can't take any _single_ response bigger than this: */ +#define LLPARSE_BUF_SIZE 256 + +struct llparser { + enum llparse_state state; + unsigned int len; + unsigned int flags; + void *ctx; + int (*cb)(const char *buf, int len, void *ctx); + char *cur; + char buf[LLPARSE_BUF_SIZE]; +}; + +struct gsmd; + +#define GSMD_FLAG_V0 0x0001 /* V0 responses to be expected from TA */ + +struct gsmd { + unsigned int flags; + struct gsmd_fd gfd_uart; + struct gsmd_fd gfd_sock; + struct llparser llp; + struct llist_head users; + struct llist_head pending_atcmds; /* our busy gsmd_atcmds */ + struct llist_head busy_atcmds; /* our busy gsmd_atcmds */ + struct gsmd_vendor_plugin *vendorpl; +}; + +struct gsmd_user { + struct llist_head list; /* our entry in the global list */ + struct llist_head finished_ucmds; /* our busy gsmd_ucmds */ + struct gsmd *gsmd; + struct gsmd_fd gfd; /* the socket */ + u_int32_t subscriptions; /* bitmaks of subscribed event groups */ +}; + +#define GSMD_DEBUG 1 /* debugging information */ +#define GSMD_INFO 3 +#define GSMD_NOTICE 5 /* abnormal/unexpected condition */ +#define GSMD_ERROR 7 /* error condition, requires user action */ +#define GSMD_FATAL 8 /* fatal, program aborted */ + +extern int gsmdlog_init(const char *path); +/* write a message to the daemons' logfile */ +void __gsmd_log(int level, const char *file, int line, const char *function, const char *message, ...); +/* macro for logging including filename and line number */ +#define gsmd_log(level, format, args ...) \ + __gsmd_log(level, __FILE__, __LINE__, __FUNCTION__, format, ## args) + +#define DEBUGP(x, args ...) gsmd_log(GSMD_DEBUG, x, ## args) + +#endif /* __GSMD__ */ + #endif /* _GSMD_H */ diff --git a/include/gsmd/select.h b/include/gsmd/select.h new file mode 100644 index 0000000..b75c338 --- /dev/null +++ b/include/gsmd/select.h @@ -0,0 +1,26 @@ +#ifndef __GSMD_SELECT_H +#define __GSMD_SELECT_H + +#ifdef __GSMD__ + +#include + +#define GSMD_FD_READ 0x0001 +#define GSMD_FD_WRITE 0x0002 +#define GSMD_FD_EXCEPT 0x0004 + +struct gsmd_fd { + struct llist_head list; + int fd; /* file descriptor */ + unsigned int when; + int (*cb)(int fd, unsigned int what, void *data); + void *data; /* void * to pass to callback */ +}; + +extern int gsmd_register_fd(struct gsmd_fd *ufd); +extern void gsmd_unregister_fd(struct gsmd_fd *ufd); +extern int gsmd_select_main(void); + +#endif /* __GSMD__ */ + +#endif diff --git a/include/gsmd/unsolicited.h b/include/gsmd/unsolicited.h new file mode 100644 index 0000000..e7f17c5 --- /dev/null +++ b/include/gsmd/unsolicited.h @@ -0,0 +1,18 @@ +#ifndef __GSMD_UNSOLICITED_H +#define __GSMD_UNSOLICITED_H + +#ifdef __GSMD__ + +#include + +struct gsmd_unsolicit { + const char *prefix; + int (*parse)(char *unsol, int len, const char *param, struct gsmd *gsmd); +}; + +extern int unsolicited_parse(struct gsmd *g, char *buf, int len, const char *param); +extern int generate_event_from_cme(struct gsmd *g, unsigned int cme_error); + +#endif /* __GSMD__ */ + +#endif diff --git a/include/gsmd/usock.h b/include/gsmd/usock.h index 2eaa6cf..94e8c37 100644 --- a/include/gsmd/usock.h +++ b/include/gsmd/usock.h @@ -53,6 +53,9 @@ enum gsmd_msg_phone { enum gsmd_msg_network { GSMD_NETWORK_REGISTER = 1, + GSMD_NETWORK_SIGQ_GET = 2, + GSMD_NETWORK_VMAIL_GET = 3, + GSMD_NETWORK_VMAIL_SET = 4, }; /* Length from 3GPP TS 04.08, Clause 10.5.4.7 */ @@ -61,7 +64,17 @@ enum gsmd_msg_network { struct gsmd_addr { u_int8_t type; char number[GSMD_ADDR_MAXLEN+1]; -}; +} __attribute__ ((packed)); + +struct gsmd_signal_quality { + u_int8_t rssi; + u_int8_t ber; +} __attribute__ ((packed)); + +struct gsmd_voicemail { + u_int8_t enable; + struct gsmd_addr addr; +} __attribute__ ((packed)); struct gsmd_evt_auxdata { union { @@ -89,6 +102,9 @@ struct gsmd_evt_auxdata { struct { u_int8_t tz; } timezone; + struct { + struct gsmd_signal_quality sigq; + } signal; } u; } __attribute__((packed)); @@ -103,4 +119,27 @@ struct gsmd_msg_hdr { } __attribute__((packed)); +#ifdef __GSMD__ + +#include + +#include +#include + +struct gsmd_user; + +struct gsmd_ucmd { + struct llist_head list; + struct gsmd_msg_hdr hdr; + char buf[]; +} __attribute__ ((packed)); + +extern int usock_init(struct gsmd *g); +extern void usock_cmd_enqueue(struct gsmd_ucmd *ucmd, struct gsmd_user *gu); +extern struct gsmd_ucmd *usock_build_event(u_int8_t type, u_int8_t subtype, u_int8_t len); +extern int usock_evt_send(struct gsmd *gsmd, struct gsmd_ucmd *ucmd, u_int32_t evt); + +#endif /* __GSMD__ */ + #endif + diff --git a/include/gsmd/vendorplugin.h b/include/gsmd/vendorplugin.h new file mode 100644 index 0000000..c3843b2 --- /dev/null +++ b/include/gsmd/vendorplugin.h @@ -0,0 +1,27 @@ +#ifndef _GSMD_VENDORPLUGIN_H +#define _GSMD_VENDORPLUGIN_H + +#ifdef __GSMD__ + +#include +#include + +struct gsmd; +struct gsmd_unsolicit; + +struct gsmd_vendor_plugin { + struct llist_head list; + unsigned char *name; + unsigned int num_unsolicit; + const struct gsmd_unsolicit *unsolicit; + int (*detect)(struct gsmd *g); + int (*initsettings)(struct gsmd *g); +}; + +extern int gsmd_vendor_plugin_register(struct gsmd_vendor_plugin *pl); +extern void gsmd_vendor_plugin_unregister(struct gsmd_vendor_plugin *pl); +extern int gsmd_vendor_plugin_find(struct gsmd *g); + +#endif /* __GSMD__ */ + +#endif diff --git a/src/gsmd/Makefile.am b/src/gsmd/Makefile.am index 2d62662..d720a4c 100644 --- a/src/gsmd/Makefile.am +++ b/src/gsmd/Makefile.am @@ -3,7 +3,8 @@ AM_CFLAGS = -std=gnu99 bin_PROGRAMS = gsmd -gsmd_SOURCES = gsmd.c atcmd.c select.c vendor_ti.c usock.c unsolicited.c log.c +gsmd_SOURCES = gsmd.c atcmd.c select.c vendor.c usock.c unsolicited.c log.c \ + vendor_ti.c #gsmd_LDADD = ../libgsmd/libgsmd.la #gsmd_LDFLAGS = -dynamic diff --git a/src/gsmd/atcmd.c b/src/gsmd/atcmd.c index 53120f4..7f95465 100644 --- a/src/gsmd/atcmd.c +++ b/src/gsmd/atcmd.c @@ -8,11 +8,13 @@ #include #include -#include #include "gsmd.h" -#include "atcmd.h" -#include "unsolicited.h" + +#include +#include +#include +#include /* libgsmd / gsmd AT command interpreter / parser / constructor * (C) 2006 by Harald Welte @@ -179,7 +181,7 @@ static int ml_parse(const char *buf, int len, void *ctx) * TBD */ - if (buf[0] == '+') { + if (buf[0] == '+' || buf[0] == '%') { /* an extended response */ const char *colon = strchr(buf, ':'); if (!colon) { diff --git a/src/gsmd/atcmd.h b/src/gsmd/atcmd.h deleted file mode 100644 index 1e4cdfb..0000000 --- a/src/gsmd/atcmd.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef __GSMD_ATCMD_H -#define __GSMD_ATCMD_H - -#include "gsmd.h" - -typedef int atcmd_cb_t(struct gsmd_atcmd *cmd, void *ctx, char *resp); - -struct gsmd_atcmd *atcmd_fill(const char *cmd, int rlen, atcmd_cb_t *cb, void *ctx, u_int16_t id); -int atcmd_submit(struct gsmd *g, struct gsmd_atcmd *cmd); -int atcmd_init(struct gsmd *g, int sockfd); -void atcmd_drain(int fd); - -#endif diff --git a/src/gsmd/gsmd.c b/src/gsmd/gsmd.c index 9595d4b..c56e74c 100644 --- a/src/gsmd/gsmd.c +++ b/src/gsmd/gsmd.c @@ -12,13 +12,13 @@ #include #include -#include - #include "gsmd.h" -#include "atcmd.h" -#include "select.h" -#include "usock.h" -#include "vendorplugin.h" + +#include +#include +#include +#include +#include static int gsmd_test_atcb(struct gsmd_atcmd *cmd, void *ctx, char *resp) { @@ -26,7 +26,7 @@ static int gsmd_test_atcb(struct gsmd_atcmd *cmd, void *ctx, char *resp) return 0; } -static int gsmd_simplecmd(struct gsmd *gsmd, char *cmdtxt) +int gsmd_simplecmd(struct gsmd *gsmd, char *cmdtxt) { struct gsmd_atcmd *cmd; cmd = atcmd_fill(cmdtxt, strlen(cmdtxt)+1, &gsmd_test_atcb, NULL, 0); @@ -43,7 +43,10 @@ int gsmd_initsettings(struct gsmd *gsmd) rc |= gsmd_simplecmd(gsmd, "ATE0V1"); rc |= gsmd_simplecmd(gsmd, "AT+CRC=1;+CREG=2;+CMEE=1;+CLIP=1;+COLP=1;+CTZR=1;+CFUN=1"); - return rc; + if (gsmd->vendorpl && gsmd->vendorpl->initsettings) + return gsmd->vendorpl->initsettings(gsmd); + else + return rc; } struct bdrt { @@ -199,6 +202,11 @@ int main(int argc, char **argv) setsid(); } + /* FIXME: do this dynamically */ + ticalypso_init(); + + gsmd_vendor_plugin_find(&g); + gsmd_initsettings(&g); while (1) { diff --git a/src/gsmd/gsmd.h b/src/gsmd/gsmd.h deleted file mode 100644 index c67e15e..0000000 --- a/src/gsmd/gsmd.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef __GSMD_H -#define __GSMD_H - -#include - -#include - -#include "select.h" - -/* Refer to 3GPP TS 07.07 v 7.8.0, Chapter 4.1 */ -#define LGSM_ATCMD_F_EXTENDED 0x01 /* as opposed to basic */ -#define LGSM_ATCMD_F_PARAM 0x02 /* as opposed to action */ - -struct gsmd_atcmd { - struct llist_head list; - void *ctx; - int (*cb)(struct gsmd_atcmd *cmd, void *ctx, char *resp); - char *resp; - int32_t ret; - u_int32_t buflen; - u_int16_t id; - u_int8_t flags; - char buf[]; -}; - -enum llparse_state { - LLPARSE_STATE_IDLE, /* idle, not parsing a response */ - LLPARSE_STATE_IDLE_CR, /* CR before response (V1) */ - LLPARSE_STATE_IDLE_LF, /* LF before response (V1) */ - LLPARSE_STATE_RESULT, /* within result payload */ - LLPARSE_STATE_RESULT_CR, /* CR after result */ - LLPARSE_STATE_ERROR, /* something went wrong */ - /* ... idle again */ -}; - -/* we can't take any _single_ response bigger than this: */ -#define LLPARSE_BUF_SIZE 256 - -struct llparser { - enum llparse_state state; - unsigned int len; - unsigned int flags; - void *ctx; - int (*cb)(const char *buf, int len, void *ctx); - char *cur; - char buf[LLPARSE_BUF_SIZE]; -}; - -#define GSMD_FLAG_V0 0x0001 /* V0 responses to be expected from TA */ - -struct gsmd { - unsigned int flags; - struct gsmd_fd gfd_uart; - struct gsmd_fd gfd_sock; - struct llparser llp; - struct llist_head users; - struct llist_head pending_atcmds; /* our busy gsmd_atcmds */ - struct llist_head busy_atcmds; /* our busy gsmd_atcmds */ -}; - -struct gsmd_user { - struct llist_head list; /* our entry in the global list */ - struct llist_head finished_ucmds; /* our busy gsmd_ucmds */ - struct gsmd *gsmd; - struct gsmd_fd gfd; /* the socket */ - u_int32_t subscriptions; /* bitmaks of subscribed event groups */ -}; - -#define GSMD_DEBUG 1 /* debugging information */ -#define GSMD_INFO 3 -#define GSMD_NOTICE 5 /* abnormal/unexpected condition */ -#define GSMD_ERROR 7 /* error condition, requires user action */ -#define GSMD_FATAL 8 /* fatal, program aborted */ - -extern int gsmdlog_init(const char *path); -/* write a message to the daemons' logfile */ -void __gsmd_log(int level, const char *file, int line, const char *function, const char *message, ...); -/* macro for logging including filename and line number */ -#define gsmd_log(level, format, args ...) \ - __gsmd_log(level, __FILE__, __LINE__, __FUNCTION__, format, ## args) - -#define DEBUGP(x, args ...) gsmd_log(GSMD_DEBUG, x, ## args) - -#endif /* __GSMD_H */ diff --git a/src/gsmd/log.c b/src/gsmd/log.c index af58c6d..a601e69 100644 --- a/src/gsmd/log.c +++ b/src/gsmd/log.c @@ -11,6 +11,8 @@ #include "gsmd.h" +#include + static FILE *logfile; static FILE syslog_dummy; static int loglevel; diff --git a/src/gsmd/select.c b/src/gsmd/select.c index fc9647f..159b560 100644 --- a/src/gsmd/select.c +++ b/src/gsmd/select.c @@ -19,7 +19,10 @@ #include #include -#include "select.h" + +#include "gsmd.h" + +#include static int maxfd = 0; static LLIST_HEAD(gsmd_fds); diff --git a/src/gsmd/select.h b/src/gsmd/select.h deleted file mode 100644 index c734eb6..0000000 --- a/src/gsmd/select.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef __GSMD_SELECT_H -#define __GSMD_SELECT_H - -#include - -#define GSMD_FD_READ 0x0001 -#define GSMD_FD_WRITE 0x0002 -#define GSMD_FD_EXCEPT 0x0004 - -struct gsmd_fd { - struct llist_head list; - int fd; /* file descriptor */ - unsigned int when; - int (*cb)(int fd, unsigned int what, void *data); - void *data; /* void * to pass to callback */ -}; - -int gsmd_register_fd(struct gsmd_fd *ufd); -void gsmd_unregister_fd(struct gsmd_fd *ufd); -int gsmd_select_main(void); - -#endif diff --git a/src/gsmd/unsolicited.c b/src/gsmd/unsolicited.c index e97f478..57a4e59 100644 --- a/src/gsmd/unsolicited.c +++ b/src/gsmd/unsolicited.c @@ -5,14 +5,14 @@ #include #include +#include "gsmd.h" + #include #include #include +#include -#include "gsmd.h" -#include "usock.h" - -static struct gsmd_ucmd *build_event(u_int8_t type, u_int8_t subtype, u_int8_t len) +struct gsmd_ucmd *usock_build_event(u_int8_t type, u_int8_t subtype, u_int8_t len) { struct gsmd_ucmd *ucmd = malloc(sizeof(*ucmd)+len); @@ -38,7 +38,7 @@ static struct gsmd_ucmd *ucmd_copy(const struct gsmd_ucmd *orig) return copy; } -static int usock_evt_send(struct gsmd *gsmd, struct gsmd_ucmd *ucmd, u_int32_t evt) +int usock_evt_send(struct gsmd *gsmd, struct gsmd_ucmd *ucmd, u_int32_t evt) { struct gsmd_user *gu; int num_sent = 0; @@ -65,7 +65,7 @@ static int ring_parse(char *buf, int len, const char *param, struct gsmd *gsmd) { /* FIXME: generate ring event */ - struct gsmd_ucmd *ucmd = build_event(GSMD_MSG_EVENT, GSMD_EVT_IN_CALL, + struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_IN_CALL, sizeof(struct gsmd_evt_auxdata)); struct gsmd_evt_auxdata *aux; if (!ucmd) @@ -80,7 +80,7 @@ static int ring_parse(char *buf, int len, const char *param, static int cring_parse(char *buf, int len, const char *param, struct gsmd *gsmd) { - struct gsmd_ucmd *ucmd = build_event(GSMD_MSG_EVENT, GSMD_EVT_IN_CALL, + struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_IN_CALL, sizeof(struct gsmd_evt_auxdata)); struct gsmd_evt_auxdata *aux; if (!ucmd) @@ -114,7 +114,7 @@ static int creg_parse(char *buf, int len, const char *param, struct gsmd *gsmd) { const char *comma = strchr(param, ','); - struct gsmd_ucmd *ucmd = build_event(GSMD_MSG_EVENT, GSMD_EVT_NETREG, + struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_NETREG, sizeof(struct gsmd_evt_auxdata)); struct gsmd_evt_auxdata *aux; if (!ucmd) @@ -124,11 +124,11 @@ static int creg_parse(char *buf, int len, const char *param, aux->u.netreg.state = atoi(param); if (comma) { /* we also have location area code and cell id to parse (hex) */ - aux->u.netreg.lac = atoi(comma+1); + aux->u.netreg.lac = strtoul(comma+2, NULL, 16); comma = strchr(comma+1, ','); if (!comma) return -EINVAL; - aux->u.netreg.ci = atoi(comma+1); + aux->u.netreg.ci = strtoul(comma+2, NULL, 16); } return usock_evt_send(gsmd, ucmd, GSMD_EVT_NETREG); @@ -140,7 +140,7 @@ static int ccwa_parse(char *buf, int len, const char *param, { const char *token; unsigned int type; - struct gsmd_ucmd *ucmd = build_event(GSMD_MSG_EVENT, GSMD_EVT_CALL_WAIT, + struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_CALL_WAIT, sizeof(struct gsmd_addr)); struct gsmd_addr *gaddr; @@ -205,7 +205,7 @@ static int cgreg_parse(char *buf, int len, const char *param, static int clip_parse(char *buf, int len, const char *param, struct gsmd *gsmd) { - struct gsmd_ucmd *ucmd = build_event(GSMD_MSG_EVENT, GSMD_EVT_IN_CLIP, + struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_IN_CLIP, sizeof(struct gsmd_evt_auxdata)); struct gsmd_evt_auxdata *aux; const char *comma = strchr(param, ','); @@ -232,7 +232,7 @@ static int clip_parse(char *buf, int len, const char *param, static int colp_parse(char *buf, int len, const char *param, struct gsmd *gsmd) { - struct gsmd_ucmd *ucmd = build_event(GSMD_MSG_EVENT, GSMD_EVT_OUT_COLP, + struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_OUT_COLP, sizeof(struct gsmd_evt_auxdata)); struct gsmd_evt_auxdata *aux; const char *comma = strchr(param, ','); @@ -257,7 +257,7 @@ static int colp_parse(char *buf, int len, const char *param, static int ctzv_parse(char *buf, int len, const char *param, struct gsmd *gsmd) { - struct gsmd_ucmd *ucmd = build_event(GSMD_MSG_EVENT, GSMD_EVT_TIMEZONE, + struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_TIMEZONE, sizeof(struct gsmd_evt_auxdata)); struct gsmd_evt_auxdata *aux; int tz; @@ -278,11 +278,6 @@ static int ctzv_parse(char *buf, int len, const char *param, return usock_evt_send(gsmd, ucmd, GSMD_EVT_TIMEZONE); } -struct gsmd_unsolicit { - const char *prefix; - int (*parse)(char *unsol, int len, const char *param, struct gsmd *gsmd); -}; - static const struct gsmd_unsolicit gsm0707_unsolicit[] = { { "RING", &ring_parse }, { "+CRING", &cring_parse }, @@ -310,7 +305,29 @@ static const struct gsmd_unsolicit gsm0707_unsolicit[] = { int unsolicited_parse(struct gsmd *g, char *buf, int len, const char *param) { int i, rc; + struct gsmd_vendor_plugin *vpl = g->vendorpl; + + /* call vendor-specific unsolicited code parser */ + if (vpl && vpl->num_unsolicit) { + for (i = 0; i < vpl->num_unsolicit; i++) { + const char *colon; + if (strncmp(buf, vpl->unsolicit[i].prefix, + strlen(vpl->unsolicit[i].prefix))) + continue; + + colon = strchr(buf, ':') + 2; + if (colon > buf+len) + colon = NULL; + + rc = vpl->unsolicit[i].parse(buf, len, colon, g); + if (rc < 0) + gsmd_log(GSMD_ERROR, "error %d during parse of " + "unsolicied response `%s'\n", rc, buf); + return rc; + } + } + /* call generic unsolicited code parser */ for (i = 0; i < ARRAY_SIZE(gsm0707_unsolicit); i++) { const char *colon; if (strncmp(buf, gsm0707_unsolicit[i].prefix, @@ -328,7 +345,6 @@ int unsolicited_parse(struct gsmd *g, char *buf, int len, const char *param) return rc; } - /* FIXME: call vendor-specific unsolicited code parser */ gsmd_log(GSMD_NOTICE, "no parser for unsolicited response `%s'\n", buf); return -ENOENT; @@ -382,7 +398,7 @@ int generate_event_from_cme(struct gsmd *g, unsigned int cme_error) ARRAY_SIZE(errors_creating_events))) return 0; - gu = build_event(GSMD_MSG_EVENT, GSMD_EVT_PIN, sizeof(*eaux)); + gu = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_PIN, sizeof(*eaux)); if (!gu) return -1; eaux = ((void *)gu) + sizeof(*gu); diff --git a/src/gsmd/unsolicited.h b/src/gsmd/unsolicited.h deleted file mode 100644 index fb99e1b..0000000 --- a/src/gsmd/unsolicited.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef __GSMD_UNSOLICITED_H -#define __GSMD_UNSOLICITED_H - -#include "gsmd.h" - -int unsolicited_parse(struct gsmd *g, const char *buf, int len, const char *param); -int generate_event_from_cme(struct gsmd *g, unsigned int cme_error); - -#endif diff --git a/src/gsmd/usock.c b/src/gsmd/usock.c index 76be1aa..42f8099 100644 --- a/src/gsmd/usock.c +++ b/src/gsmd/usock.c @@ -7,13 +7,13 @@ #include #include +#include "gsmd.h" + #include #include - -#include "gsmd.h" -#include "select.h" -#include "atcmd.h" -#include "usock.h" +#include +#include +#include void usock_cmd_enqueue(struct gsmd_ucmd *ucmd, struct gsmd_user *gu) { @@ -169,16 +169,123 @@ static int usock_rcv_phone(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, return atcmd_submit(gu->gsmd, cmd); } +static int network_vmail_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) +{ + struct gsmd_user *gu = ctx; + struct gsmd_voicemail *vmail; + struct gsmd_ucmd *ucmd = malloc(sizeof(*ucmd)+sizeof(*vmail)); + char *comma; + + DEBUGP("entering(cmd=%p, gu=%p)\n", cmd, gu); + + if (!ucmd) + return -ENOMEM; + + /* FIXME: pass error values back somehow */ + ucmd->hdr.version = GSMD_PROTO_VERSION; + ucmd->hdr.msg_type = GSMD_MSG_NETWORK; + ucmd->hdr.len = sizeof(*vmail); + ucmd->hdr.id = cmd->id; + + if (cmd->buf[7] == '=') { + /* response to set command */ + ucmd->hdr.msg_subtype = GSMD_NETWORK_VMAIL_SET; + /* FIXME: */ + return 0; + } else { + /* response to get command */ + char *tok = strtok(resp, ","); + if (!tok) + goto out_free_einval; + ucmd->hdr.msg_subtype = GSMD_NETWORK_VMAIL_GET; + vmail->enable = atoi(tok); + + tok = strtok(NULL, ","); + if (!tok) + goto out_free_einval; + strncpy(vmail->addr.number, tok, GSMD_ADDR_MAXLEN); + vmail->addr.number[GSMD_ADDR_MAXLEN] = '\0'; + + tok = strtok(NULL, ","); + if (!tok) + goto out_free_einval; + vmail->addr.type = atoi(tok); + } + + usock_cmd_enqueue(ucmd, gu); + + return 0; + +out_free_einval: + gsmd_log(GSMD_ERROR, "can't understand voicemail response\n"); + free(ucmd); + return -EINVAL; +} + +static struct gsmd_ucmd *gsmd_ucmd_fill(int len, u_int8_t msg_type, u_int8_t msg_subtype, + u_int16_t id) +{ + struct gsmd_ucmd *ucmd; + + ucmd = malloc(sizeof(*ucmd)+len); + if (!ucmd) + return NULL; + + ucmd->hdr.version = GSMD_PROTO_VERSION; + ucmd->hdr.msg_type = msg_type; + ucmd->hdr.msg_subtype = msg_subtype; + ucmd->hdr.len = len; + ucmd->hdr.id = id; + + return ucmd; +} + +static int network_sigq_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) +{ + struct gsmd_user *gu = ctx; + struct gsmd_signal_quality *gsq; + struct gsmd_ucmd *ucmd; + char *comma; + + ucmd = gsmd_ucmd_fill(sizeof(*gsq), GSMD_MSG_NETWORK, + GSMD_NETWORK_SIGQ_GET, 0); + if (!ucmd) + return -ENOMEM; + + gsq = (struct gsmd_signal_quality *) ucmd->buf; + gsq->rssi = atoi(resp); + comma = strchr(resp, ','); + if (!comma) { + free(ucmd); + return -EIO; + } + gsq->ber = atoi(comma+1); + + usock_cmd_enqueue(ucmd, gu); + + return 0; +} + static int usock_rcv_network(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, int len) { struct gsmd_atcmd *cmd; + struct gsmd_voicemail *vmail = (struct gsmd_voicemail *) gph->data; switch (gph->msg_subtype) { case GSMD_NETWORK_REGISTER: cmd = atcmd_fill("AT+COPS", 9+1, &null_cmd_cb, gu, 0); break; + case GSMD_NETWORK_VMAIL_GET: + cmd = atcmd_fill("AT+CSVM?", 8+1, &network_vmail_cb, gu, 0); + break; + case GSMD_NETWORK_VMAIL_SET: + cmd = atcmd_fill("AT+CSVM=", 8+1, &network_vmail_cb, gu, 0); + break; + case GSMD_NETWORK_SIGQ_GET: + cmd = atcmd_fill("AT+CSQ", 6+1, &network_sigq_cb, gu, 0); + break; default: return -EINVAL; } diff --git a/src/gsmd/usock.h b/src/gsmd/usock.h deleted file mode 100644 index efa0f34..0000000 --- a/src/gsmd/usock.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef __GSMD_USOCK_H -#define __GSMD_USOCK_H - -#include - -struct gsmd_ucmd { - struct llist_head list; - struct gsmd_msg_hdr hdr; - char buf[]; -} __attribute__ ((packed)); - -extern int usock_init(struct gsmd *g); -extern void usock_cmd_enqueue(struct gsmd_ucmd *ucmd, struct gsmd_user *gu); - -#endif - diff --git a/src/gsmd/vendor.c b/src/gsmd/vendor.c new file mode 100644 index 0000000..d577e98 --- /dev/null +++ b/src/gsmd/vendor.c @@ -0,0 +1,39 @@ +#include + +#include + +#include "gsmd.h" + +#include +#include + +static LLIST_HEAD(vendorpl_list); + +int gsmd_vendor_plugin_register(struct gsmd_vendor_plugin *pl) +{ + llist_add(&pl->list, &vendorpl_list); + + return 0; +} + +void gsmd_vendor_plugin_unregister(struct gsmd_vendor_plugin *pl) +{ + llist_del(&pl->list); +} + +int gsmd_vendor_plugin_find(struct gsmd *g) +{ + struct gsmd_vendor_plugin *pl; + + if (g->vendorpl) + return -EEXIST; + + llist_for_each_entry(pl, &vendorpl_list, list) { + if (pl->detect(g) == 1) { + g->vendorpl = pl; + return 1; + } + } + + return 0; +} diff --git a/src/gsmd/vendor_ti.c b/src/gsmd/vendor_ti.c index ac67b92..53ca7ed 100644 --- a/src/gsmd/vendor_ti.c +++ b/src/gsmd/vendor_ti.c @@ -5,6 +5,15 @@ #include #include +#include "gsmd.h" + +#include +#include +#include +#include +#include + +#if 0 #include "vendorplugin.h" static int @@ -31,8 +40,60 @@ ti_setopt(struct gsmd *gh, int optname, const void *optval, int optlen) } } -static int ti_parseunsolicit(struct gsmd *gh) +#endif + + +static int csq_parse(char *buf, int len, char *param, + struct gsmd *gsmd) +{ + char *tok; + struct gsmd_evt_auxdata *aux; + struct gsmd_ucmd *ucmd = usock_build_event(GSMD_MSG_EVENT, GSMD_EVT_SIGNAL, + sizeof(*aux)); + + DEBUGP("entering csq_parse param=`%s'\n", param); + if (!ucmd) + return -EINVAL; + + + aux = (struct gsmd_evt_auxdata *) ucmd->buf; + tok = strtok(param, ","); + if (!tok) + goto out_free_io; + + aux->u.signal.sigq.rssi = atoi(tok); + + tok = strtok(NULL, ","); + if (!tok) + goto out_free_io; + + aux->u.signal.sigq.ber = atoi(tok); + + DEBUGP("sending EVT_SIGNAL\n"); + usock_evt_send(gsmd, ucmd, GSMD_EVT_SIGNAL); + + return 0; + +out_free_io: + free(ucmd); + return -EIO; +} + +static int cpri_parse(char *buf, int len, const char *param, struct gsmd *gsmd) +{ + +} + +static int cpi_parse(char *buf, int len, const char *param, struct gsmd *gsmd) { + +} + +static const struct gsmd_unsolicit ticalypso_unsolicit[] = { + { "\%CSQ", &csq_parse }, /* Signal Quality */ + { "\%CPRI", &cpri_parse }, /* Ciphering Indication */ + { "\%CPI", &cpi_parse }, /* Call Progress Information */ + /* FIXME: parse all the below and generate the respective events */ /* %CPROAM: CPHS Home Country Roaming Indicator */ @@ -43,11 +104,29 @@ static int ti_parseunsolicit(struct gsmd *gh) /* %CPKY: Press Key */ /* %CMGRS: Message Retransmission Service */ /* %CGEV: reports GPRS network events */ - return -EINVAL; +}; + +static int ticalypso_detect(struct gsmd *g) +{ + /* FIXME: do actual detection of vendor if we have multiple vendors */ + return 1; } -struct gsmd_vendorspecific ti_vendorspec = { - .getopt = &ti_getopt, - .setopt = &ti_setopt, - .parse_unsolicit = &ti_parseunsolicit, +static int ticalypso_initsettings(struct gsmd *g) +{ + return gsmd_simplecmd(g, "AT\%CPI=3;\%CPRI=1;\%CSQ=1"); +} + +static struct gsmd_vendor_plugin plugin_ticalypso = { + .name = "TI Calypso", + .num_unsolicit = ARRAY_SIZE(ticalypso_unsolicit), + .unsolicit = &ticalypso_unsolicit, + .detect = &ticalypso_detect, + .initsettings = &ticalypso_initsettings, }; + +/* FIXME: this will be _init() when we make this a plugin */ +int ticalypso_init(void) +{ + return gsmd_vendor_plugin_register(&plugin_ticalypso); +} diff --git a/src/gsmd/vendorplugin.h b/src/gsmd/vendorplugin.h index b8be9ba..62546ba 100644 --- a/src/gsmd/vendorplugin.h +++ b/src/gsmd/vendorplugin.h @@ -1,6 +1,8 @@ #ifndef __GSMD_VENDORPLUG_H #define __GSMD_VENDORPLUG_H +#ifdef __GSMD__ + #include "gsmd.h" /* gsmd vendor-specific plugin */ @@ -26,4 +28,6 @@ struct gsmd_vendorspecific { /* ciphering indications */ +#endif /* __GSMD__ */ + #endif diff --git a/src/libgsmd/libgsmd.c b/src/libgsmd/libgsmd.c index 7f936e8..8dde4b6 100644 --- a/src/libgsmd/libgsmd.c +++ b/src/libgsmd/libgsmd.c @@ -82,9 +82,11 @@ int lgsm_handle_packet(struct lgsm_handle *lh, char *buf, int len) handler = lh->handler[gmh->msg_type]; if (handler) - handler(lh, gmh); - else + return handler(lh, gmh); + else { fprintf(stderr, "unable to handle packet type=%u\n", gmh->msg_type); + return 0; + } } int lgsm_register_handler(struct lgsm_handle *lh, int type, lgsm_msg_handler *handler) diff --git a/src/libgsmd/libgsmd_network.c b/src/libgsmd/libgsmd_network.c index ae104b8..73bc895 100644 --- a/src/libgsmd/libgsmd_network.c +++ b/src/libgsmd/libgsmd_network.c @@ -16,3 +16,7 @@ int lgsm_netreg_register(struct lgsm_handle *lh, int oper) return lgsm_send_simple(lh, GSMD_MSG_NETWORK, GSMD_NETWORK_REGISTER); } +int lgsm_signal_quality(struct lgsm_handle *lh) +{ + return lgsm_send_simple(lh, GSMD_MSG_NETWORK, GSMD_NETWORK_SIGQ_GET); +} diff --git a/src/util/atcmd.c b/src/util/atcmd.c index 6cf9aa7..61f7032 100644 --- a/src/util/atcmd.c +++ b/src/util/atcmd.c @@ -44,6 +44,8 @@ int atcmd_main(struct lgsm_handle *lgsmh) break; } rc = lgsm_handle_packet(lgsmh, buf, rc); + if (rc < 0) + printf("ERROR processing packet: %d(%s)\n", rc, strerror(rc)); } if (FD_ISSET(0, &readset)) { /* we've received something on stdin. send it as passthrough diff --git a/src/util/event.c b/src/util/event.c index 0f09d47..bff895d 100644 --- a/src/util/event.c +++ b/src/util/event.c @@ -6,14 +6,14 @@ static int incall_handler(struct lgsm_handle *lh, int evt, struct gsmd_evt_auxdata *aux) { - printf("EVENT: Incoming call type=%u!\n", aux->u.call.type); + printf("EVENT: Incoming call type = %u\n", aux->u.call.type); return 0; } static int clip_handler(struct lgsm_handle *lh, int evt, struct gsmd_evt_auxdata *aux) { - printf("EVENT: Incoming call clip=`%s'\n", aux->u.clip.addr.number); + printf("EVENT: Incoming call clip = %s\n", aux->u.clip.addr.number); return 0; } @@ -41,15 +41,21 @@ static int netreg_handler(struct lgsm_handle *lh, int evt, struct gsmd_evt_auxda } if (aux->u.netreg.lac) - printf("LocationAreaCode=0x%04X ", aux->u.netreg.lac); + printf("LocationAreaCode = 0x%04X ", aux->u.netreg.lac); if (aux->u.netreg.ci) - printf("CellID=0x%04X ", aux->u.netreg.ci); + printf("CellID = 0x%04X ", aux->u.netreg.ci); printf("\n"); return 0; } +static int sigq_handler(struct lgsm_handle *lh, int evt, struct gsmd_evt_auxdata *aux) +{ + printf("EVENT: Signal Quality: %u\n", aux->u.signal.sigq.rssi); + return 0; +} + int event_init(struct lgsm_handle *lh) { int rc; @@ -57,6 +63,7 @@ int event_init(struct lgsm_handle *lh) rc = lgsm_evt_handler_register(lh, GSMD_EVT_IN_CALL, &incall_handler); rc |= lgsm_evt_handler_register(lh, GSMD_EVT_IN_CLIP, &clip_handler); rc |= lgsm_evt_handler_register(lh, GSMD_EVT_NETREG, &netreg_handler); + rc |= lgsm_evt_handler_register(lh, GSMD_EVT_SIGNAL, &sigq_handler); return rc; } -- cgit v1.2.3