telit: add load_unlock_retries interface
This commit is contained in:

committed by
Aleksander Morgado

parent
7978225934
commit
c4ffe572ae
@@ -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 \
|
||||
|
@@ -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;
|
||||
|
75
plugins/telit/mm-modem-helpers-telit.c
Normal file
75
plugins/telit/mm-modem-helpers-telit.c
Normal 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;
|
||||
}
|
25
plugins/telit/mm-modem-helpers-telit.h
Normal file
25
plugins/telit/mm-modem-helpers-telit.h
Normal 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 */
|
||||
|
104
plugins/telit/tests/test-mm-modem-helpers-telit.c
Normal file
104
plugins/telit/tests/test-mm-modem-helpers-telit.c
Normal 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 ();
|
||||
}
|
Reference in New Issue
Block a user