r1316 - in trunk/src/target/gsm: include/gsmd src/gsmd

laforge at sita.openmoko.org laforge at sita.openmoko.org
Sat Mar 10 23:05:19 CET 2007


Author: laforge
Date: 2007-03-10 23:05:17 +0100 (Sat, 10 Mar 2007)
New Revision: 1316

Added:
   trunk/src/target/gsm/include/gsmd/extrsp.h
   trunk/src/target/gsm/src/gsmd/ext_response.c
   trunk/src/target/gsm/src/gsmd/operator_cache.c
Modified:
   trunk/src/target/gsm/include/gsmd/gsmd.h
   trunk/src/target/gsm/include/gsmd/talloc.h
   trunk/src/target/gsm/src/gsmd/Makefile.am
   trunk/src/target/gsm/src/gsmd/gsmd.c
   trunk/src/target/gsm/src/gsmd/unsolicited.c
   trunk/src/target/gsm/src/gsmd/vendor_ti.c
Log:
* 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


Added: trunk/src/target/gsm/include/gsmd/extrsp.h
===================================================================
--- trunk/src/target/gsm/include/gsmd/extrsp.h	2007-03-10 16:19:10 UTC (rev 1315)
+++ trunk/src/target/gsm/include/gsmd/extrsp.h	2007-03-10 22:05:17 UTC (rev 1316)
@@ -0,0 +1,45 @@
+#ifndef _GSMD_EXTRSP_H
+#define _GSMD_EXTRSP_H
+
+/* how many tokens (CSV items) can an extended response have, max */
+#define GSM_EXTRSP_MAX_TOKENS	16
+
+/* how many individual sub-ranges can one range contain */
+#define GSM_EXTRSP_MAX_RANGES	16
+
+
+struct gsm_extrsp_range_item {
+	int min;
+	int max;
+};
+
+enum gsm_extrsp_tok_type {
+	GSMD_ECMD_RTT_NONE,
+	GSMD_ECMD_RTT_EMPTY,
+	GSMD_ECMD_RTT_NUMERIC,
+	GSMD_ECMD_RTT_STRING,
+	GSMD_ECMD_RTT_RANGE,
+};
+
+struct gsm_extrsp_tok {
+	enum gsm_extrsp_tok_type type;
+	union {
+		struct {
+			struct gsm_extrsp_range_item item[GSM_EXTRSP_MAX_RANGES];
+			int num_items;
+		} range;
+		char string[64];
+		int numeric;
+	} u;
+};
+
+struct gsm_extrsp {
+	unsigned int num_tokens;
+	struct gsm_extrsp_tok tokens[GSM_EXTRSP_MAX_TOKENS];
+};
+
+extern int extrsp_supports(const struct gsm_extrsp *er, int index, int value);
+extern struct gsm_extrsp *extrsp_parse(const void *ctx, const char *input);
+extern void extrsp_dump(const struct gsm_extrsp *er);
+
+#endif

Modified: trunk/src/target/gsm/include/gsmd/gsmd.h
===================================================================
--- trunk/src/target/gsm/include/gsmd/gsmd.h	2007-03-10 16:19:10 UTC (rev 1315)
+++ trunk/src/target/gsm/include/gsmd/gsmd.h	2007-03-10 22:05:17 UTC (rev 1316)
@@ -66,6 +66,8 @@
 	struct llist_head busy_atcmds;	/* our busy gsmd_atcmds */
 	struct gsmd_vendor_plugin *vendorpl;
 	struct gsmd_device_state dev_state;
