telit: add load_unlock_retries interface

This commit is contained in:
Carlo Lobrano
2015-12-16 15:38:58 +01:00
committed by Aleksander Morgado
parent 7978225934
commit c4ffe572ae
5 changed files with 404 additions and 1 deletions

View File

@@ -550,11 +550,27 @@ libmm_plugin_telit_la_SOURCES = \
telit/mm-plugin-telit.c \
telit/mm-plugin-telit.h \
telit/mm-broadband-modem-telit.c \
telit/mm-broadband-modem-telit.h
telit/mm-broadband-modem-telit.h \
telit/mm-modem-helpers-telit.c \
telit/mm-modem-helpers-telit.h
libmm_plugin_telit_la_CPPFLAGS = $(PLUGIN_COMMON_COMPILER_FLAGS)
libmm_plugin_telit_la_LDFLAGS = $(PLUGIN_COMMON_LINKER_FLAGS)
udevrules_DATA += telit/77-mm-telit-port-types.rules
noinst_PROGRAMS += test-modem-helpers-telit
test_modem_helpers_telit_SOURCES = \
telit/mm-modem-helpers-telit.c \
telit/mm-modem-helpers-telit.h \
telit/tests/test-mm-modem-helpers-telit.c
test_modem_helpers_telit_CPPFLAGS = \
-I$(top_srcdir)/plugins/telit \
$(PLUGIN_COMMON_COMPILER_FLAGS)
test_modem_helpers_telit_LDADD = \
$(top_builddir)/libmm-glib/libmm-glib.la \
$(top_builddir)/src/libmodem-helpers.la
test_modem_helpers_telit_LDADD = $(top_builddir)/libmm-glib/libmm-glib.la
test_modem_helpers_telit_LDFLAGS = $(PLUGIN_COMMON_LINKER_FLAGS)
# MTK
libmm_plugin_mtk_la_SOURCES = \
mtk/mm-plugin-mtk.c \

View File

