diff options
author | Aleksander Morgado <aleksander@lanedo.com> | 2012-02-20 09:53:46 +0100 |
---|---|---|
committer | Aleksander Morgado <aleksander@lanedo.com> | 2012-03-16 14:28:14 +0100 |
commit | 8396d8a82f05a548d5bc5c058713b413964d7c0a (patch) | |
tree | 1cf93521da6d0c7976a0c31f62ea4bca74a71208 | |
parent | 205313b783d63aa4a61520c351f5db74141b5d8e (diff) |
option: implement default access technology loading
-rw-r--r-- | plugins/option/mm-broadband-modem-option.c | 339 |
1 files changed, 338 insertions, 1 deletions
diff --git a/plugins/option/mm-broadband-modem-option.c b/plugins/option/mm-broadband-modem-option.c index a371f060..bf15b1de 100644 --- a/plugins/option/mm-broadband-modem-option.c +++ b/plugins/option/mm-broadband-modem-option.c @@ -24,10 +24,11 @@ #include <ctype.h> #include "ModemManager.h" -#include "mm-serial-parsers.h" +#include "mm-modem-helpers.h" #include "mm-log.h" #include "mm-errors-types.h" #include "mm-iface-modem.h" +#include "mm-iface-modem-3gpp.h" #include "mm-base-modem-at.h" #include "mm-broadband-modem-option.h" @@ -37,6 +38,340 @@ G_DEFINE_TYPE_EXTENDED (MMBroadbandModemOption, mm_broadband_modem_option, MM_TY G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)); /*****************************************************************************/ +/* Load access technologies (Modem interface) */ + +typedef enum { + ACCESS_TECHNOLOGIES_STEP_FIRST, + ACCESS_TECHNOLOGIES_STEP_OSSYS, + ACCESS_TECHNOLOGIES_STEP_OCTI, + ACCESS_TECHNOLOGIES_STEP_OWCTI, + ACCESS_TECHNOLOGIES_STEP_LAST +} AccessTechnologiesStep; + +typedef struct { + MMBroadbandModemOption *self; + GSimpleAsyncResult *result; + MMModemAccessTechnology access_technology; + gboolean check_2g; + gboolean check_3g; + AccessTechnologiesStep step; +} AccessTechnologiesContext; + +static void load_access_technologies_step (AccessTechnologiesContext *ctx); + +static void +access_technologies_context_complete_and_free (AccessTechnologiesContext *ctx) +{ + g_simple_async_result_complete (ctx->result); + g_object_unref (ctx->result); + g_object_unref (ctx->self); + g_free (ctx); +} + +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; + + /* We are reporting ALL 3GPP access technologies here */ + *access_technologies = (MMModemAccessTechnology) GPOINTER_TO_UINT ( + g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res))); + *mask = MM_IFACE_MODEM_3GPP_ALL_ACCESS_TECHNOLOGIES_MASK; + return TRUE; +} + +static gboolean +ossys_to_mm (gchar ossys, + MMModemAccessTechnology *access_technology) +{ + if (ossys == '0') { + *access_technology = MM_MODEM_ACCESS_TECHNOLOGY_GPRS; + return TRUE; + } + + if (ossys == '2') { + *access_technology = MM_MODEM_ACCESS_TECHNOLOGY_UMTS; + return TRUE; + } + + if (ossys == '3') { + *access_technology = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; + return TRUE; + } + + return FALSE; +} + +static gboolean +parse_ossys_response (const gchar *response, + MMModemAccessTechnology *access_technology) +{ + MMModemAccessTechnology current = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; + const gchar *p; + GRegex *r; + GMatchInfo *match_info; + gchar *str; + gboolean success = FALSE; + + p = mm_strip_tag (response, "_OSSYS:"); + r = g_regex_new ("(\\d),(\\d)", G_REGEX_UNGREEDY, 0, NULL); + g_assert (r != NULL); + + g_regex_match (r, p, 0, &match_info); + if (g_match_info_matches (match_info)) { + str = g_match_info_fetch (match_info, 2); + if (str && ossys_to_mm (str[0], ¤t)) { + *access_technology = current; + success = TRUE; + } + g_free (str); + } + g_match_info_free (match_info); + g_regex_unref (r); + + return success; +} + +static void +ossys_query_ready (MMBaseModem *self, + GAsyncResult *res, + AccessTechnologiesContext *ctx) +{ + const gchar *response; + + /* If for some reason the OSSYS request failed, still try to check + * explicit 2G/3G mode with OCTI and OWCTI; maybe we'll get something. + */ + response = mm_base_modem_at_command_finish (self, res, NULL); + /* Response is _OSSYS: <n>,<act> so we must skip the <n> */ + if (response && + parse_ossys_response (response, &ctx->access_technology)) { + /* If the OSSYS response indicated a generic access tech type + * then only check for more specific access tech of that type. + */ + if (ctx->access_technology == MM_MODEM_ACCESS_TECHNOLOGY_GPRS) + ctx->check_3g = FALSE; + else if (ctx->access_technology == MM_MODEM_ACCESS_TECHNOLOGY_UMTS) + ctx->check_2g = FALSE; + } + + /* Go on to next step */ + ctx->step++; + load_access_technologies_step (ctx); +} + +static gboolean +octi_to_mm (gchar octi, + MMModemAccessTechnology *access_technology) +{ + if (octi == '1') { + *access_technology = MM_MODEM_ACCESS_TECHNOLOGY_GSM; + return TRUE; + } + + if (octi == '2') { + *access_technology = MM_MODEM_ACCESS_TECHNOLOGY_GPRS; + return TRUE; + } + + if (octi == '3') { + *access_technology = MM_MODEM_ACCESS_TECHNOLOGY_EDGE; + return TRUE; + } + + return FALSE; +} + +static gboolean +parse_octi_response (const gchar *response, + MMModemAccessTechnology *access_technology) +{ + MMModemAccessTechnology current = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; + const gchar *p; + GRegex *r; + GMatchInfo *match_info; + gchar *str; + gboolean success = FALSE; + + p = mm_strip_tag (response, "_OCTI:"); + r = g_regex_new ("(\\d),(\\d)", G_REGEX_UNGREEDY, 0, NULL); + g_assert (r != NULL); + + g_regex_match (r, p, 0, &match_info); + if (g_match_info_matches (match_info)) { + str = g_match_info_fetch (match_info, 2); + if (str && octi_to_mm (str[0], ¤t)) { + *access_technology = current; + success = TRUE; + } + g_free (str); + } + g_match_info_free (match_info); + g_regex_unref (r); + + return success; +} + +static void +octi_query_ready (MMBaseModem *self, + GAsyncResult *res, + AccessTechnologiesContext *ctx) +{ + MMModemAccessTechnology octi = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; + const gchar *response; + + response = mm_base_modem_at_command_finish (self, res, NULL); + if (response && + parse_octi_response (response, &octi)) { + /* If current tech is 2G or unknown then use the more specific + * OCTI response. + */ + if (ctx->access_technology < MM_MODEM_ACCESS_TECHNOLOGY_UMTS) + ctx->access_technology = octi; + } + + /* Go on to next step */ + ctx->step++; + load_access_technologies_step (ctx); +} + +static gboolean +owcti_to_mm (gchar owcti, MMModemAccessTechnology *access_technology) +{ + if (owcti == '1') { + *access_technology = MM_MODEM_ACCESS_TECHNOLOGY_UMTS; + return TRUE; + } + + if (owcti == '2') { + *access_technology = MM_MODEM_ACCESS_TECHNOLOGY_HSDPA; + return TRUE; + } + + if (owcti == '3') { + *access_technology = MM_MODEM_ACCESS_TECHNOLOGY_HSUPA; + return TRUE; + } + + if (owcti == '4') { + *access_technology = MM_MODEM_ACCESS_TECHNOLOGY_HSPA; + return TRUE; + } + + return FALSE; +} + +static gboolean +parse_owcti_response (const gchar *response, + MMModemAccessTechnology *access_technology) +{ + response = mm_strip_tag (response, "_OWCTI:"); + return owcti_to_mm (*response, access_technology); +} + +static void +owcti_query_ready (MMBaseModem *self, + GAsyncResult *res, + AccessTechnologiesContext *ctx) +{ + MMModemAccessTechnology owcti = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; + const gchar *response; + + response = mm_base_modem_at_command_finish (self, res, NULL); + if (response && + parse_owcti_response (response, &owcti)) { + ctx->access_technology = owcti; + } + + /* Go on to next step */ + ctx->step++; + load_access_technologies_step (ctx); +} + +static void +load_access_technologies_step (AccessTechnologiesContext *ctx) +{ + switch (ctx->step) { + case ACCESS_TECHNOLOGIES_STEP_FIRST: + /* Go on to next step */ + ctx->step++; + + case ACCESS_TECHNOLOGIES_STEP_OSSYS: + mm_base_modem_at_command (MM_BASE_MODEM (ctx->self), + "_OSSYS?", + 3, + FALSE, + NULL, /* cancellable */ + (GAsyncReadyCallback)ossys_query_ready, + ctx); + break; + + case ACCESS_TECHNOLOGIES_STEP_OCTI: + if (ctx->check_2g) { + mm_base_modem_at_command (MM_BASE_MODEM (ctx->self), + "_OCTI?", + 3, + FALSE, + NULL, /* cancellable */ + (GAsyncReadyCallback)octi_query_ready, + ctx); + return; + } + /* Go on to next step */ + ctx->step++; + + case ACCESS_TECHNOLOGIES_STEP_OWCTI: + if (ctx->check_3g) { + mm_base_modem_at_command (MM_BASE_MODEM (ctx->self), + "_OWCTI?", + 3, + FALSE, + NULL, /* cancellable */ + (GAsyncReadyCallback)owcti_query_ready, + ctx); + return; + } + /* Go on to next step */ + ctx->step++; + + + case ACCESS_TECHNOLOGIES_STEP_LAST: + /* All done, set result and complete */ + g_simple_async_result_set_op_res_gpointer (ctx->result, + GUINT_TO_POINTER (ctx->access_technology), + NULL); + access_technologies_context_complete_and_free (ctx); + break; + } +} + +static void +load_access_technologies (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + AccessTechnologiesContext *ctx; + + ctx = g_new (AccessTechnologiesContext, 1); + ctx->self = g_object_ref (self); + ctx->result = g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + load_access_technologies); + ctx->step = ACCESS_TECHNOLOGIES_STEP_FIRST; + ctx->check_2g = TRUE; + ctx->check_3g = TRUE; + ctx->access_technology = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; + + load_access_technologies_step (ctx); +} + +/*****************************************************************************/ MMBroadbandModemOption * mm_broadband_modem_option_new (const gchar *device, @@ -62,6 +397,8 @@ mm_broadband_modem_option_init (MMBroadbandModemOption *self) static void iface_modem_init (MMIfaceModem *iface) { + iface->load_access_technologies = load_access_technologies; + iface->load_access_technologies_finish = load_access_technologies_finish; } static void |