cinterion: query network technology capabilities

We try to look for 'psinfo' indication in AT^SIND? output (available in 3G
devices from Cinterion), and if that is not available, we try to use the
AT^SMONG GPRS monitor (available in 2G devices from Cinterion).
This commit is contained in:
Aleksander Morgado
2011-06-06 17:20:16 +02:00
parent c6060e8c0f
commit 795de12050
+205
View File
@@ -28,6 +28,14 @@
G_DEFINE_TYPE (MMModemCinterionGsm, mm_modem_cinterion_gsm, MM_TYPE_GENERIC_GSM);
#define MM_MODEM_CINTERION_GSM_GET_PRIVATE(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MODEM_CINTERION_GSM, MMModemCinterionGsmPrivate))
typedef struct {
/* Flag to know if we should try AT^SIND or not to get psinfo */
gboolean sind_psinfo;
} MMModemCinterionGsmPrivate;
MMModem *
mm_modem_cinterion_gsm_new (const char *device,
const char *driver,
@@ -48,15 +56,212 @@ mm_modem_cinterion_gsm_new (const char *device,
NULL));
}
static MMModemGsmAccessTech
get_access_technology_from_smong_gprs_status (const gchar *gprs_status,
GError **error)
{
if (strlen (gprs_status) == 1) {
switch (gprs_status[0]) {
case '0':
return MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
case '1':
case '2':
return MM_MODEM_GSM_ACCESS_TECH_GPRS;
case '3':
case '4':
return MM_MODEM_GSM_ACCESS_TECH_EDGE;
default:
break;
}
}
g_set_error (error,
MM_MODEM_ERROR,
MM_MODEM_ERROR_GENERAL,
"Couldn't get network capabilities, "
"invalid GPRS status value: '%s'",
gprs_status);
return MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
}
static MMModemGsmAccessTech
get_access_technology_from_psinfo (const gchar *psinfo,
GError **error)
{
if (strlen (psinfo) == 1) {
switch (psinfo[0]) {
case '0':
return MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
case '1':
case '2':
return MM_MODEM_GSM_ACCESS_TECH_GPRS;
case '3':
case '4':
return MM_MODEM_GSM_ACCESS_TECH_EDGE;
case '5':
case '6':
return MM_MODEM_GSM_ACCESS_TECH_UMTS;
case '7':
case '8':
return MM_MODEM_GSM_ACCESS_TECH_HSDPA;
default:
break;
}
}
g_set_error (error,
MM_MODEM_ERROR,
MM_MODEM_ERROR_GENERAL,
"Couldn't get network capabilities, "
"invalid psinfo value: '%s'",
psinfo);
return MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
}
static void
get_smong_cb (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
MMCallbackInfo *info = user_data;
MMModemCinterionGsmPrivate *priv = MM_MODEM_CINTERION_GSM_GET_PRIVATE (info->modem);
MMModemGsmAccessTech act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
GMatchInfo *match_info = NULL;
GRegex *regex;
if (error) {
info->error = g_error_copy (error);
mm_callback_info_set_result (info, GUINT_TO_POINTER (act), NULL);
mm_callback_info_schedule (info);
return;
}
/* The AT^SMONG command returns a cell info table, where the second
* column identifies the "GPRS status", which is exactly what we want.
* So we'll try to read that second number in the values row.
*
* AT^SMONG
* GPRS Monitor
* BCCH G PBCCH PAT MCC MNC NOM TA RAC # Cell #
* 0776 1 - - 214 03 2 00 01
* OK
*/
regex = g_regex_new (".*GPRS Monitor\\r\\n"
"BCCH\\s*G.*\\r\\n"
"(\\d*)\\s*(\\d*)\\s*", 0, 0, NULL);
if (g_regex_match_full (regex, response->str, response->len, 0, 0, &match_info, NULL)) {
gchar *gprs_status;
gprs_status = g_match_info_fetch (match_info, 2);
act = get_access_technology_from_smong_gprs_status (gprs_status, &info->error);
g_free (gprs_status);
/* We'll default to use SMONG then */
priv->sind_psinfo = FALSE;
} else {
g_set_error (&info->error,
MM_MODEM_ERROR,
MM_MODEM_ERROR_GENERAL,
"Couldn't get network capabilities, invalid SMONG reply: '%s'",
response->str);
/* We'll reset here the flag to try to use SIND/psinfo the next time */
priv->sind_psinfo = TRUE;
}
mm_callback_info_set_result (info, GUINT_TO_POINTER (act), NULL);
mm_callback_info_schedule (info);
}
static void
get_sind_cb (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
MMCallbackInfo *info = user_data;
MMModemGsmAccessTech act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
GMatchInfo *match_info = NULL;
GRegex *regex;
if (error) {
info->error = g_error_copy (error);
mm_callback_info_set_result (info, GUINT_TO_POINTER (act), NULL);
mm_callback_info_schedule (info);
return;
}
/* The AT^SIND? command replies a list of several different indicators.
* We will only look for 'psinfo' which is the one which may tell us
* the available network access technology. Note that only 3G-enabled
* devices seem to have this indicator.
*
* AT+SIND?
* ^SIND: battchg,1,1
* ^SIND: signal,1,99
* ...
*/
regex = g_regex_new ("\\r\\n\\^SIND:\\s*psinfo,\\s*(\\d*),\\s*(\\d*)", 0, 0, NULL);
if (g_regex_match_full (regex, response->str, response->len, 0, 0, &match_info, NULL)) {
gchar *ind_value;
ind_value = g_match_info_fetch (match_info, 2);
act = get_access_technology_from_psinfo (ind_value, &info->error);
g_free (ind_value);
mm_callback_info_set_result (info, GUINT_TO_POINTER (act), NULL);
mm_callback_info_schedule (info);
return;
}
/* If there was no 'psinfo' indicator, we'll try AT^SMONG and read the cell
* info table. */
mm_at_serial_port_queue_command (port, "^SMONG", 3, get_smong_cb, info);
}
static void
get_access_technology (MMGenericGsm *gsm,
MMModemUIntFn callback,
gpointer user_data)
{
MMModemCinterionGsmPrivate *priv = MM_MODEM_CINTERION_GSM_GET_PRIVATE (gsm);
MMAtSerialPort *port;
MMCallbackInfo *info;
info = mm_callback_info_uint_new (MM_MODEM (gsm), callback, user_data);
port = mm_generic_gsm_get_best_at_port (gsm, &info->error);
if (!port) {
mm_callback_info_schedule (info);
return;
}
if (priv->sind_psinfo) {
mm_at_serial_port_queue_command (port, "^SIND?", 3, get_sind_cb, info);
} else {
mm_at_serial_port_queue_command (port, "^SMONG", 3, get_smong_cb, info);
}
}
/*****************************************************************************/
static void
mm_modem_cinterion_gsm_init (MMModemCinterionGsm *self)
{
MMModemCinterionGsmPrivate *priv = MM_MODEM_CINTERION_GSM_GET_PRIVATE (self);
/* Set defaults */
priv->sind_psinfo = TRUE; /* Initially, always try to get psinfo */
}
static void
mm_modem_cinterion_gsm_class_init (MMModemCinterionGsmClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
MMGenericGsmClass *gsm_class = MM_GENERIC_GSM_CLASS (klass);
g_type_class_add_private (object_class, sizeof (MMModemCinterionGsmPrivate));
gsm_class->get_access_technology = get_access_technology;
}