@@ -31,6 +31,7 @@
#include "mm-iface-modem.h"
#include "mm-iface-modem-3gpp.h"
#include "mm-broadband-modem-telit.h"
#include "mm-modem-helpers-telit.h"
static void iface_modem_init (MMIfaceModem *iface);
static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface);
@@ -39,6 +40,186 @@ G_DEFINE_TYPE_EXTENDED (MMBroadbandModemTelit, mm_broadband_modem_telit, MM_TYPE
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init));
/*****************************************************************************/
/* Load unlock retries (Modem interface) */
#define CSIM_QUERY_PIN_RETRIES_STR "+CSIM=10,0020000100"
#define CSIM_QUERY_PUK_RETRIES_STR "+CSIM=10,002C000100"
#define CSIM_QUERY_PIN2_RETRIES_STR "+CSIM=10,0020008100"
#define CSIM_QUERY_PUK2_RETRIES_STR "+CSIM=10,002C008100"
#define CSIM_QUERY_TIMEOUT 3
typedef enum {
LOAD_UNLOCK_RETRIES_STEP_FIRST,
LOAD_UNLOCK_RETRIES_STEP_PIN,
LOAD_UNLOCK_RETRIES_STEP_PUK,
LOAD_UNLOCK_RETRIES_STEP_PIN2,
LOAD_UNLOCK_RETRIES_STEP_PUK2,
LOAD_UNLOCK_RETRIES_STEP_LAST
} LoadUnlockRetriesStep;
typedef struct {
MMBroadbandModemTelit* self;
GSimpleAsyncResult* result;
MMUnlockRetries* retries;
LoadUnlockRetriesStep step;
guint succeded_requests;
} LoadUnlockRetriesContext;
static void load_unlock_retries_step (LoadUnlockRetriesContext* ctx);
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 *
modem_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
csim_query_ready (MMBaseModem *self,
GAsyncResult* res,
LoadUnlockRetriesContext* ctx)
{
const gchar *response;
gint unlock_retries;
GError *error = NULL;
response = mm_base_modem_at_command_finish (self, res, &error);
if (!response) {
mm_warn ("No respose for step %d: %s", ctx->step, error->message);
g_error_free (error);
goto next_step;
}
if ( (unlock_retries = parse_csim_response (ctx->step, response, &error)) < 0) {
mm_warn ("Parse error in step %d: %s.", ctx->step, error->message);
g_error_free (error);
goto next_step;
}
ctx->succeded_requests++;
switch (ctx->step) {
case LOAD_UNLOCK_RETRIES_STEP_PIN:
mm_dbg ("PIN unlock retries left: %d", unlock_retries);
mm_unlock_retries_set (ctx->retries, MM_MODEM_LOCK_SIM_PIN, unlock_retries);
break;
case LOAD_UNLOCK_RETRIES_STEP_PUK:
mm_dbg ("PUK unlock retries left: %d", unlock_retries);
mm_unlock_retries_set (ctx->retries, MM_MODEM_LOCK_SIM_PUK, unlock_retries);
break;
case LOAD_UNLOCK_RETRIES_STEP_PIN2:
mm_dbg ("PIN2 unlock retries left: %d", unlock_retries);
mm_unlock_retries_set (ctx->retries, MM_MODEM_LOCK_SIM_PIN2, unlock_retries);
break;
case LOAD_UNLOCK_RETRIES_STEP_PUK2:
mm_dbg ("PUK2 unlock retries left: %d", unlock_retries);
mm_unlock_retries_set (ctx->retries, MM_MODEM_LOCK_SIM_PUK2, unlock_retries);
break;
default:
break;
}
next_step:
ctx->step++;
load_unlock_retries_step (ctx);
}
static void
load_unlock_retries_step (LoadUnlockRetriesContext* ctx)
{
switch (ctx->step) {
case LOAD_UNLOCK_RETRIES_STEP_FIRST:
/* Fall back on next step */
ctx->step++;
case LOAD_UNLOCK_RETRIES_STEP_PIN:
mm_base_modem_at_command (MM_BASE_MODEM (ctx->self),
CSIM_QUERY_PIN_RETRIES_STR,
CSIM_QUERY_TIMEOUT,
FALSE,
(GAsyncReadyCallback) csim_query_ready,
ctx);
break;
case LOAD_UNLOCK_RETRIES_STEP_PUK:
mm_base_modem_at_command (MM_BASE_MODEM (ctx->self),
CSIM_QUERY_PUK_RETRIES_STR,
CSIM_QUERY_TIMEOUT,
FALSE,
(GAsyncReadyCallback) csim_query_ready,
ctx);
break;
case LOAD_UNLOCK_RETRIES_STEP_PIN2:
mm_base_modem_at_command (MM_BASE_MODEM (ctx->self),
CSIM_QUERY_PIN2_RETRIES_STR,
CSIM_QUERY_TIMEOUT,
FALSE,
(GAsyncReadyCallback) csim_query_ready,
ctx);
break;
case LOAD_UNLOCK_RETRIES_STEP_PUK2:
mm_base_modem_at_command (MM_BASE_MODEM (ctx->self),
CSIM_QUERY_PUK2_RETRIES_STR,
CSIM_QUERY_TIMEOUT,
FALSE,
(GAsyncReadyCallback) csim_query_ready,
ctx);
break;
case LOAD_UNLOCK_RETRIES_STEP_LAST:
if (ctx->succeded_requests == 0) {
g_simple_async_result_set_error (ctx->result,
MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
"Could not get any of the SIM unlock retries values. Look above for warning messages");
} else {
g_simple_async_result_set_op_res_gpointer (ctx->result,
g_object_ref (ctx->retries),
(GDestroyNotify)g_object_unref);
}
load_unlock_retries_context_complete_and_free (ctx);
break;
default:
break;
}
}
static void
modem_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,
modem_load_unlock_retries);
ctx->retries = mm_unlock_retries_new ();
ctx->step = 0;
ctx->succeded_requests = 0;
load_unlock_retries_step (ctx);
}
/*****************************************************************************/
/* Modem power down (Modem interface) */
@@ -336,6 +517,8 @@ mm_broadband_modem_telit_init (MMBroadbandModemTelit *self)
static void
iface_modem_init (MMIfaceModem *iface)
{
iface->load_unlock_retries_finish = modem_load_unlock_retries_finish;
iface->load_unlock_retries = modem_load_unlock_retries;
iface->reset = modem_reset;
iface->reset_finish = modem_reset_finish;
iface->modem_power_down = modem_power_down;

View File

@@ -0,0 +1,75 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details:
*
* Copyright (C) 2015 Telit.
*
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ModemManager.h>
#define _LIBMM_INSIDE_MMCLI
#include <libmm-glib.h>
#include "mm-log.h"
#include "mm-modem-helpers.h"
#include "mm-modem-helpers-telit.h"
/*****************************************************************************/
/* +CSIM response parser */
gint parse_csim_response (const guint step, const gchar* response, GError** error)
{
GRegex *r = NULL;
GMatchInfo *match_info = NULL;
gchar* retries_hex_str;
guint retries;
r = g_regex_new ("\\+CSIM:\\s*[0-9]+,\\s*.*63C(.*)\"", G_REGEX_RAW, 0, NULL);
if (!g_regex_match (r, response, 0, &match_info)) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
"Could not parse reponse '%s'", response);
g_match_info_free (match_info);
g_regex_unref (r);
return -1;
}
if (!g_match_info_matches (match_info)) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
"Could not find matches in response '%s'", response);
g_match_info_free (match_info);
g_regex_unref (r);
return -1;
}
retries_hex_str = mm_get_string_unquoted_from_match_info (match_info, 1);
g_assert (NULL != retries_hex_str);
/* convert hex value to uint */
if (sscanf (retries_hex_str, "%x", &retries) != 1) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
"Could not get retry value from match '%s'",
retries_hex_str);
g_match_info_free (match_info);
g_regex_unref (r);
return -1;
}
g_free (retries_hex_str);
g_match_info_free (match_info);
g_regex_unref (r);
return retries;
}

