cinterion: after SIM unlock, query SIM status until ready

This commit is contained in:
Aleksander Morgado
2014-03-03 14:33:12 +01:00
parent f20724ec3f
commit 191168e3ef
4 changed files with 213 additions and 4 deletions

View File

@@ -1230,6 +1230,120 @@ setup_flow_control (MMIfaceModem *self,
result);
}
/*****************************************************************************/
/* 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 *
@@ -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;

View File

@@ -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;
}

View File

@@ -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 */

View File

@@ -210,6 +210,42 @@ test_scfg_response_3g (void)
g_array_unref (expected_bands);
}
/*****************************************************************************/
/* 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
@@ -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 ();
}