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.
This commit is contained in:
Harald Welte 2013-10-13 18:22:44 +02:00
parent 58a9b679e9
commit 2aa67b809f
3 changed files with 58 additions and 2 deletions

View File

@ -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

View File

@ -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 */

View File

@ -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;
}