From 2aa67b809f5b06fb86a6f8dfc556bfb7c9169729 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 13 Oct 2013 18:22:44 +0200 Subject: wavecom/sysmocom: use AT@COPS if available, instead of AT+COPS In certain sysmocom proprietary versions of the wavecom modem, we have a non-blocking operator scan command called AT@COPS=?, which we can use instead of AT+COPS=?. The wavecom vendor plugin checks at start time if the command is available. If yes, iti s used in case a libgsm client is asking for an operator scan, instead of the standard AT+COPS=? variant. --- include/gsmd/vendorplugin.h | 8 ++++++++ src/gsmd/usock.c | 16 ++++++++++++++-- src/gsmd/vendor_wavecom.c | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/include/gsmd/vendorplugin.h b/include/gsmd/vendorplugin.h index 8669bb7..d4c8b29 100644 --- a/include/gsmd/vendorplugin.h +++ b/include/gsmd/vendorplugin.h @@ -24,6 +24,14 @@ 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); +/* should we use AT@COPS=? instead of AT+COPS=? */ +extern int g_use_ATatCOPS; +/* the last user that requested an AT@COPS=? scan */ +extern struct gsmd_user *g_last_cops_user; +extern int g_last_cops_id; +struct gsmd_atcmd; +int network_opers_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp); + #endif /* __GSMD__ */ #endif diff --git a/src/gsmd/usock.c b/src/gsmd/usock.c index 41814c8..157a874 100644 --- a/src/gsmd/usock.c +++ b/src/gsmd/usock.c @@ -1062,7 +1062,14 @@ static int network_opers_parse(const char *str, struct gsmd_msg_oper **out) return len; } -static int network_opers_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) +/* should we use AT@COPS=? instead of AT+COPS=? */ +int g_use_ATatCOPS; + +/* the last user that requested an AT@COPS=? scan */ +struct gsmd_user *g_last_cops_user; +int g_last_cops_id; + +int network_opers_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) { struct gsmd_user *gu = ctx; struct gsmd_msg_oper *buf = NULL; @@ -1206,7 +1213,12 @@ static int usock_rcv_network(struct gsmd_user *gu, struct gsmd_msg_hdr *gph, cmd = atcmd_fill("AT+COPS?", 8+1, &network_oper_n_cb, gu, 0, NULL); break; case GSMD_NETWORK_OPER_LIST: - cmd = atcmd_fill("AT+COPS=?", 9+1, &network_opers_cb, gu, 0, NULL); + if (g_use_ATatCOPS) { + g_last_cops_user = gu; + g_last_cops_id = cmd->id; + cmd = atcmd_fill("AT@COPS=?", 9+1, &network_opers_cb, gu, 0, NULL); + } else + cmd = atcmd_fill("AT+COPS=?", 9+1, &network_opers_cb, gu, 0, NULL); break; case GSMD_NETWORK_PREF_LIST: /* Set long alphanumeric format */ diff --git a/src/gsmd/vendor_wavecom.c b/src/gsmd/vendor_wavecom.c index b1b6929..dc309ab 100644 --- a/src/gsmd/vendor_wavecom.c +++ b/src/gsmd/vendor_wavecom.c @@ -213,10 +213,34 @@ static int sais_parse(const char *buf, int len, const char *param, return 0; }; +static int cops_parse(const char *buf, int len, const char *param, + struct gsmd *gsmd) +{ + struct gsmd_atcmd fake_atcmd; + + if (!g_use_ATatCOPS) + return 0; + + if (!strcmp(buf, "+COPS: ERROR\r\n")) + return 0; + + if (!g_use_ATatCOPS || !g_last_cops_user) + return 0; + + fake_atcmd.id = g_last_cops_id; + + network_opers_cb(&fake_atcmd, g_last_cops_user, buf); + + return 0; +}; + + static const struct gsmd_unsolicit wavecom_unsolicit[] = { { "+CCED", &cced_parse }, /* Cell Environment Report */ { "+SYSMOCOM_GPS", &sgps_parse }, { "+SYSMOCOM_AIS", &sais_parse }, + /* proprietary non-blocking response to AT@COPS=? */ + { "+COPS", &cops_parse }, }; static int wavecom_detect(struct gsmd *g) @@ -225,6 +249,15 @@ static int wavecom_detect(struct gsmd *g) return 1; } +static int at_atcops_cb(struct gsmd_atcmd *cmd, void *ctx, char *resp) +{ + /* if the result is successful, at@cops is supported */ + if (cmd->ret == 0) + g_use_ATatCOPS = 1; + + return 0; +} + static int wavecom_initsettings(struct gsmd *g) { int rc = 0; @@ -255,6 +288,9 @@ static int wavecom_initsettings(struct gsmd *g) rc |= gsmd_simplecmd(g, "AT+WREGC=0"); rc |= gsmd_simplecmd(g, "AT+CCED=1,3"); + cmd = atcmd_fill("AT@COPS=?", 9+1, &at_atcops_cb, NULL, 0, NULL); + rc |= atcmd_submit(g, cmd); + return rc; } -- cgit v1.2.3