diff options
-rw-r--r-- | plugins/cinterion/mm-broadband-modem-cinterion.c | 116 | ||||
-rw-r--r-- | plugins/cinterion/mm-modem-helpers-cinterion.c | 47 | ||||
-rw-r--r-- | plugins/cinterion/mm-modem-helpers-cinterion.h | 9 | ||||
-rw-r--r-- | plugins/cinterion/tests/test-modem-helpers-cinterion.c | 45 |
4 files changed, 213 insertions, 4 deletions
diff --git a/plugins/cinterion/mm-broadband-modem-cinterion.c b/plugins/cinterion/mm-broadband-modem-cinterion.c index 31110d56..6affd802 100644 --- a/plugins/cinterion/mm-broadband-modem-cinterion.c +++ b/plugins/cinterion/mm-broadband-modem-cinterion.c @@ -1231,6 +1231,120 @@ setup_flow_control (MMIfaceModem *self, } /*****************************************************************************/ +/* After SIM unlock (Modem interface) */ + +#define MAX_AFTER_SIM_UNLOCK_RETRIES 15 + +typedef enum { + CINTERION_SIM_STATUS_REMOVED = 0, + CINTERION_SIM_STATUS_INSERTED = 1, + CINTERION_SIM_STATUS_INIT_COMPLETED = 5, +} CinterionSimStatus; + +typedef struct { + MMBroadbandModemCinterion *self; + GSimpleAsyncResult *result; + guint retries; + guint timeout_id; +} AfterSimUnlockContext; + +static void +after_sim_unlock_context_complete_and_free (AfterSimUnlockContext *ctx) +{ + g_assert (ctx->timeout_id == 0); + g_simple_async_result_complete (ctx->result); + g_object_unref (ctx->result); + g_object_unref (ctx->self); + g_slice_free (AfterSimUnlockContext, ctx); +} + +static gboolean +after_sim_unlock_finish (MMIfaceModem *self, + GAsyncResult *res, + GError **error) +{ + return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error); +} + +static void after_sim_unlock_context_step (AfterSimUnlockContext *ctx); + +static gboolean +simstatus_timeout_cb (AfterSimUnlockContext *ctx) +{ + ctx->timeout_id = 0; + after_sim_unlock_context_step (ctx); + return FALSE; +} + +static void +simstatus_check_ready (MMBaseModem *self, + GAsyncResult *res, + AfterSimUnlockContext *ctx) +{ + const gchar *response; + + response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, NULL); + if (response) { + gchar *descr = NULL; + guint val = 0; + + if (mm_cinterion_parse_sind_response (response, &descr, NULL, &val, NULL) && + g_str_equal (descr, "simstatus") && + val == CINTERION_SIM_STATUS_INIT_COMPLETED) { + /* SIM ready! */ + g_free (descr); + g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); + after_sim_unlock_context_complete_and_free (ctx); + return; + } + + g_free (descr); + } + + /* Need to retry after 1 sec */ + g_assert (ctx->timeout_id == 0); + ctx->timeout_id = g_timeout_add_seconds (1, (GSourceFunc)simstatus_timeout_cb, ctx); +} + +static void +after_sim_unlock_context_step (AfterSimUnlockContext *ctx) +{ + if (ctx->retries == 0) { + /* Too much wait, go on anyway */ + g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE); + after_sim_unlock_context_complete_and_free (ctx); + return; + } + + /* Recheck */ + ctx->retries--; + mm_base_modem_at_command (MM_BASE_MODEM (ctx->self), + "^SIND=\"simstatus\",1", + 3, + FALSE, + (GAsyncReadyCallback)simstatus_check_ready, + ctx); +} + +static void +after_sim_unlock (MMIfaceModem *self, + GAsyncReadyCallback callback, + gpointer user_data) +{ + AfterSimUnlockContext *ctx; + + ctx = g_slice_new0 (AfterSimUnlockContext); + ctx->self = g_object_ref (self); + ctx->result = g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + after_sim_unlock); + ctx->retries = MAX_AFTER_SIM_UNLOCK_RETRIES; + + after_sim_unlock_context_step (ctx); +} + +/*****************************************************************************/ MMBroadbandModemCinterion * mm_broadband_modem_cinterion_new (const gchar *device, @@ -1290,6 +1404,8 @@ iface_modem_init (MMIfaceModem *iface) 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_after_sim_unlock = after_sim_unlock; + iface->modem_after_sim_unlock_finish = after_sim_unlock_finish; iface->modem_power_down = modem_power_down; iface->modem_power_down_finish = modem_power_down_finish; iface->modem_power_off = modem_power_off; diff --git a/plugins/cinterion/mm-modem-helpers-cinterion.c b/plugins/cinterion/mm-modem-helpers-cinterion.c index 97eb7115..118cbb67 100644 --- a/plugins/cinterion/mm-modem-helpers-cinterion.c +++ b/plugins/cinterion/mm-modem-helpers-cinterion.c @@ -286,3 +286,50 @@ mm_cinterion_build_band (GArray *bands, *out_band = band; return TRUE; } + +/*****************************************************************************/ +/* Single ^SIND response parser */ + +gboolean +mm_cinterion_parse_sind_response (const gchar *response, + gchar **description, + guint *mode, + guint *value, + GError **error) +{ + GRegex *r; + GMatchInfo *match_info; + guint errors = 0; + + if (!response) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Missing response"); + return FALSE; + } + + r = g_regex_new ("\\^SIND:\\s*(.*),(\\d+),(\\d+)(\\r\\n)?", 0, 0, NULL); + g_assert (r != NULL); + + if (g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, NULL)) { + if (description) { + *description = mm_get_string_unquoted_from_match_info (match_info, 1); + if (*description == NULL) + errors++; + } + if (mode && !mm_get_uint_from_match_info (match_info, 2, mode)) + errors++; + if (value && !mm_get_uint_from_match_info (match_info, 3, value)) + errors++; + } else + errors++; + + if (match_info) + g_match_info_free (match_info); + g_regex_unref (r); + + if (errors > 0) { + g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Failed parsing ^SIND response"); + return FALSE; + } + + return TRUE; +} diff --git a/plugins/cinterion/mm-modem-helpers-cinterion.h b/plugins/cinterion/mm-modem-helpers-cinterion.h index f4c982f6..ecc10460 100644 --- a/plugins/cinterion/mm-modem-helpers-cinterion.h +++ b/plugins/cinterion/mm-modem-helpers-cinterion.h @@ -43,4 +43,13 @@ gboolean mm_cinterion_build_band (GArray *bands, guint *out_band, GError **error); +/*****************************************************************************/ +/* Single ^SIND response parser */ + +gboolean mm_cinterion_parse_sind_response (const gchar *response, + gchar **description, + guint *mode, + guint *value, + GError **error); + #endif /* MM_MODEM_HELPERS_CINTERION_H */ diff --git a/plugins/cinterion/tests/test-modem-helpers-cinterion.c b/plugins/cinterion/tests/test-modem-helpers-cinterion.c index 1ee71c9b..5dc4f960 100644 --- a/plugins/cinterion/tests/test-modem-helpers-cinterion.c +++ b/plugins/cinterion/tests/test-modem-helpers-cinterion.c @@ -211,6 +211,42 @@ test_scfg_response_3g (void) } /*****************************************************************************/ +/* Test ^SIND responses */ + +static void +common_test_sind_response (const gchar *response, + const gchar *expected_description, + guint expected_mode, + guint expected_value) +{ + GError *error = NULL; + gboolean res; + gchar *description; + guint mode; + guint value; + + res = mm_cinterion_parse_sind_response (response, + &description, + &mode, + &value, + &error); + g_assert_no_error (error); + g_assert (res == TRUE); + + g_assert_cmpstr (description, ==, expected_description); + g_assert_cmpuint (mode, ==, expected_mode); + g_assert_cmpuint (value, ==, expected_value); + + g_free (description); +} + +static void +test_sind_response_simstatus (void) +{ + common_test_sind_response ("^SIND: simstatus,1,5", "simstatus", 1, 5); +} + +/*****************************************************************************/ void _mm_log (const char *loc, @@ -239,10 +275,11 @@ int main (int argc, char **argv) g_type_init (); g_test_init (&argc, &argv, NULL); - g_test_add_func ("/MM/cinterion/scfg", test_scfg); - g_test_add_func ("/MM/cinterion/scfg/response/3g", test_scfg_response_3g); - g_test_add_func ("/MM/cinterion/scfg/response/2g", test_scfg_response_2g); - g_test_add_func ("/MM/cinterion/scfg/response/2g/ucs2", test_scfg_response_2g_ucs2); + g_test_add_func ("/MM/cinterion/scfg", test_scfg); + g_test_add_func ("/MM/cinterion/scfg/response/3g", test_scfg_response_3g); + g_test_add_func ("/MM/cinterion/scfg/response/2g", test_scfg_response_2g); + g_test_add_func ("/MM/cinterion/scfg/response/2g/ucs2", test_scfg_response_2g_ucs2); + g_test_add_func ("/MM/cinterion/sind/response/simstatus", test_sind_response_simstatus); return g_test_run (); } |