+
+	struct llist_head operators;		/* cached list of operator names */
 };
 
 struct gsmd_user {

Modified: trunk/src/target/gsm/include/gsmd/talloc.h
===================================================================
--- trunk/src/target/gsm/include/gsmd/talloc.h	2007-03-10 16:19:10 UTC (rev 1315)
+++ trunk/src/target/gsm/include/gsmd/talloc.h	2007-03-10 22:05:17 UTC (rev 1316)
@@ -26,6 +26,7 @@
 
 /* nfsim additions */
 #include <stdarg.h>
+#include <stdio.h>
 
 /* this is only needed for compatibility with the old talloc */
 typedef void TALLOC_CTX;

Modified: trunk/src/target/gsm/src/gsmd/Makefile.am
===================================================================
--- trunk/src/target/gsm/src/gsmd/Makefile.am	2007-03-10 16:19:10 UTC (rev 1315)
+++ trunk/src/target/gsm/src/gsmd/Makefile.am	2007-03-10 22:05:17 UTC (rev 1316)
@@ -4,7 +4,7 @@
 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
 

Added: trunk/src/target/gsm/src/gsmd/ext_response.c
===================================================================
--- trunk/src/target/gsm/src/gsmd/ext_response.c	2007-03-10 16:19:10 UTC (rev 1315)
+++ trunk/src/target/gsm/src/gsmd/ext_response.c	2007-03-10 22:05:17 UTC (rev 1316)
@@ -0,0 +1,213 @@
+/* gsmd extended response parser
+ *
+ * (C) 2007 by OpenMoko, Inc.
+ * Written by Harald Welte <laforge at openmoko.org>
+ * 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 <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+
+#include "gsmd.h"
+
+#include <gsmd/gsmd.h>
+#include <gsmd/atcmd.h>
+#include <gsmd/extrsp.h>
+#include <gsmd/talloc.h>
+
+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;
+		}
+	}
+
+}

Modified: trunk/src/target/gsm/src/gsmd/gsmd.c
===================================================================
--- trunk/src/target/gsm/src/gsmd/gsmd.c	2007-03-10 16:19:10 UTC (rev 1315)
+++ trunk/src/target/gsm/src/gsmd/gsmd.c	2007-03-10 22:05:17 UTC (rev 1316)
@@ -282,6 +282,8 @@
 
 	gsmd_initsettings(&g);
 
+	gsmd_opname_init(&g);
+
 	while (1) {
 		int ret = gsmd_select_main();
 		if (ret == 0)

Added: trunk/src/target/gsm/src/gsmd/operator_cache.c
===================================================================
--- trunk/src/target/gsm/src/gsmd/operator_cache.c	2007-03-10 16:19:10 UTC (rev 1315)
+++ trunk/src/target/gsm/src/gsmd/operator_cache.c	2007-03-10 22:05:17 UTC (rev 1316)
@@ -0,0 +1,99 @@
+/* gsmd cache of operator names
+ *
+ * (C) 2006-2007 by OpenMoko, Inc.
+ * Written by Harald Welte <laforge at openmoko.org>
+ * 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 <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+#include "gsmd.h"
+
+#include <common/linux_list.h>
+#include <gsmd/gsmd.h>
+#include <gsmd/talloc.h>
+
+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;
+}

Modified: trunk/src/target/gsm/src/gsmd/unsolicited.c
===================================================================
--- trunk/src/target/gsm/src/gsmd/unsolicited.c	2007-03-10 16:19:10 UTC (rev 1315)
+++ trunk/src/target/gsm/src/gsmd/unsolicited.c	2007-03-10 22:05:17 UTC (rev 1316)
@@ -31,6 +31,7 @@
 
 #include <gsmd/usock.h>
 #include <gsmd/event.h>
+#include <gsmd/extrsp.h>
 #include <gsmd/ts0707.h>
 #include <gsmd/unsolicited.h>
 #include <gsmd/talloc.h>
@@ -308,6 +309,28 @@
 	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 @@
 	{ "+CLIP",	&clip_parse },
 	{ "+COLP",	&colp_parse },
 	{ "+CTZV",	&ctzv_parse },	/* Timezone */
+	{ "+COPN",	&copn_parse },  /* operator names, treat as unsolicited */
 	/*
 	{ "+CKEV",	&ckev_parse },
 	{ "+CDEV",	&cdev_parse },

Modified: trunk/src/target/gsm/src/gsmd/vendor_ti.c
===================================================================
--- trunk/src/target/gsm/src/gsmd/vendor_ti.c	2007-03-10 16:19:10 UTC (rev 1315)
+++ trunk/src/target/gsm/src/gsmd/vendor_ti.c	2007-03-10 22:05:17 UTC (rev 1316)
@@ -23,6 +23,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
+#include <stdio.h>
 #include <errno.h>
 
 #include "gsmd.h"
@@ -30,6 +31,9 @@
 #include <gsmd/gsmd.h>
 #include <gsmd/usock.h>
 #include <gsmd/event.h>
+#include <gsmd/talloc.h>
+#include <gsmd/extrsp.h>
+#include <gsmd/atcmd.h>
 #include <gsmd/vendorplugin.h>
 #include <gsmd/unsolicited.h>
 
@@ -214,7 +218,7 @@
 	return 0;
 
 out_free_io:
-	free(ucmd);
+	talloc_free(ucmd);
 	return -EIO;
 }
 
@@ -237,7 +241,26 @@
 
 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,17 +272,26 @@
 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;
 }
 





More information about the commitlog mailing list