diff options
author | Aleksander Morgado <aleksander@lanedo.com> | 2012-03-18 17:07:13 +0100 |
---|---|---|
committer | Aleksander Morgado <aleksander@lanedo.com> | 2012-03-18 17:28:14 +0100 |
commit | 82d72744a25c6912cb6e6737b40b830f9652d06c (patch) | |
tree | 4d2011bd2ceb58d3b2f0fcebee21c45f67e927bf | |
parent | d58d3f52a29aaed06c805da70311a2b66d4eeaf9 (diff) | |
download | ModemManager-82d72744a25c6912cb6e6737b40b830f9652d06c.tar.gz |
anydata: get detailed CDMA1x/EVDO registration states
-rw-r--r-- | plugins/anydata/mm-broadband-modem-anydata.c | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/plugins/anydata/mm-broadband-modem-anydata.c b/plugins/anydata/mm-broadband-modem-anydata.c index 9521eef59..1a95229b5 100644 --- a/plugins/anydata/mm-broadband-modem-anydata.c +++ b/plugins/anydata/mm-broadband-modem-anydata.c @@ -26,6 +26,7 @@ #include "ModemManager.h" #include "mm-serial-parsers.h" #include "mm-log.h" +#include "mm-modem-helpers.h" #include "mm-errors-types.h" #include "mm-base-modem-at.h" #include "mm-broadband-modem-anydata.h" @@ -37,6 +38,220 @@ G_DEFINE_TYPE_EXTENDED (MMBroadbandModemAnydata, mm_broadband_modem_anydata, MM_ G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_CDMA, iface_modem_cdma_init)); /*****************************************************************************/ +/* Detailed registration state (CDMA interface) */ +typedef struct { + MMModemCdmaRegistrationState detailed_cdma1x_state; + MMModemCdmaRegistrationState detailed_evdo_state; +} DetailedRegistrationStateResults; + +typedef struct { + MMBroadbandModem *self; + GSimpleAsyncResult *result; + MMAtSerialPort *port; + MMModemCdmaRegistrationState cdma1x_state; + MMModemCdmaRegistrationState evdo_state; + GError *error; +} DetailedRegistrationStateContext; + +static void +detailed_registration_state_context_complete_and_free (DetailedRegistrationStateContext *ctx) +{ + if (ctx->error) + g_simple_async_result_take_error (ctx->result, ctx->error); + else { + DetailedRegistrationStateResults *results; + + results = g_new (DetailedRegistrationStateResults, 1); + results->detailed_cdma1x_state = ctx->cdma1x_state; + results->detailed_evdo_state = ctx->evdo_state; + g_simple_async_result_set_op_res_gpointer (ctx->result, results, g_free); + } + + g_simple_async_result_complete (ctx->result); + g_object_unref (ctx->port); + g_object_unref (ctx->result); + g_object_unref (ctx->self); + g_free (ctx); +} + +static gboolean +get_detailed_registration_state_finish (MMIfaceModemCdma *self, + GAsyncResult *res, + MMModemCdmaRegistrationState *detailed_cdma1x_state, + MMModemCdmaRegistrationState *detailed_evdo_state, + GError **error) +{ + DetailedRegistrationStateResults *results; + + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error)) + return FALSE; + + results = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res)); + *detailed_cdma1x_state = results->detailed_cdma1x_state; + *detailed_evdo_state = results->detailed_evdo_state; + return TRUE; +} + +static void +hstate_ready (MMIfaceModemCdma *self, + GAsyncResult *res, + DetailedRegistrationStateContext *ctx) +{ + GError *error = NULL; + const gchar *response; + GRegex *r; + GMatchInfo *match_info; + + response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error); + if (error) { + /* Leave superclass' reg state alone if AT*HSTATE isn't supported */ + g_error_free (error); + /* Result is set here when completing */ + detailed_registration_state_context_complete_and_free (ctx); + return; + } + + response = mm_strip_tag (response, "*HSTATE:"); + + /* Format is "<at state>,<session state>,<channel>,<pn>,<EcIo>,<rssi>,..." */ + r = g_regex_new ("\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*([^,\\)]*)\\s*,\\s*([^,\\)]*)\\s*,.*", + G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + g_assert (r != NULL); + + g_regex_match (r, response, 0, &match_info); + if (g_match_info_get_match_count (match_info) >= 6) { + guint val = 0; + gint dbm = 0; + + /* dBm is between -106 (worst) and -20.7 (best) */ + mm_get_int_from_match_info (match_info, 6, &dbm); + + /* Parse the EVDO radio state */ + if (mm_get_uint_from_match_info (match_info, 1, &val)) { + switch (val) { + case 3: /* IDLE */ + /* If IDLE and the EVDO dBm is -105 or lower, assume no service. + * It may be that IDLE actually means NO SERVICE too; not sure. + */ + if (dbm > -105) + ctx->evdo_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED; + break; + case 4: /* ACCESS */ + case 5: /* CONNECT */ + ctx->evdo_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED; + break; + default: + mm_warn ("ANYDATA: unknown *STATE (%d); assuming no service.", val); + /* fall through */ + case 0: /* NO SERVICE */ + case 1: /* ACQUISITION */ + case 2: /* SYNC */ + break; + } + } + } + + g_match_info_free (match_info); + g_regex_unref (r); + + /* Result is set here when completing */ + detailed_registration_state_context_complete_and_free (ctx); +} + +static void +state_ready (MMIfaceModemCdma *self, + GAsyncResult *res, + DetailedRegistrationStateContext *ctx) +{ + const gchar *response; + GRegex *r; + GMatchInfo *match_info; + + response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &ctx->error); + if (ctx->error) { + detailed_registration_state_context_complete_and_free (ctx); + return; + } + + response = mm_strip_tag (response, "*STATE:"); + + /* Format is "<channel>,<pn>,<sid>,<nid>,<state>,<rssi>,..." */ + r = g_regex_new ("\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*([^,\\)]*)\\s*,.*", + G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + g_assert (r != NULL); + + g_regex_match (r, response, 0, &match_info); + if (g_match_info_get_match_count (match_info) >= 6) { + guint val = 0; + gint dbm = 0; + + /* dBm is between -106 (worst) and -20.7 (best) */ + mm_get_int_from_match_info (match_info, 6, &dbm); + + /* Parse the 1x radio state */ + if (mm_get_uint_from_match_info (match_info, 5, &val)) { + switch (val) { + case 1: /* IDLE */ + /* If IDLE and the 1X dBm is -105 or lower, assume no service. + * It may be that IDLE actually means NO SERVICE too; not sure. + */ + if (dbm > -105) + ctx->cdma1x_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED; + break; + case 2: /* ACCESS */ + case 3: /* PAGING */ + case 4: /* TRAFFIC */ + ctx->cdma1x_state = MM_MODEM_CDMA_REGISTRATION_STATE_REGISTERED; + break; + default: + mm_warn ("ANYDATA: unknown *STATE (%d); assuming no service.", val); + /* fall through */ + case 0: /* NO SERVICE */ + break; + } + } + } + + g_match_info_free (match_info); + g_regex_unref (r); + + /* Try for EVDO state too */ + mm_base_modem_at_command (MM_BASE_MODEM (self), + "*HSTATE?", + 3, + FALSE, + (GAsyncReadyCallback)hstate_ready, + ctx); +} + +static void +get_detailed_registration_state (MMIfaceModemCdma *self, + MMModemCdmaRegistrationState cdma1x_state, + MMModemCdmaRegistrationState evdo_state, + GAsyncReadyCallback callback, + gpointer user_data) +{ + DetailedRegistrationStateContext *ctx; + + /* Setup context */ + ctx = g_new0 (DetailedRegistrationStateContext, 1); + ctx->self = g_object_ref (self); + ctx->result = g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + get_detailed_registration_state); + ctx->cdma1x_state = cdma1x_state; + ctx->evdo_state = evdo_state; + + mm_base_modem_at_command (MM_BASE_MODEM (self), + "*STATE?", + 3, + FALSE, + (GAsyncReadyCallback)state_ready, + ctx); +} + +/*****************************************************************************/ MMBroadbandModemAnydata * mm_broadband_modem_anydata_new (const gchar *device, @@ -64,6 +279,8 @@ iface_modem_cdma_init (MMIfaceModemCdma *iface) { iface->get_cdma1x_serving_system = NULL; iface->get_cdma1x_serving_system_finish = NULL; + iface->get_detailed_registration_state = get_detailed_registration_state; + iface->get_detailed_registration_state_finish = get_detailed_registration_state_finish; } static void |