summaryrefslogtreecommitdiff
path: root/src/gsmd
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2013-10-13 18:22:44 +0200
committerHarald Welte <laforge@gnumonks.org>2013-10-13 18:22:44 +0200
commit2aa67b809f5b06fb86a6f8dfc556bfb7c9169729 (patch)
tree81aabb15f5635ebc4cf07806bd98345a20fd5675 /src/gsmd
parent58a9b679e9084f4a7061dc3d00a6a3177e2559fa (diff)
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.
Diffstat (limited to 'src/gsmd')
-rw-r--r--src/gsmd/usock.c16
-rw-r--r--src/gsmd/vendor_wavecom.c36
2 files changed, 50 insertions, 2 deletions
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;
}
personal git repositories of Harald Welte. Your mileage may vary