cinterion: modification to fetching unlock retries
Colin Helliwell
colin.helliwell at ln-systems.com
Fri Apr 14 12:57:55 UTC 2017
Some Cinterion modems support AT^SPIC to fetch the 'unlock retries', but some don't. Another method possibly available is to used AT+CSIM (as per Telit plugin).
This aims to allow either method to be tried - if the first step of the first method fails (e.g. SPIC not supported), then try again using the alternate.
I did wonder about a single array of commands but that would have meant hard-coding in a 'goto' to get from A to B, hence prone to future changes breaking it.
Bit more checking required yet, but at first glance it looks like basically works.
I'm not sending this as a patch here, but just to get views on (or objections to!) the general approach.
Note that I've coded it to make it easy to switch which method is tried first (TBD? Configurable? Run-time based on the Model?) - see the #defines. And it's another reason for having two separate arrays.
The CSIM parsing isn't shown here, but at the moment it's as per the Telit helper.
Apologies in advance if my webmail screws up the line-wrapping.
/*****************************************************************************/
/* Load unlock retries (Modem interface) */
typedef struct {
MMBroadbandModemCinterion *self;
GSimpleAsyncResult *result;
MMUnlockRetries *retries;
gint i;
} LoadUnlockRetriesContext;
typedef struct {
MMModemLock lock;
const gchar *command;
} UnlockRetriesMap;
const UnlockRetriesMap *unlock_retries_map_ptr;
guint unlock_retries_map_size;
static const UnlockRetriesMap unlock_retries_map_spic [] = {
{ MM_MODEM_LOCK_SIM_PIN, "^SPIC=\"SC\"" },
{ MM_MODEM_LOCK_SIM_PUK, "^SPIC=\"SC\",1" },
{ MM_MODEM_LOCK_SIM_PIN2, "^SPIC=\"P2\"" },
{ MM_MODEM_LOCK_SIM_PUK2, "^SPIC=\"P2\",1" },
{ MM_MODEM_LOCK_PH_FSIM_PIN, "^SPIC=\"PS\"" },
{ MM_MODEM_LOCK_PH_FSIM_PUK, "^SPIC=\"PS\",1" },
{ MM_MODEM_LOCK_PH_NET_PIN, "^SPIC=\"PN\"" },
{ MM_MODEM_LOCK_PH_NET_PUK, "^SPIC=\"PN\",1" },
};
static const UnlockRetriesMap unlock_retries_map_csim [] = {
{ MM_MODEM_LOCK_SIM_PIN, "+CSIM=10,\"0020000100\"" },
{ MM_MODEM_LOCK_SIM_PUK, "+CSIM=10,\"002C000100\"" },
{ MM_MODEM_LOCK_SIM_PIN2, "+CSIM=10,\"0020008100\"" },
{ MM_MODEM_LOCK_SIM_PUK2, "+CSIM=10,\"002C008100\"" },
};
#define UNLOCK_RETRIES_FIRST_MAP unlock_retries_map_spic
#define UNLOCK_RETRIES_SECOND_MAP unlock_retries_map_csim
static void
load_unlock_retries_context_complete_and_free (LoadUnlockRetriesContext *ctx)
{
g_simple_async_result_complete (ctx->result);
g_object_unref (ctx->retries);
g_object_unref (ctx->result);
g_object_unref (ctx->self);
g_slice_free (LoadUnlockRetriesContext, ctx);
}
static MMUnlockRetries *
load_unlock_retries_finish (MMIfaceModem *self,
GAsyncResult *res,
GError **error)
{
if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
return NULL;
return (MMUnlockRetries *) g_object_ref (g_simple_async_result_get_op_res_gpointer (
G_SIMPLE_ASYNC_RESULT (res)));
}
static void load_unlock_retries_context_step (LoadUnlockRetriesContext *ctx);
static void
load_unlock_retries_ready (MMBaseModem *self,
GAsyncResult *res,
LoadUnlockRetriesContext *ctx)
{
const gchar *response;
GError *error = NULL;
response = mm_base_modem_at_command_finish (self, res, &error);
if (!response) {
mm_dbg ("Couldn't load retry count for lock '%s': %s",
mm_modem_lock_get_string (unlock_retries_map_ptr[ctx->i].lock),
error->message);
g_error_free (error);
/* Switch to second map if first step of first one fails */
if ((unlock_retries_map_ptr == UNLOCK_RETRIES_FIRST_MAP) && !ctx->i) {
/* Set the second method to try */
unlock_retries_map_ptr = UNLOCK_RETRIES_SECOND_MAP;
unlock_retries_map_size = G_N_ELEMENTS (UNLOCK_RETRIES_SECOND_MAP);
/* Restart state machine */
ctx->i = -1;
}
} else {
gint val;
if (unlock_retries_map_ptr == unlock_retries_map_spic) {
response = mm_strip_tag (response, "^SPIC:");
if (!mm_get_uint_from_str (response, (guint *) &val))
val = -1;
} else if (unlock_retries_map_ptr == unlock_retries_map_csim) {
GError *error = NULL;
val = mm_cinterion_parse_csim_response (ctx->i, response, &error);
if (val < 0)
mm_warn ("Parse error in step %d: %s.", ctx->i, error->message);
}
if (val < 0)
mm_dbg ("Couldn't parse retry count value for lock '%s'",
mm_modem_lock_get_string (unlock_retries_map_ptr[ctx->i].lock));
else
mm_unlock_retries_set (ctx->retries, unlock_retries_map_ptr[ctx->i].lock, (guint) val);
}
/* Go to next lock value */
ctx->i++;
load_unlock_retries_context_step (ctx);
}
static void
load_unlock_retries_context_step (LoadUnlockRetriesContext *ctx)
{
if (ctx->i == unlock_retries_map_size) {
g_simple_async_result_set_op_res_gpointer (ctx->result,
g_object_ref (ctx->retries),
g_object_unref);
load_unlock_retries_context_complete_and_free (ctx);
return;
}
mm_base_modem_at_command (
MM_BASE_MODEM (ctx->self),
unlock_retries_map_ptr[ctx->i].command,
3,
FALSE,
(GAsyncReadyCallback)load_unlock_retries_ready,
ctx);
}
static void
load_unlock_retries (MMIfaceModem *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
LoadUnlockRetriesContext *ctx;
ctx = g_slice_new0 (LoadUnlockRetriesContext);
ctx->self = g_object_ref (self);
ctx->result = g_simple_async_result_new (G_OBJECT (self),
callback,
user_data,
load_unlock_retries);
ctx->retries = mm_unlock_retries_new ();
ctx->i = 0;
/* Set the first method to try */
unlock_retries_map_ptr = UNLOCK_RETRIES_FIRST_MAP;
unlock_retries_map_size = G_N_ELEMENTS (UNLOCK_RETRIES_FIRST_MAP);
load_unlock_retries_context_step (ctx);
}
More information about the ModemManager-devel
mailing list