sim: load emergency numbers from EF_ECC
This commit is contained in:
@@ -973,7 +973,84 @@ mm_base_sim_get_path (MMBaseSim *self)
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* SIM IDENTIFIER */
|
||||
/* Emergency numbers */
|
||||
|
||||
static GStrv
|
||||
parse_emergency_numbers (const gchar *response,
|
||||
GError **error)
|
||||
{
|
||||
guint sw1 = 0;
|
||||
guint sw2 = 0;
|
||||
gchar *hex = 0;
|
||||
GStrv ret;
|
||||
|
||||
if (!mm_3gpp_parse_crsm_response (response, &sw1, &sw2, &hex, error))
|
||||
return NULL;
|
||||
|
||||
if ((sw1 == 0x90 && sw2 == 0x00) ||
|
||||
(sw1 == 0x91) ||
|
||||
(sw1 == 0x92) ||
|
||||
(sw1 == 0x9f)) {
|
||||
ret = mm_3gpp_parse_emergency_numbers (hex, error);
|
||||
g_free (hex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
g_free (hex);
|
||||
g_set_error (error,
|
||||
MM_CORE_ERROR,
|
||||
MM_CORE_ERROR_FAILED,
|
||||
"SIM failed to handle CRSM request (sw1 %d sw2 %d)",
|
||||
sw1, sw2);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GStrv
|
||||
load_emergency_numbers_finish (MMBaseSim *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
gchar *result;
|
||||
GStrv emergency_numbers;
|
||||
guint i;
|
||||
|
||||
result = g_task_propagate_pointer (G_TASK (res), error);
|
||||
if (!result)
|
||||
return NULL;
|
||||
|
||||
emergency_numbers = parse_emergency_numbers (result, error);
|
||||
g_free (result);
|
||||
|
||||
if (!emergency_numbers)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; emergency_numbers[i]; i++)
|
||||
mm_dbg ("loaded emergency number: %s", emergency_numbers[i]);
|
||||
|
||||
return emergency_numbers;
|
||||
}
|
||||
|
||||
STR_REPLY_READY_FN (load_emergency_numbers)
|
||||
|
||||
static void
|
||||
load_emergency_numbers (MMBaseSim *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
mm_dbg ("loading emergency numbers...");
|
||||
|
||||
/* READ BINARY of EF_ECC (Emergency Call Codes) ETSI TS 51.011 section 10.3.27 */
|
||||
mm_base_modem_at_command (
|
||||
self->priv->modem,
|
||||
"+CRSM=176,28599,0,0,15",
|
||||
20,
|
||||
FALSE,
|
||||
(GAsyncReadyCallback)load_emergency_numbers_command_ready,
|
||||
g_task_new (self, NULL, callback, user_data));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* ICCID */
|
||||
|
||||
static gchar *
|
||||
parse_iccid (const gchar *response,
|
||||
@@ -1784,6 +1861,8 @@ mm_base_sim_class_init (MMBaseSimClass *klass)
|
||||
klass->load_operator_identifier_finish = load_operator_identifier_finish;
|
||||
klass->load_operator_name = load_operator_name;
|
||||
klass->load_operator_name_finish = load_operator_name_finish;
|
||||
klass->load_emergency_numbers = load_emergency_numbers;
|
||||
klass->load_emergency_numbers_finish = load_emergency_numbers_finish;
|
||||
klass->send_pin = send_pin;
|
||||
klass->send_pin_finish = common_send_pin_puk_finish;
|
||||
klass->send_puk = send_puk;
|
||||
|
@@ -4352,6 +4352,70 @@ mm_3gpp_parse_operator_id (const gchar *operator_id,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
/* Emergency numbers (+CRSM output) */
|
||||
|
||||
GStrv
|
||||
mm_3gpp_parse_emergency_numbers (const char *raw, GError **error)
|
||||
{
|
||||
gsize rawlen;
|
||||
guint8 *bin;
|
||||
gsize binlen;
|
||||
gsize max_items;
|
||||
GPtrArray *out;
|
||||
guint i;
|
||||
|
||||
/* The emergency call code is of a variable length with a maximum length of
|
||||
* 6 digits. Each emergency call code is coded on three bytes, with each
|
||||
* digit within the code being coded on four bits. If a code of less that 6
|
||||
* digits is chosen, then the unused nibbles shall be set to 'F'. */
|
||||
|
||||
rawlen = strlen (raw);
|
||||
if (!rawlen) {
|
||||
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
|
||||
"empty emergency numbers list");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (rawlen % 6 != 0) {
|
||||
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
|
||||
"invalid raw emergency numbers list length: %" G_GSIZE_FORMAT, rawlen);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bin = (guint8 *) mm_utils_hexstr2bin (raw, &binlen);
|
||||
if (!bin) {
|
||||
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
|
||||
"invalid raw emergency numbers list contents: %s", raw);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
max_items = binlen / 3;
|
||||
out = g_ptr_array_sized_new (max_items + 1);
|
||||
|
||||
for (i = 0; i < max_items; i++) {
|
||||
gchar *number;
|
||||
|
||||
number = mm_bcd_to_string (&bin[i*3], 3);
|
||||
if (number && number[0])
|
||||
g_ptr_array_add (out, number);
|
||||
else
|
||||
g_free (number);
|
||||
}
|
||||
|
||||
g_free (bin);
|
||||
|
||||
if (!out->len) {
|
||||
g_ptr_array_unref (out);
|
||||
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
|
||||
"uninitialized emergency numbers list");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_ptr_array_add (out, NULL);
|
||||
return (GStrv) g_ptr_array_free (out, FALSE);
|
||||
}
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
gboolean
|
||||
|
@@ -445,6 +445,8 @@ gboolean mm_3gpp_rsrp_level_to_rsrp (guint rsrp_level,
|
||||
gboolean mm_3gpp_rssnr_level_to_rssnr (gint rssnr_level,
|
||||
gdouble *out_rssnr);
|
||||
|
||||
GStrv mm_3gpp_parse_emergency_numbers (const char *raw, GError **error);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* CDMA specific helpers and utilities */
|
||||
/*****************************************************************************/
|
||||
|
@@ -4337,6 +4337,55 @@ test_clcc_response_multiple (void)
|
||||
common_test_clcc_response (response, expected_call_info_list, G_N_ELEMENTS (expected_call_info_list));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Test +CRSM EF_ECC read data parsing */
|
||||
|
||||
#define MAX_EMERGENCY_NUMBERS 5
|
||||
typedef struct {
|
||||
const gchar *raw;
|
||||
guint n_numbers;
|
||||
gchar *numbers[MAX_EMERGENCY_NUMBERS];
|
||||
} EmergencyNumbersTest;
|
||||
|
||||
static const EmergencyNumbersTest emergency_numbers_tests[] = {
|
||||
{ "", 0 },
|
||||
{ "FFF", 0 },
|
||||
{ "FFFFFF" "FFFFFF" "FFFFFF" "FFFFFF" "FFFFFF", 0 },
|
||||
{ "00F0FF" "11F2FF" "88F8FF", 3, { "000", "112", "888" } },
|
||||
{ "00F0FF" "11F2FF" "88F8FF" "FFFFFF" "FFFFFF", 3, { "000", "112", "888" } },
|
||||
{ "00F0FF" "11F2FF" "88F8FF" "214365" "08FFFF", 5, { "000", "112", "888", "123456", "80" } },
|
||||
};
|
||||
|
||||
static void
|
||||
test_emergency_numbers (void)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < G_N_ELEMENTS (emergency_numbers_tests); i++) {
|
||||
GStrv numbers;
|
||||
GError *error = NULL;
|
||||
guint j;
|
||||
|
||||
g_debug (" testing %s...", emergency_numbers_tests[i].raw);
|
||||
|
||||
numbers = mm_3gpp_parse_emergency_numbers (emergency_numbers_tests[i].raw, &error);
|
||||
if (!emergency_numbers_tests[i].n_numbers) {
|
||||
g_assert (error);
|
||||
g_assert (!numbers);
|
||||
continue;
|
||||
}
|
||||
|
||||
g_assert_no_error (error);
|
||||
g_assert (numbers);
|
||||
|
||||
g_assert_cmpuint (emergency_numbers_tests[i].n_numbers, ==, g_strv_length (numbers));
|
||||
for (j = 0; j < emergency_numbers_tests[i].n_numbers; j++)
|
||||
g_assert_cmpstr (emergency_numbers_tests[i].numbers[j], ==, numbers[j]);
|
||||
|
||||
g_strfreev (numbers);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
@@ -4659,6 +4708,8 @@ int main (int argc, char **argv)
|
||||
g_test_suite_add (suite, TESTCASE (test_clcc_response_single_long, NULL));
|
||||
g_test_suite_add (suite, TESTCASE (test_clcc_response_multiple, NULL));
|
||||
|
||||
g_test_suite_add (suite, TESTCASE (test_emergency_numbers, NULL));
|
||||
|
||||
g_test_suite_add (suite, TESTCASE (test_parse_uint_list, NULL));
|
||||
|
||||
g_test_suite_add (suite, TESTCASE (test_bcd_to_string, NULL));
|
||||
|
Reference in New Issue
Block a user