From 3026b93e266558671bd361b6c07546f8174974bc Mon Sep 17 00:00:00 2001 From: laforge Date: Sat, 10 Mar 2007 22:05:17 +0000 Subject: * include stdio from talloc.h * add new generic extended-response parser * add operator cache, using ext-resp-parser * add proper detection of supported %CPI modes and select highest available one * add %CTZV to vendor_ti init string git-svn-id: http://svn.openmoko.org/trunk/src/target/gsm@1316 99fdad57-331a-0410-800a-d7fa5415bdb3 --- src/gsmd/Makefile.am | 2 +- src/gsmd/ext_response.c | 213 ++++++++++++++++++++++++++++++++++++++++++++++ src/gsmd/gsmd.c | 2 + src/gsmd/operator_cache.c | 99 +++++++++++++++++++++ src/gsmd/unsolicited.c | 24 ++++++ src/gsmd/vendor_ti.c | 44 ++++++++-- 6 files changed, 377 insertions(+), 7 deletions(-) create mode 100644 src/gsmd/ext_response.c create mode 100644 src/gsmd/operator_cache.c (limited to 'src') diff --git a/src/gsmd/Makefile.am b/src/gsmd/Makefile.am index b431ec5..940f610 100644 --- a/src/gsmd/Makefile.am +++ b/src/gsmd/Makefile.am @@ -4,7 +4,7 @@ AM_CFLAGS = -std=gnu99 sbin_PROGRAMS = gsmd gsmd_SOURCES = gsmd.c atcmd.c select.c vendor.c usock.c unsolicited.c log.c \ - vendor_ti.c talloc.c + vendor_ti.c talloc.c operator_cache.c ext_response.c #gsmd_LDADD = ../libgsmd/libgsmd.la #gsmd_LDFLAGS = -dynamic diff --git a/src/gsmd/ext_response.c b/src/gsmd/ext_response.c new file mode 100644 index 0000000..5b31c8d --- /dev/null +++ b/src/gsmd/ext_response.c @@ -0,0 +1,213 @@ +/* gsmd extended response parser + * + * (C) 2007 by OpenMoko, Inc. + * Written by Harald Welte + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "gsmd.h" + +#include +#include +#include +#include + +int extrsp_supports(const struct gsm_extrsp *er, int index, int value) +{ + int i; + + if (index >= er->num_tokens) + return -EINVAL; + if (er->tokens[index].type != GSMD_ECMD_RTT_RANGE) + return -EINVAL; + + for (i = 0; i < er->tokens[index].u.range.num_items; i++) { + struct gsm_extrsp_range_item *ri = + &er->tokens[index].u.range.item[i]; + if (value >= ri->min && value <= ri->max) + return 1; + } + + return 0; +} + +enum parser_state { + IDLE, + TOKEN_STRING, + TOKEN_STRING_LASTQUOTE, + TOKEN_NUMERIC, + TOKEN_RANGE, +}; + +/* parse a comma-separated list, possibly containing quote values */ +struct gsm_extrsp *extrsp_parse(const void *ctx, const char *input) +{ + const char *cur = input; + struct gsm_extrsp *er; + int cur_tok = 0; + enum parser_state state = IDLE; + char buf[512]; + char *cur_buf = buf; + struct gsm_extrsp_tok *cur_token; + + if (!input || strlen(input) == 0) + return NULL; + + er = talloc(ctx, struct gsm_extrsp); + if (!er) + return NULL; + memset(er, 0, sizeof(*er)); + + while (*cur) { + cur_token = &er->tokens[er->num_tokens]; + + switch (state) { + case IDLE: + memset(buf, 0, sizeof(buf)); + cur_buf = buf; + + if (isblank(*cur)) + break; + else if (*cur == '"') { + cur_token->type = GSMD_ECMD_RTT_STRING; + state = TOKEN_STRING; + } else if (*cur == '(') { + cur_token->type = GSMD_ECMD_RTT_RANGE; + state = TOKEN_RANGE; + } else if (isdigit(*cur)) { + cur_token->type = GSMD_ECMD_RTT_NUMERIC; + *cur_buf = *cur; + cur_buf++; + state = TOKEN_NUMERIC; + } else if (*cur == ',') { + cur_token->type = GSMD_ECMD_RTT_EMPTY; + er->num_tokens++; + state = IDLE; + } + break; + case TOKEN_NUMERIC: + if (*cur == ',') { + /* end of number */ + cur_token->u.numeric = atoi(buf); + er->num_tokens++; + state = IDLE; + } else if (isdigit(*cur)) { + *cur_buf = *cur; + cur_buf++; + } else { + /* ERORR */ + } + break; + case TOKEN_STRING: + if (*cur == '"') { + int len = strlen(buf); + if (len > sizeof(cur_token->u.string)-1) + len = sizeof(cur_token->u.string)-1; + + /* end of string token */ + strncpy(cur_token->u.string, buf, len); + er->num_tokens++; + state = TOKEN_STRING_LASTQUOTE; + } else { + *cur_buf = *cur; + cur_buf++; + } + break; + case TOKEN_STRING_LASTQUOTE: + if (*cur == ',') + state = IDLE; + else { + /* ERROR */ + } + break; + case TOKEN_RANGE: + if (isdigit(*cur)) { + *cur_buf = *cur; + cur_buf++; + } else if (*cur == '-') { + /* previous number has completed */ + cur_token->u.range.item[cur_token->u.range.num_items].min = atoi(buf); + memset(buf, 0, sizeof(buf)); + cur_buf = buf; + } else if (*cur == ',') { + /* previous number has completed */ + cur_token->u.range.item[cur_token->u.range.num_items].max = atoi(buf); + cur_token->u.range.num_items++; + } else if (*cur == ')') { + /* previous number has completed */ + cur_token->u.range.item[cur_token->u.range.num_items].max = atoi(buf); + cur_token->u.range.num_items++; + state = TOKEN_STRING_LASTQUOTE; + er->num_tokens++; + } else { + /* ERROR */ + } + break; + } + cur++; + } + + //extrsp_dump(er); + return er; +} + +static const char *er_tok_names[] = { + [GSMD_ECMD_RTT_EMPTY] = "EMPTY", + [GSMD_ECMD_RTT_NUMERIC] = "NUMERIC", + [GSMD_ECMD_RTT_STRING] = "STRING", + [GSMD_ECMD_RTT_RANGE] = "RANGE", +}; + +void extrsp_dump(const struct gsm_extrsp *er) +{ + int i; + + DEBUGP("entering(er=%p, num_tokens=%u)\n", er, er->num_tokens); + for (i = 0; i < er->num_tokens; i++) { + const struct gsm_extrsp_tok *tok = &er->tokens[i]; + DEBUGP("Token %u: %s: ", i, er_tok_names[tok->type]); + switch (tok->type) { + case GSMD_ECMD_RTT_EMPTY: + DEBUGP("\n"); + break; + case GSMD_ECMD_RTT_NUMERIC: + DEBUGP("%d\n", tok->u.numeric); + break; + case GSMD_ECMD_RTT_STRING: + DEBUGP("%s\n", tok->u.string); + break; + case GSMD_ECMD_RTT_RANGE: { + int j; + for (j = 0; j < tok->u.range.num_items; j++) + DEBUGP("%d-%d, ", tok->u.range.item[j].min, + tok->u.range.item[j].max); + } + + break; + } + } + +} diff --git a/src/gsmd/gsmd.c b/src/gsmd/gsmd.c index 6c72f97..8254ae0 100644 --- a/src/gsmd/gsmd.c +++ b/src/gsmd/gsmd.c @@ -282,6 +282,8 @@ int main(int argc, char **argv) gsmd_initsettings(&g); + gsmd_opname_init(&g); + while (1) { int ret = gsmd_select_main(); if (ret == 0) diff --git a/src/gsmd/operator_cache.c b/src/gsmd/operator_cache.c new file mode 100644 index 0000000..e680706 --- /dev/null +++ b/src/gsmd/operator_cache.c @@ -0,0 +1,99 @@ +/* gsmd cache of operator names + * + * (C) 2006-2007 by OpenMoko, Inc. + * Written by Harald Welte + * All Rights Reserved + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + */ + +#include +#include +#include +#include +#include + +#include "gsmd.h" + +#include +#include +#include + +static void *__opc_ctx; + +struct opname { + struct llist_head list; + struct { + u_int16_t mcc; /* mobile country code */ + u_int8_t mnc; /* mobile network code */ + } numeric; + char alnum_long[16+1]; + //char alnum_short[8+1]; +}; + +/* add an entry to the operator name list, overwrite existing entries for + * same mcc/mnc */ +static int _opname_add(struct gsmd *g, struct opname *op) +{ + struct opname *cur, *cur2; + + llist_for_each_entry_safe(cur, cur2, &g->operators, list) { + if (op->numeric.mcc == cur->numeric.mcc && + op->numeric.mnc == cur->numeric.mnc) { + llist_del(&cur->list); + talloc_free(cur); + } + } + llist_add_tail(&op->list, &g->operators); + + return 0; +} + +int gsmd_opname_add(struct gsmd *g, const char *numeric_bcd_string, + const char *alnum_long) +{ + struct opname *op; + char mcc[3+1]; + char mnc[2+1]; + + if (strlen(numeric_bcd_string) != 5) + return -EINVAL; + + op = talloc(__opc_ctx, struct opname); + if (!op) + return -ENOMEM; + + memset(mcc, 0, sizeof(mcc)); + memset(mnc, 0, sizeof(mnc)); + + strncpy(mcc, numeric_bcd_string, 3); + strncpy(mnc, numeric_bcd_string+3, 2); + + strncpy(op->alnum_long, alnum_long, sizeof(op->alnum_long-1)); + op->numeric.mcc = atoi(mcc); + op->numeric.mnc = atoi(mnc); + + return _opname_add(g, op); +} + +int gsmd_opname_init(struct gsmd *g) +{ + INIT_LLIST_HEAD(&g->operators); + + __opc_ctx = talloc_named_const(gsmd_tallocs, 1, "operator_cache"); + + return 0; +} diff --git a/src/gsmd/unsolicited.c b/src/gsmd/unsolicited.c index 82f45f4..c355c71 100644 --- a/src/gsmd/unsolicited.c +++ b/src/gsmd/unsolicited.c @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -308,6 +309,28 @@ static int ctzv_parse(char *buf, int len, const char *param, return usock_evt_send(gsmd, ucmd, GSMD_EVT_TIMEZONE); } +static int copn_parse(char *buf, int len, const char *param, + struct gsmd *gsmd) +{ + struct gsm_extrsp *er = extrsp_parse(gsmd_tallocs, param); + int rc = 0; + + if (!er) + return -ENOMEM; + + extrsp_dump(er); + + if (er->num_tokens == 2 && + er->tokens[0].type == GSMD_ECMD_RTT_STRING && + er->tokens[1].type == GSMD_ECMD_RTT_STRING) + rc = gsmd_opname_add(gsmd, er->tokens[0].u.string, + er->tokens[1].u.string); + + talloc_free(er); + + return rc; +} + static const struct gsmd_unsolicit gsm0707_unsolicit[] = { { "RING", &ring_parse }, { "+CRING", &cring_parse }, @@ -320,6 +343,7 @@ static const struct gsmd_unsolicit gsm0707_unsolicit[] = { { "+CLIP", &clip_parse }, { "+COLP", &colp_parse }, { "+CTZV", &ctzv_parse }, /* Timezone */ + { "+COPN", &copn_parse }, /* operator names, treat as unsolicited */ /* { "+CKEV", &ckev_parse }, { "+CDEV", &cdev_parse }, diff --git a/src/gsmd/vendor_ti.c b/src/gsmd/vendor_ti.c index 6617edf..0cc0783 100644 --- a/src/gsmd/vendor_ti.c +++ b/src/gsmd/vendor_ti.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "gsmd.h" @@ -30,6 +31,9 @@ #include #include #include +#include +#include +#include #include #include @@ -214,7 +218,7 @@ out_send: return 0; out_free_io: - free(ucmd); + talloc_free(ucmd); return -EIO; } @@ -237,7 +241,26 @@ static const struct gsmd_unsolicit ticalypso_unsolicit[] = { static int cpi_detect_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) { + struct gsmd *g = ctx; + struct gsm_extrsp *er; + + if (strncmp(resp, "%CPI: ", 6)) + return -EINVAL; + resp += 6; + er = extrsp_parse(cmd, resp); + if (!er) + return -EINVAL; + + if (extrsp_supports(er, 0, 3)) + return gsmd_simplecmd(g, "AT%CPI=3"); + else if (extrsp_supports(er, 0, 2)) + return gsmd_simplecmd(g, "AT%CPI=2"); + else + DEBUGP("Call Progress Indication mode 2 or 3 not supported!!\n"); + + talloc_free(er); + return 0; } static int ticalypso_detect(struct gsmd *g) @@ -249,16 +272,25 @@ static int ticalypso_detect(struct gsmd *g) static int ticalypso_initsettings(struct gsmd *g) { int rc; + struct gsmd_atcmd *cmd; + /* use +CTZR: to report time zone changes */ rc |= gsmd_simplecmd(g, "AT+CTZR=1"); - /* enable %CPI: call progress indication */ - rc = gsmd_simplecmd(g, "AT\%CPI=3"); + /* use %CTZV: Report time and date */ + rc |= gsmd_simplecmd(g, "AT%CTZV=1"); + /* use %CGREG */ + //rc |= gsmd_simplecmd(g, "AT%CGREG=3"); /* enable %CPRI: ciphering indications */ - rc |= gsmd_simplecmd(g, "AT\%CPRI=1"); + rc |= gsmd_simplecmd(g, "AT%CPRI=1"); /* enable %CSQ: signal quality reports */ - rc |= gsmd_simplecmd(g, "AT\%CSQ=1"); + rc |= gsmd_simplecmd(g, "AT%CSQ=1"); /* send unsolicited commands at any time */ - rc |= gsmd_simplecmd(g, "AT\%CUNS=0"); + rc |= gsmd_simplecmd(g, "AT%CUNS=0"); + + /* enable %CPI: call progress indication */ + cmd = atcmd_fill("AT%CPI=?", 9, &cpi_detect_cb, g, 0); + if (cmd) + atcmd_submit(g, cmd); return rc; } -- cgit v1.2.3