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);
}
_______________________________________________
ModemManager-devel mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/modemmanager-devel

Reply via email to