cinterion: implement access technology loading logic

This commit is contained in:
Aleksander Morgado
2012-01-22 15:54:05 +01:00
parent 8321bd5875
commit a6301ee0c4

View File

@@ -41,6 +41,9 @@ G_DEFINE_TYPE_EXTENDED (MMBroadbandModemCinterion, mm_broadband_modem_cinterion,
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init));
struct _MMBroadbandModemCinterionPrivate {
/* Flag to know if we should try AT^SIND or not to get psinfo */
gboolean sind_psinfo;
/* Command to go into sleep mode */
gchar *sleep_mode_cmd;
@@ -175,6 +178,248 @@ modem_power_down (MMIfaceModem *self,
result);
}
/*****************************************************************************/
/* ACCESS TECHNOLOGIES */
static gboolean
load_access_technologies_finish (MMIfaceModem *self,
GAsyncResult *res,
MMModemAccessTechnology *access_technologies,
guint *mask,
GError **error)
{
if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
return FALSE;
*access_technologies = (MMModemAccessTechnology) GPOINTER_TO_UINT (
g_simple_async_result_get_op_res_gpointer (
G_SIMPLE_ASYNC_RESULT (res)));
*mask = MM_MODEM_ACCESS_TECHNOLOGY_ANY;
return TRUE;
}
static MMModemAccessTechnology
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_ACCESS_TECHNOLOGY_UNKNOWN;
case '1':
case '2':
return MM_MODEM_ACCESS_TECHNOLOGY_GPRS;
case '3':
case '4':
return MM_MODEM_ACCESS_TECHNOLOGY_EDGE;
default:
break;
}
}
g_set_error (error,
MM_CORE_ERROR,
MM_CORE_ERROR_INVALID_ARGS,
"Couldn't get network capabilities, "
"invalid GPRS status value: '%s'",
gprs_status);
return MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
}
static void
smong_query_ready (MMBroadbandModemCinterion *self,
GAsyncResult *res,
GSimpleAsyncResult *operation_result)
{
const gchar *response;
GError *error = NULL;
GMatchInfo *match_info = NULL;
GRegex *regex;
response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
if (!response) {
/* Let the error be critical. */
g_simple_async_result_take_error (operation_result, error);
g_simple_async_result_complete (operation_result);
g_object_unref (operation_result);
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, strlen (response), 0, 0, &match_info, NULL)) {
gchar *gprs_status;
MMModemAccessTechnology act;
gprs_status = g_match_info_fetch (match_info, 2);
act = get_access_technology_from_smong_gprs_status (gprs_status, &error);
g_free (gprs_status);
if (error)
g_simple_async_result_take_error (operation_result, error);
else {
/* We'll default to use SMONG then */
self->priv->sind_psinfo = FALSE;
g_simple_async_result_set_op_res_gpointer (operation_result,
GUINT_TO_POINTER (act),
NULL);
}
} else {
/* We'll reset here the flag to try to use SIND/psinfo the next time */
self->priv->sind_psinfo = TRUE;
g_simple_async_result_set_error (operation_result,
MM_CORE_ERROR,
MM_CORE_ERROR_INVALID_ARGS,
"Couldn't get network capabilities, "
"invalid SMONG reply: '%s'",
response);
}
g_match_info_free (match_info);
g_regex_unref (regex);
g_simple_async_result_complete (operation_result);
g_object_unref (operation_result);
}
static MMModemAccessTechnology
get_access_technology_from_psinfo (const gchar *psinfo,
GError **error)
{
if (strlen (psinfo) == 1) {
switch (psinfo[0]) {
case '0':
return MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
case '1':
case '2':
return MM_MODEM_ACCESS_TECHNOLOGY_GPRS;
case '3':
case '4':
return MM_MODEM_ACCESS_TECHNOLOGY_EDGE;
case '5':
case '6':
return MM_MODEM_ACCESS_TECHNOLOGY_UMTS;
case '7':
case '8':
return MM_MODEM_ACCESS_TECHNOLOGY_HSDPA;
default:
break;
}
}
g_set_error (error,
MM_CORE_ERROR,
MM_CORE_ERROR_INVALID_ARGS,
"Couldn't get network capabilities, "
"invalid psinfo value: '%s'",
psinfo);
return MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
}
static void
sind_query_ready (MMBroadbandModemCinterion *self,
GAsyncResult *res,
GSimpleAsyncResult *operation_result)
{
const gchar *response;
GError *error = NULL;
GMatchInfo *match_info = NULL;
GRegex *regex;
response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
if (!response) {
/* Let the error be critical. */
g_simple_async_result_take_error (operation_result, error);
g_simple_async_result_complete (operation_result);
g_object_unref (operation_result);
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, strlen (response), 0, 0, &match_info, NULL)) {
MMModemAccessTechnology act;
gchar *ind_value;
ind_value = g_match_info_fetch (match_info, 2);
act = get_access_technology_from_psinfo (ind_value, &error);
g_free (ind_value);
g_simple_async_result_set_op_res_gpointer (operation_result, GUINT_TO_POINTER (act), NULL);
g_simple_async_result_complete (operation_result);
g_object_unref (operation_result);
} else {
/* If there was no 'psinfo' indicator, we'll try AT^SMONG and read the cell
* info table. */
mm_base_modem_at_command (
MM_BASE_MODEM (self),
"^SMONG",
3,
FALSE,
NULL, /* cancellable */
(GAsyncReadyCallback)smong_query_ready,
operation_result);
}
g_match_info_free (match_info);
g_regex_unref (regex);
}
static void
load_access_technologies (MMIfaceModem *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
MMBroadbandModemCinterion *broadband = MM_BROADBAND_MODEM_CINTERION (self);
GSimpleAsyncResult *result;
result = g_simple_async_result_new (G_OBJECT (self),
callback,
user_data,
load_access_technologies);
if (broadband->priv->sind_psinfo) {
mm_base_modem_at_command (
MM_BASE_MODEM (self),
"^SIND?",
3,
FALSE,
NULL, /* cancellable */
(GAsyncReadyCallback)sind_query_ready,
result);
return;
}
mm_base_modem_at_command (
MM_BASE_MODEM (self),
"^SMONG",
3,
FALSE,
NULL, /* cancellable */
(GAsyncReadyCallback)smong_query_ready,
result);
}
/*****************************************************************************/
/* SUPPORTED MODES */
@@ -348,6 +593,9 @@ mm_broadband_modem_cinterion_init (MMBroadbandModemCinterion *self)
self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self),
MM_TYPE_BROADBAND_MODEM_CINTERION,
MMBroadbandModemCinterionPrivate);
/* Set defaults */
self->priv->sind_psinfo = TRUE; /* Initially, always try to get psinfo */
}
static void
@@ -365,6 +613,8 @@ iface_modem_init (MMIfaceModem *iface)
{
iface->load_supported_modes = load_supported_modes;
iface->load_supported_modes_finish = load_supported_modes_finish;
iface->load_access_technologies = load_access_technologies;
iface->load_access_technologies_finish = load_access_technologies_finish;
iface->setup_flow_control = setup_flow_control;
iface->setup_flow_control_finish = setup_flow_control_finish;
iface->modem_power_down = modem_power_down;