View File

@@ -0,0 +1,25 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details:
*
* Copyright (C) 2015 Telit.
*
*/
#ifndef MM_MODEM_HELPERS_TELIT_H
#define MM_MODEM_HELPERS_TELIT_H
#include <glib.h>
/* +CSIM response parser */
gint parse_csim_response (const guint step, const gchar* response, GError** error);
#endif /* MM_MODEM_HELPERS_TELIT_H */

View File

@@ -0,0 +1,104 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details:
*
* Copyright (C) 2015 Telit
*
*/
#include <stdio.h>
#include <glib.h>
#include <glib-object.h>
#include <locale.h>
#include <ModemManager.h>
#define _LIBMM_INSIDE_MM
#include <libmm-glib.h>
#include "mm-log.h"
#include "mm-modem-helpers.h"
#include "mm-modem-helpers-telit.h"
typedef struct {
gchar* response;
gint result;
} CSIMResponseTest;
static CSIMResponseTest valid_csim_response_test_list [] = {
/* The parser expects that 2nd arg contains
* substring "63Cx" where x is an HEX string
* representing the retry value */
{"+CSIM:8,\"xxxx63C1\"", 1},
{"+CSIM:8,\"xxxx63CA\"", 10},
{"+CSIM:8,\"xxxx63CF\"", 15},
/* The parser accepts spaces */
{"+CSIM:8,\"xxxx63C1\"", 1},
{"+CSIM:8, \"xxxx63C1\"", 1},
{"+CSIM: 8, \"xxxx63C1\"", 1},
{"+CSIM: 8, \"xxxx63C1\"", 1},
/* the parser expects an int as first argument (2nd arg's length),
* but does not check if it is correct */
{"+CSIM: 10, \"63CF\"", 15},
/* the parser expect a quotation mark at the end
* of the response, but not at the begin */
{"+CSIM: 10, 63CF\"", 15},
{ NULL, -1}
};
static CSIMResponseTest invalid_csim_response_test_list [] = {
/* Test missing final quotation mark */
{"+CSIM: 8, xxxx63CF", -1},
/* Negative test for substring "63Cx" */
{"+CSIM: 4, xxxx73CF\"", -1},
/* Test missing first argument */
{"+CSIM:xxxx63CF\"", -1},
{ NULL, -1}
};
static void
test_parse_csim_response (void)
{
const gint step = 1;
guint i;
gint res;
GError* error = NULL;
/* Test valid responses */
for (i = 0; valid_csim_response_test_list[i].response != NULL; i++) {
res = parse_csim_response (step, valid_csim_response_test_list[i].response, &error);
g_assert_no_error (error);
g_assert_cmpint (res, ==, valid_csim_response_test_list[i].result);
}
/* Test invalid responses */
for (i = 0; invalid_csim_response_test_list[i].response != NULL; i++) {
res = parse_csim_response (step, invalid_csim_response_test_list[i].response, &error);
g_assert_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED);
g_assert_cmpint (res, ==, invalid_csim_response_test_list[i].result);
if (NULL != error) {
g_error_free (error);
error = NULL;
}
}
}
int main (int argc, char **argv)
{
setlocale (LC_ALL, "");
g_type_init ();
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/MM/telit/csim", test_parse_csim_response);
return g_test_run ();
}