diff options
Diffstat (limited to 'plugins/ublox/mm-modem-helpers-ublox.c')
-rw-r--r-- | plugins/ublox/mm-modem-helpers-ublox.c | 2014 |
1 files changed, 0 insertions, 2014 deletions
diff --git a/plugins/ublox/mm-modem-helpers-ublox.c b/plugins/ublox/mm-modem-helpers-ublox.c deleted file mode 100644 index 84a7cf27..00000000 --- a/plugins/ublox/mm-modem-helpers-ublox.c +++ /dev/null @@ -1,2014 +0,0 @@ -/* -*- 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) 2016 Aleksander Morgado <aleksander@aleksander.es> - */ - -#include <glib.h> -#include <string.h> - -#include "mm-log.h" -#include "mm-modem-helpers.h" -#include "mm-modem-helpers-ublox.h" - -/*****************************************************************************/ -/* +UPINCNT response parser */ - -gboolean -mm_ublox_parse_upincnt_response (const gchar *response, - guint *out_pin_attempts, - guint *out_pin2_attempts, - guint *out_puk_attempts, - guint *out_puk2_attempts, - GError **error) -{ - g_autoptr(GRegex) r = NULL; - g_autoptr(GMatchInfo) match_info = NULL; - GError *inner_error = NULL; - guint pin_attempts = 0; - guint pin2_attempts = 0; - guint puk_attempts = 0; - guint puk2_attempts = 0; - gboolean success = TRUE; - - g_assert (out_pin_attempts); - g_assert (out_pin2_attempts); - g_assert (out_puk_attempts); - g_assert (out_puk2_attempts); - - /* Response may be e.g.: - * +UPINCNT: 3,3,10,10 - */ - r = g_regex_new ("\\+UPINCNT: (\\d+),(\\d+),(\\d+),(\\d+)(?:\\r\\n)?", 0, 0, NULL); - g_assert (r != NULL); - - g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error); - if (!inner_error && g_match_info_matches (match_info)) { - if (!mm_get_uint_from_match_info (match_info, 1, &pin_attempts)) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, - "Couldn't parse PIN attempts"); - goto out; - } - if (!mm_get_uint_from_match_info (match_info, 2, &pin2_attempts)) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, - "Couldn't parse PIN2 attempts"); - goto out; - } - if (!mm_get_uint_from_match_info (match_info, 3, &puk_attempts)) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, - "Couldn't parse PUK attempts"); - goto out; - } - if (!mm_get_uint_from_match_info (match_info, 4, &puk2_attempts)) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, - "Couldn't parse PUK2 attempts"); - goto out; - } - success = TRUE; - } - -out: - - if (inner_error) { - g_propagate_error (error, inner_error); - return FALSE; - } - - if (!success) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Couldn't parse +UPINCNT response: '%s'", response); - return FALSE; - } - - *out_pin_attempts = pin_attempts; - *out_pin2_attempts = pin2_attempts; - *out_puk_attempts = puk_attempts; - *out_puk2_attempts = puk2_attempts; - return TRUE; -} - -/*****************************************************************************/ -/* UUSBCONF? response parser */ - -gboolean -mm_ublox_parse_uusbconf_response (const gchar *response, - MMUbloxUsbProfile *out_profile, - GError **error) -{ - g_autoptr(GRegex) r = NULL; - g_autoptr(GMatchInfo) match_info = NULL; - GError *inner_error = NULL; - MMUbloxUsbProfile profile = MM_UBLOX_USB_PROFILE_UNKNOWN; - - g_assert (out_profile != NULL); - - /* Response may be e.g.: - * +UUSBCONF: 3,"RNDIS",,"0x1146" - * +UUSBCONF: 2,"ECM",,"0x1143" - * +UUSBCONF: 0,"",,"0x1141" - * - * Note: we don't rely on the PID; assuming future new modules will - * have a different PID but they may keep the profile names. - */ - r = g_regex_new ("\\+UUSBCONF: (\\d+),([^,]*),([^,]*),([^,]*)(?:\\r\\n)?", 0, 0, NULL); - g_assert (r != NULL); - - g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error); - if (!inner_error && g_match_info_matches (match_info)) { - g_autofree gchar *profile_name = NULL; - - profile_name = mm_get_string_unquoted_from_match_info (match_info, 2); - if (profile_name && profile_name[0]) { - if (g_str_equal (profile_name, "RNDIS")) - profile = MM_UBLOX_USB_PROFILE_RNDIS; - else if (g_str_equal (profile_name, "ECM")) - profile = MM_UBLOX_USB_PROFILE_ECM; - else - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, - "Unknown USB profile: '%s'", profile_name); - } else - profile = MM_UBLOX_USB_PROFILE_BACK_COMPATIBLE; - } - - if (inner_error) { - g_propagate_error (error, inner_error); - return FALSE; - } - - if (profile == MM_UBLOX_USB_PROFILE_UNKNOWN) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Couldn't parse profile response"); - return FALSE; - } - - *out_profile = profile; - return TRUE; -} - -/*****************************************************************************/ -/* UBMCONF? response parser */ - -gboolean -mm_ublox_parse_ubmconf_response (const gchar *response, - MMUbloxNetworkingMode *out_mode, - GError **error) -{ - g_autoptr(GRegex) r = NULL; - g_autoptr(GMatchInfo) match_info = NULL; - GError *inner_error = NULL; - MMUbloxNetworkingMode mode = MM_UBLOX_NETWORKING_MODE_UNKNOWN; - - g_assert (out_mode != NULL); - - /* Response may be e.g.: - * +UBMCONF: 1 - * +UBMCONF: 2 - */ - r = g_regex_new ("\\+UBMCONF: (\\d+)(?:\\r\\n)?", 0, 0, NULL); - g_assert (r != NULL); - - g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error); - if (!inner_error && g_match_info_matches (match_info)) { - guint mode_id = 0; - - if (mm_get_uint_from_match_info (match_info, 1, &mode_id)) { - switch (mode_id) { - case 1: - mode = MM_UBLOX_NETWORKING_MODE_ROUTER; - break; - case 2: - mode = MM_UBLOX_NETWORKING_MODE_BRIDGE; - break; - default: - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, - "Unknown mode id: '%u'", mode_id); - break; - } - } - } - - if (inner_error) { - g_propagate_error (error, inner_error); - return FALSE; - } - - if (mode == MM_UBLOX_NETWORKING_MODE_UNKNOWN) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Couldn't parse networking mode response"); - return FALSE; - } - - *out_mode = mode; - return TRUE; -} - -/*****************************************************************************/ -/* UIPADDR=N response parser */ - -gboolean -mm_ublox_parse_uipaddr_response (const gchar *response, - guint *out_cid, - gchar **out_if_name, - gchar **out_ipv4_address, - gchar **out_ipv4_subnet, - gchar **out_ipv6_global_address, - gchar **out_ipv6_link_local_address, - GError **error) -{ - g_autoptr(GRegex) r = NULL; - g_autoptr(GMatchInfo) match_info = NULL; - GError *inner_error = NULL; - guint cid = 0; - g_autofree gchar *if_name = NULL; - g_autofree gchar *ipv4_address = NULL; - g_autofree gchar *ipv4_subnet = NULL; - g_autofree gchar *ipv6_global_address = NULL; - g_autofree gchar *ipv6_link_local_address = NULL; - - /* Response may be e.g.: - * +UIPADDR: 1,"ccinet0","5.168.120.13","255.255.255.0","","" - * +UIPADDR: 2,"ccinet1","","","2001::2:200:FF:FE00:0/64","FE80::200:FF:FE00:0/64" - * +UIPADDR: 3,"ccinet2","5.10.100.2","255.255.255.0","2001::1:200:FF:FE00:0/64","FE80::200:FF:FE00:0/64" - * - * We assume only ONE line is returned; because we request +UIPADDR with a specific N CID. - */ - r = g_regex_new ("\\+UIPADDR: (\\d+),([^,]*),([^,]*),([^,]*),([^,]*),([^,]*)(?:\\r\\n)?", 0, 0, NULL); - g_assert (r != NULL); - - g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error); - if (inner_error) { - g_propagate_error (error, inner_error); - return FALSE; - } - - if (!g_match_info_matches (match_info)) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, "Couldn't match +UIPADDR response"); - return FALSE; - } - - if (out_cid && !mm_get_uint_from_match_info (match_info, 1, &cid)) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Error parsing cid"); - return FALSE; - } - - if (out_if_name && !(if_name = mm_get_string_unquoted_from_match_info (match_info, 2))) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Error parsing interface name"); - return FALSE; - } - - /* Remaining strings are optional */ - ipv4_address = mm_get_string_unquoted_from_match_info (match_info, 3); - ipv4_subnet = mm_get_string_unquoted_from_match_info (match_info, 4); - ipv6_global_address = mm_get_string_unquoted_from_match_info (match_info, 5); - ipv6_link_local_address = mm_get_string_unquoted_from_match_info (match_info, 6); - - if (out_cid) - *out_cid = cid; - if (out_if_name) - *out_if_name = g_steal_pointer (&if_name); - if (out_ipv4_address) - *out_ipv4_address = g_steal_pointer (&ipv4_address); - if (out_ipv4_subnet) - *out_ipv4_subnet = g_steal_pointer (&ipv4_subnet); - if (out_ipv6_global_address) - *out_ipv6_global_address = g_steal_pointer (&ipv6_global_address); - if (out_ipv6_link_local_address) - *out_ipv6_link_local_address = g_steal_pointer (&ipv6_link_local_address); - return TRUE; -} - -/*****************************************************************************/ -/* CFUN? response parser */ - -gboolean -mm_ublox_parse_cfun_response (const gchar *response, - MMModemPowerState *out_state, - GError **error) -{ - guint state; - - if (!mm_3gpp_parse_cfun_query_response (response, &state, error)) - return FALSE; - - switch (state) { - case 1: - *out_state = MM_MODEM_POWER_STATE_ON; - return TRUE; - case 0: - /* minimum functionality */ - case 4: - /* airplane mode */ - case 19: - /* minimum functionality with SIM deactivated */ - *out_state = MM_MODEM_POWER_STATE_LOW; - return TRUE; - default: - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Unknown +CFUN state: %u", state); - return FALSE; - } -} - -/*****************************************************************************/ -/* URAT=? response parser */ - -/* Index of the array is the ublox-specific value */ -static const MMModemMode ublox_combinations[] = { - ( MM_MODEM_MODE_2G ), - ( MM_MODEM_MODE_2G | MM_MODEM_MODE_3G ), - ( MM_MODEM_MODE_3G ), - ( MM_MODEM_MODE_4G ), - ( MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G ), - ( MM_MODEM_MODE_2G | MM_MODEM_MODE_4G ), - ( MM_MODEM_MODE_3G | MM_MODEM_MODE_4G ), - ( MM_MODEM_MODE_4G ), - ( MM_MODEM_MODE_4G ), -}; - -GArray * -mm_ublox_parse_urat_test_response (const gchar *response, - gpointer log_object, - GError **error) -{ - GArray *combinations = NULL; - GArray *selected = NULL; - GArray *preferred = NULL; - gchar **split; - guint split_len; - GError *inner_error = NULL; - guint i; - - /* - * E.g.: - * AT+URAT=? - * +URAT: (0-6),(0,2,3) - */ - response = mm_strip_tag (response, "+URAT:"); - split = mm_split_string_groups (response); - split_len = g_strv_length (split); - if (split_len > 2 || split_len < 1) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Unexpected number of groups in +URAT=? response: %u", g_strv_length (split)); - goto out; - } - - /* The selected list must have values */ - selected = mm_parse_uint_list (split[0], &inner_error); - if (inner_error) - goto out; - - if (!selected) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "No selected RAT values given in +URAT=? response"); - goto out; - } - - /* For our purposes, the preferred list may be empty */ - preferred = mm_parse_uint_list (split[1], &inner_error); - if (inner_error) - goto out; - - /* Build array of combinations */ - combinations = g_array_new (FALSE, FALSE, sizeof (MMModemModeCombination)); - - for (i = 0; i < selected->len; i++) { - guint selected_value; - MMModemModeCombination combination; - guint j; - - selected_value = g_array_index (selected, guint, i); - if (selected_value >= G_N_ELEMENTS (ublox_combinations)) { - mm_obj_warn (log_object, "unexpected AcT value: %u", selected_value); - continue; - } - - /* Combination without any preferred */ - combination.allowed = ublox_combinations[selected_value]; - combination.preferred = MM_MODEM_MODE_NONE; - g_array_append_val (combinations, combination); - - if (mm_count_bits_set (combination.allowed) == 1) - continue; - - if (!preferred) - continue; - - for (j = 0; j < preferred->len; j++) { - guint preferred_value; - - preferred_value = g_array_index (preferred, guint, j); - if (preferred_value >= G_N_ELEMENTS (ublox_combinations)) { - mm_obj_warn (log_object, "unexpected AcT preferred value: %u", preferred_value); - continue; - } - combination.preferred = ublox_combinations[preferred_value]; - if (mm_count_bits_set (combination.preferred) != 1) { - mm_obj_warn (log_object, "AcT preferred value should be a single AcT: %u", preferred_value); - continue; - } - if (!(combination.allowed & combination.preferred)) - continue; - g_array_append_val (combinations, combination); - } - } - - if (combinations->len == 0) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "No combinations built from +URAT=? response"); - goto out; - } - -out: - g_strfreev (split); - if (selected) - g_array_unref (selected); - if (preferred) - g_array_unref (preferred); - - if (inner_error) { - if (combinations) - g_array_unref (combinations); - g_propagate_error (error, inner_error); - return NULL; - } - - return combinations; -} - -typedef struct { - const gchar *model; - SettingsUpdateMethod method; - FeatureSupport uact; - FeatureSupport ubandsel; - MMModemMode mode; - MMModemBand bands_2g[4]; - MMModemBand bands_3g[6]; - MMModemBand bands_4g[12]; -} BandConfiguration; - -static const BandConfiguration band_configuration[] = { - { - .model = "SARA-G300", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_2G, - .bands_2g = { MM_MODEM_BAND_EGSM, MM_MODEM_BAND_DCS } - }, - { - .model = "SARA-G310", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_2G, - .bands_2g = { MM_MODEM_BAND_G850, MM_MODEM_BAND_EGSM, MM_MODEM_BAND_DCS, MM_MODEM_BAND_PCS } - }, - { - .model = "SARA-G340", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_2G, - .bands_2g = { MM_MODEM_BAND_EGSM, MM_MODEM_BAND_DCS } - }, - { - .model = "SARA-G350", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_2G, - .bands_2g = { MM_MODEM_BAND_G850, MM_MODEM_BAND_EGSM, MM_MODEM_BAND_DCS, MM_MODEM_BAND_PCS } - }, - { - .model = "SARA-G450", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_2G, - .bands_2g = { MM_MODEM_BAND_G850, MM_MODEM_BAND_EGSM, MM_MODEM_BAND_DCS, MM_MODEM_BAND_PCS } - }, - { - .model = "LISA-U200", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G, - .bands_2g = { MM_MODEM_BAND_G850, MM_MODEM_BAND_EGSM, MM_MODEM_BAND_DCS, MM_MODEM_BAND_PCS }, - .bands_3g = { MM_MODEM_BAND_UTRAN_6, MM_MODEM_BAND_UTRAN_5, MM_MODEM_BAND_UTRAN_8, - MM_MODEM_BAND_UTRAN_4, MM_MODEM_BAND_UTRAN_2, MM_MODEM_BAND_UTRAN_1 } - }, - { - .model = "LISA-U201", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G, - .bands_2g = { MM_MODEM_BAND_G850, MM_MODEM_BAND_EGSM, MM_MODEM_BAND_DCS, MM_MODEM_BAND_PCS }, - .bands_3g = { MM_MODEM_BAND_UTRAN_6, MM_MODEM_BAND_UTRAN_5, MM_MODEM_BAND_UTRAN_8, - MM_MODEM_BAND_UTRAN_2, MM_MODEM_BAND_UTRAN_1 } - }, - { - .model = "LISA-U230", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G, - .bands_2g = { MM_MODEM_BAND_G850, MM_MODEM_BAND_EGSM, MM_MODEM_BAND_DCS, MM_MODEM_BAND_PCS }, - .bands_3g = { MM_MODEM_BAND_UTRAN_6, MM_MODEM_BAND_UTRAN_5, MM_MODEM_BAND_UTRAN_8, - MM_MODEM_BAND_UTRAN_4, MM_MODEM_BAND_UTRAN_2, MM_MODEM_BAND_UTRAN_1 } - }, - { - .model = "LISA-U260", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G, - .bands_2g = { MM_MODEM_BAND_G850, MM_MODEM_BAND_EGSM, MM_MODEM_BAND_DCS, MM_MODEM_BAND_PCS }, - .bands_3g = { MM_MODEM_BAND_UTRAN_5, MM_MODEM_BAND_UTRAN_2 } - }, - { - .model = "LISA-U270", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G, - .bands_2g = { MM_MODEM_BAND_G850, MM_MODEM_BAND_EGSM, MM_MODEM_BAND_DCS, MM_MODEM_BAND_PCS }, - .bands_3g = { MM_MODEM_BAND_UTRAN_8, MM_MODEM_BAND_UTRAN_1 } - }, - { - .model = "SARA-U201", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G, - .bands_2g = { MM_MODEM_BAND_G850, MM_MODEM_BAND_EGSM, MM_MODEM_BAND_DCS, MM_MODEM_BAND_PCS }, - .bands_3g = { MM_MODEM_BAND_UTRAN_6, MM_MODEM_BAND_UTRAN_5, MM_MODEM_BAND_UTRAN_8, - MM_MODEM_BAND_UTRAN_2, MM_MODEM_BAND_UTRAN_1 } - }, - { - .model = "SARA-U260", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G, - .bands_2g = { MM_MODEM_BAND_G850, MM_MODEM_BAND_PCS }, - .bands_3g = { MM_MODEM_BAND_UTRAN_5, MM_MODEM_BAND_UTRAN_2 } - }, - { - .model = "SARA-U270", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G, - .bands_2g = { MM_MODEM_BAND_EGSM, MM_MODEM_BAND_DCS }, - .bands_3g = { MM_MODEM_BAND_UTRAN_8, MM_MODEM_BAND_UTRAN_1 } - }, - { - .model = "SARA-U280", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_3G, - .bands_3g = { MM_MODEM_BAND_UTRAN_5, MM_MODEM_BAND_UTRAN_2 } - }, - { - .model = "MPCI-L201", - .method = SETTINGS_UPDATE_METHOD_CFUN, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_3G | MM_MODEM_MODE_4G, - .bands_3g = { MM_MODEM_BAND_UTRAN_5, MM_MODEM_BAND_UTRAN_2 }, - .bands_4g = { MM_MODEM_BAND_EUTRAN_2, MM_MODEM_BAND_EUTRAN_4, MM_MODEM_BAND_EUTRAN_5, - MM_MODEM_BAND_EUTRAN_13, MM_MODEM_BAND_EUTRAN_17 } - }, - { - .model = "MPCI-L200", - .method = SETTINGS_UPDATE_METHOD_CFUN, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G, - .bands_2g = { MM_MODEM_BAND_G850, MM_MODEM_BAND_EGSM, MM_MODEM_BAND_DCS, MM_MODEM_BAND_PCS }, - .bands_3g = { MM_MODEM_BAND_UTRAN_5, MM_MODEM_BAND_UTRAN_8, MM_MODEM_BAND_UTRAN_4, - MM_MODEM_BAND_UTRAN_2, MM_MODEM_BAND_UTRAN_1 }, - .bands_4g = { MM_MODEM_BAND_EUTRAN_2, MM_MODEM_BAND_EUTRAN_4, MM_MODEM_BAND_EUTRAN_5, - MM_MODEM_BAND_EUTRAN_7, MM_MODEM_BAND_EUTRAN_17 } - }, - { - .model = "MPCI-L210", - .method = SETTINGS_UPDATE_METHOD_CFUN, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G, - .bands_2g = { MM_MODEM_BAND_G850, MM_MODEM_BAND_EGSM, MM_MODEM_BAND_DCS, MM_MODEM_BAND_PCS }, - .bands_3g = { MM_MODEM_BAND_UTRAN_5, MM_MODEM_BAND_UTRAN_8, MM_MODEM_BAND_UTRAN_2, - MM_MODEM_BAND_UTRAN_1 }, - .bands_4g = { MM_MODEM_BAND_EUTRAN_1, MM_MODEM_BAND_EUTRAN_3, MM_MODEM_BAND_EUTRAN_5, - MM_MODEM_BAND_EUTRAN_7, MM_MODEM_BAND_EUTRAN_8, MM_MODEM_BAND_EUTRAN_20 } - }, - { - .model = "MPCI-L220", - .method = SETTINGS_UPDATE_METHOD_CFUN, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_3G | MM_MODEM_MODE_4G, - .bands_3g = { MM_MODEM_BAND_UTRAN_5, MM_MODEM_BAND_UTRAN_8, MM_MODEM_BAND_UTRAN_1 }, - .bands_4g = { MM_MODEM_BAND_EUTRAN_1, MM_MODEM_BAND_EUTRAN_3, MM_MODEM_BAND_EUTRAN_5, - MM_MODEM_BAND_EUTRAN_8, MM_MODEM_BAND_EUTRAN_19 } - }, - { - .model = "MPCI-L280", - .method = SETTINGS_UPDATE_METHOD_CFUN, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G, - .bands_2g = { MM_MODEM_BAND_G850, MM_MODEM_BAND_EGSM, MM_MODEM_BAND_DCS, MM_MODEM_BAND_PCS }, - .bands_3g = { MM_MODEM_BAND_UTRAN_5, MM_MODEM_BAND_UTRAN_8, MM_MODEM_BAND_UTRAN_2, - MM_MODEM_BAND_UTRAN_1 }, - .bands_4g = { MM_MODEM_BAND_EUTRAN_1, MM_MODEM_BAND_EUTRAN_3, MM_MODEM_BAND_EUTRAN_5, - MM_MODEM_BAND_EUTRAN_7, MM_MODEM_BAND_EUTRAN_8, MM_MODEM_BAND_EUTRAN_28 } - }, - { - .model = "TOBY-L200", - .method = SETTINGS_UPDATE_METHOD_CFUN, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G, - .bands_2g = { MM_MODEM_BAND_G850, MM_MODEM_BAND_EGSM, MM_MODEM_BAND_DCS, MM_MODEM_BAND_PCS }, - .bands_3g = { MM_MODEM_BAND_UTRAN_5, MM_MODEM_BAND_UTRAN_8, MM_MODEM_BAND_UTRAN_4, - MM_MODEM_BAND_UTRAN_2, MM_MODEM_BAND_UTRAN_1 }, - .bands_4g = { MM_MODEM_BAND_EUTRAN_2, MM_MODEM_BAND_EUTRAN_4, MM_MODEM_BAND_EUTRAN_5, - MM_MODEM_BAND_EUTRAN_7, MM_MODEM_BAND_EUTRAN_17 } - }, - { - .model = "TOBY-L201", - .method = SETTINGS_UPDATE_METHOD_CFUN, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_3G | MM_MODEM_MODE_4G, - .bands_3g = { MM_MODEM_BAND_UTRAN_5, MM_MODEM_BAND_UTRAN_2 }, - .bands_4g = { MM_MODEM_BAND_EUTRAN_2, MM_MODEM_BAND_EUTRAN_4, MM_MODEM_BAND_EUTRAN_5, - MM_MODEM_BAND_EUTRAN_13, MM_MODEM_BAND_EUTRAN_17 } - }, - { - .model = "TOBY-L210", - .method = SETTINGS_UPDATE_METHOD_CFUN, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G, - .bands_2g = { MM_MODEM_BAND_G850, MM_MODEM_BAND_EGSM, MM_MODEM_BAND_DCS, MM_MODEM_BAND_PCS }, - .bands_3g = { MM_MODEM_BAND_UTRAN_5, MM_MODEM_BAND_UTRAN_8, MM_MODEM_BAND_UTRAN_2, - MM_MODEM_BAND_UTRAN_1 }, - .bands_4g = { MM_MODEM_BAND_EUTRAN_1, MM_MODEM_BAND_EUTRAN_3, MM_MODEM_BAND_EUTRAN_5, - MM_MODEM_BAND_EUTRAN_7, MM_MODEM_BAND_EUTRAN_8, MM_MODEM_BAND_EUTRAN_20 } - }, - { - .model = "TOBY-L220", - .method = SETTINGS_UPDATE_METHOD_CFUN, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_3G | MM_MODEM_MODE_4G, - .bands_3g = { MM_MODEM_BAND_UTRAN_5, MM_MODEM_BAND_UTRAN_8, MM_MODEM_BAND_UTRAN_2, - MM_MODEM_BAND_UTRAN_1 }, - .bands_4g = { MM_MODEM_BAND_EUTRAN_1, MM_MODEM_BAND_EUTRAN_3, MM_MODEM_BAND_EUTRAN_5, - MM_MODEM_BAND_EUTRAN_8, MM_MODEM_BAND_EUTRAN_19 } - }, - { - .model = "TOBY-L280", - .method = SETTINGS_UPDATE_METHOD_CFUN, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G, - .bands_2g = { MM_MODEM_BAND_G850, MM_MODEM_BAND_EGSM, MM_MODEM_BAND_DCS, MM_MODEM_BAND_PCS }, - .bands_3g = { MM_MODEM_BAND_UTRAN_5, MM_MODEM_BAND_UTRAN_8, MM_MODEM_BAND_UTRAN_2, - MM_MODEM_BAND_UTRAN_1 }, - .bands_4g = { MM_MODEM_BAND_EUTRAN_1, MM_MODEM_BAND_EUTRAN_3, MM_MODEM_BAND_EUTRAN_5, - MM_MODEM_BAND_EUTRAN_7, MM_MODEM_BAND_EUTRAN_8, MM_MODEM_BAND_EUTRAN_28 } - }, - { - .model = "TOBY-L4006", - .method = SETTINGS_UPDATE_METHOD_CFUN, - .uact = FEATURE_SUPPORTED, - .ubandsel = FEATURE_UNSUPPORTED, - .mode = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G, - .bands_2g = { MM_MODEM_BAND_G850, MM_MODEM_BAND_PCS }, - .bands_3g = { MM_MODEM_BAND_UTRAN_5, MM_MODEM_BAND_UTRAN_4, MM_MODEM_BAND_UTRAN_2 }, - .bands_4g = { MM_MODEM_BAND_EUTRAN_2, MM_MODEM_BAND_EUTRAN_4, MM_MODEM_BAND_EUTRAN_5, - MM_MODEM_BAND_EUTRAN_7, MM_MODEM_BAND_EUTRAN_12, MM_MODEM_BAND_EUTRAN_13, - MM_MODEM_BAND_EUTRAN_29 } - }, - { - .model = "TOBY-L4106", - .method = SETTINGS_UPDATE_METHOD_CFUN, - .uact = FEATURE_SUPPORTED, - .ubandsel = FEATURE_UNSUPPORTED, - .mode = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G, - .bands_2g = { MM_MODEM_BAND_EGSM, MM_MODEM_BAND_DCS }, - .bands_3g = { MM_MODEM_BAND_UTRAN_8, MM_MODEM_BAND_UTRAN_1 }, - .bands_4g = { MM_MODEM_BAND_EUTRAN_1, MM_MODEM_BAND_EUTRAN_3, MM_MODEM_BAND_EUTRAN_7, - MM_MODEM_BAND_EUTRAN_8, MM_MODEM_BAND_EUTRAN_20, MM_MODEM_BAND_EUTRAN_38 } - }, - { - .model = "TOBY-L4206", - .method = SETTINGS_UPDATE_METHOD_CFUN, - .uact = FEATURE_SUPPORTED, - .ubandsel = FEATURE_UNSUPPORTED, - .mode = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G, - .bands_2g = { MM_MODEM_BAND_G850, MM_MODEM_BAND_EGSM, MM_MODEM_BAND_DCS, MM_MODEM_BAND_PCS }, - .bands_3g = { MM_MODEM_BAND_UTRAN_5, MM_MODEM_BAND_UTRAN_8, MM_MODEM_BAND_UTRAN_1 }, - .bands_4g = { MM_MODEM_BAND_EUTRAN_1, MM_MODEM_BAND_EUTRAN_3, MM_MODEM_BAND_EUTRAN_5, - MM_MODEM_BAND_EUTRAN_7, MM_MODEM_BAND_EUTRAN_8, MM_MODEM_BAND_EUTRAN_9, - MM_MODEM_BAND_EUTRAN_19, MM_MODEM_BAND_EUTRAN_28 } - }, - { - .model = "TOBY-L4906", - .method = SETTINGS_UPDATE_METHOD_CFUN, - .uact = FEATURE_SUPPORTED, - .ubandsel = FEATURE_UNSUPPORTED, - .mode = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G, - .bands_2g = { MM_MODEM_BAND_EGSM, MM_MODEM_BAND_DCS }, - .bands_3g = { MM_MODEM_BAND_UTRAN_8, MM_MODEM_BAND_UTRAN_1 }, - .bands_4g = { MM_MODEM_BAND_EUTRAN_1, MM_MODEM_BAND_EUTRAN_3, MM_MODEM_BAND_EUTRAN_39, - MM_MODEM_BAND_EUTRAN_40, MM_MODEM_BAND_EUTRAN_41 } - }, - { - .model = "TOBY-R200", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G, - .bands_2g = { MM_MODEM_BAND_G850, MM_MODEM_BAND_EGSM, MM_MODEM_BAND_DCS, MM_MODEM_BAND_PCS }, - .bands_3g = { MM_MODEM_BAND_UTRAN_5, MM_MODEM_BAND_UTRAN_8, MM_MODEM_BAND_UTRAN_2, - MM_MODEM_BAND_UTRAN_1 }, - .bands_4g = { MM_MODEM_BAND_EUTRAN_2, MM_MODEM_BAND_EUTRAN_4, MM_MODEM_BAND_EUTRAN_5, - MM_MODEM_BAND_EUTRAN_12 } - }, - { - .model = "TOBY-R202", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_3G | MM_MODEM_MODE_4G, - .bands_3g = { MM_MODEM_BAND_UTRAN_5, MM_MODEM_BAND_UTRAN_2 }, - .bands_4g = { MM_MODEM_BAND_EUTRAN_2, MM_MODEM_BAND_EUTRAN_4, MM_MODEM_BAND_EUTRAN_5, - MM_MODEM_BAND_EUTRAN_12 } - }, - { - .model = "LARA-R202", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_3G | MM_MODEM_MODE_4G, - .bands_3g = { MM_MODEM_BAND_UTRAN_5, MM_MODEM_BAND_UTRAN_2 }, - .bands_4g = { MM_MODEM_BAND_EUTRAN_2, MM_MODEM_BAND_EUTRAN_4, MM_MODEM_BAND_EUTRAN_5, - MM_MODEM_BAND_EUTRAN_12 } - }, - { - .model = "LARA-R203", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_4G, - .bands_4g = { MM_MODEM_BAND_EUTRAN_2, MM_MODEM_BAND_EUTRAN_4, MM_MODEM_BAND_EUTRAN_12 } - }, - { - .model = "LARA-R204", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_4G, - .bands_4g = { MM_MODEM_BAND_EUTRAN_4, MM_MODEM_BAND_EUTRAN_13 } - }, - { - .model = "LARA-R211", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_2G | MM_MODEM_MODE_4G, - .bands_2g = { MM_MODEM_BAND_EGSM, MM_MODEM_BAND_DCS }, - .bands_4g = { MM_MODEM_BAND_EUTRAN_3, MM_MODEM_BAND_EUTRAN_7, MM_MODEM_BAND_EUTRAN_20 } - }, - { - .model = "LARA-R280", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_3G | MM_MODEM_MODE_4G, - .bands_3g = { MM_MODEM_BAND_UTRAN_1 }, - .bands_4g = { MM_MODEM_BAND_EUTRAN_3, MM_MODEM_BAND_EUTRAN_8, MM_MODEM_BAND_EUTRAN_28 } - }, - { - .model = "LARA-R3121", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_4G, - .bands_4g = { MM_MODEM_BAND_EUTRAN_3, MM_MODEM_BAND_EUTRAN_7, MM_MODEM_BAND_EUTRAN_20 } - }, - { - .model = "SARA-N200", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_4G, - .bands_4g = { MM_MODEM_BAND_EUTRAN_8 } - }, - { - .model = "SARA-N201", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_4G, - .bands_4g = { MM_MODEM_BAND_EUTRAN_5 } - }, - { - .model = "SARA-N210", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_4G, - .bands_4g = { MM_MODEM_BAND_EUTRAN_20 } - }, - { - .model = "SARA-N211", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_4G, - .bands_4g = { MM_MODEM_BAND_EUTRAN_8, MM_MODEM_BAND_EUTRAN_20 } - }, - { - .model = "SARA-N280", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_SUPPORTED, - .mode = MM_MODEM_MODE_4G, - .bands_4g = { MM_MODEM_BAND_EUTRAN_28 } - }, - { - .model = "SARA-R410M-52B", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_UNSUPPORTED, - .mode = MM_MODEM_MODE_4G, - .bands_4g = { MM_MODEM_BAND_EUTRAN_2, MM_MODEM_BAND_EUTRAN_4, MM_MODEM_BAND_EUTRAN_5, - MM_MODEM_BAND_EUTRAN_12, MM_MODEM_BAND_EUTRAN_13 } - }, - { - .model = "SARA-R410M-02B", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_UNSUPPORTED, - .mode = MM_MODEM_MODE_4G, - .bands_4g = { MM_MODEM_BAND_EUTRAN_1, MM_MODEM_BAND_EUTRAN_2, MM_MODEM_BAND_EUTRAN_3, - MM_MODEM_BAND_EUTRAN_4, MM_MODEM_BAND_EUTRAN_5, MM_MODEM_BAND_EUTRAN_8, - MM_MODEM_BAND_EUTRAN_12, MM_MODEM_BAND_EUTRAN_13, MM_MODEM_BAND_EUTRAN_19, - MM_MODEM_BAND_EUTRAN_20, MM_MODEM_BAND_EUTRAN_28, MM_MODEM_BAND_EUTRAN_39 } - }, - { - .model = "SARA-R412M-02B", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_UNSUPPORTED, - .mode = MM_MODEM_MODE_2G | MM_MODEM_MODE_4G, - .bands_2g = { MM_MODEM_BAND_G850, MM_MODEM_BAND_EGSM, MM_MODEM_BAND_DCS, MM_MODEM_BAND_PCS }, - .bands_4g = { MM_MODEM_BAND_EUTRAN_1, MM_MODEM_BAND_EUTRAN_2, MM_MODEM_BAND_EUTRAN_3, - MM_MODEM_BAND_EUTRAN_4, MM_MODEM_BAND_EUTRAN_5, MM_MODEM_BAND_EUTRAN_8, - MM_MODEM_BAND_EUTRAN_12, MM_MODEM_BAND_EUTRAN_13, MM_MODEM_BAND_EUTRAN_19, - MM_MODEM_BAND_EUTRAN_20, MM_MODEM_BAND_EUTRAN_28, MM_MODEM_BAND_EUTRAN_39 } - }, - { - .model = "SARA-N410-02B", - .method = SETTINGS_UPDATE_METHOD_COPS, - .uact = FEATURE_UNSUPPORTED, - .ubandsel = FEATURE_UNSUPPORTED, - .mode = MM_MODEM_MODE_4G, - .bands_4g = { MM_MODEM_BAND_EUTRAN_1, MM_MODEM_BAND_EUTRAN_2, MM_MODEM_BAND_EUTRAN_3, - MM_MODEM_BAND_EUTRAN_4, MM_MODEM_BAND_EUTRAN_5, MM_MODEM_BAND_EUTRAN_8, - MM_MODEM_BAND_EUTRAN_12, MM_MODEM_BAND_EUTRAN_13, MM_MODEM_BAND_EUTRAN_19, - MM_MODEM_BAND_EUTRAN_20, MM_MODEM_BAND_EUTRAN_28 } - }, -}; - -gboolean -mm_ublox_get_support_config (const gchar *model, - UbloxSupportConfig *config, - GError **error) -{ - guint i; - - if (!model) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Support configuration unknown for unknown model"); - return FALSE; - } - - for (i = 0; i < G_N_ELEMENTS (band_configuration); i++) { - /* NOTE: matching by prefix! */ - if (g_str_has_prefix (model, band_configuration[i].model)) { - config->loaded = TRUE; - config->method = band_configuration[i].method; - config->uact = band_configuration[i].uact; - config->ubandsel = band_configuration[i].ubandsel; - return TRUE; - } - } - - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "No support configuration found for modem: %s", model); - return FALSE; -} - -/*****************************************************************************/ -/* Supported modes loading */ - -static MMModemMode -supported_modes_per_model (const gchar *model) -{ - MMModemMode mode; - guint i; - - mode = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G; - - if (model) { - for (i = 0; i < G_N_ELEMENTS (band_configuration); i++) - if (g_str_has_prefix (model, band_configuration[i].model)) { - mode = band_configuration[i].mode; - return mode;; - } - } - - return mode; -} - -GArray * -mm_ublox_filter_supported_modes (const gchar *model, - GArray *combinations, - gpointer logger, - GError **error) -{ - MMModemModeCombination mode; - GArray *all; - GArray *filtered; - - /* Model not specified? */ - if (!model) - return combinations; - - /* AT+URAT=? lies; we need an extra per-device filtering, thanks u-blox. - * Don't know all PIDs for all devices, so model string based filtering... */ - - mode.allowed = supported_modes_per_model (model); - mode.preferred = MM_MODEM_MODE_NONE; - - /* Nothing filtered? */ - if (mode.allowed == supported_modes_per_model (NULL)) - return combinations; - - all = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), 1); - g_array_append_val (all, mode); - filtered = mm_filter_supported_modes (all, combinations, logger); - g_array_unref (all); - g_array_unref (combinations); - - /* Error if nothing left */ - if (filtered->len == 0) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "No valid mode combinations built after filtering (model %s)", model); - g_array_unref (filtered); - return NULL; - } - - return filtered; -} - -/*****************************************************************************/ -/* Supported bands loading */ - -GArray * -mm_ublox_get_supported_bands (const gchar *model, - gpointer log_object, - GError **error) -{ - MMModemMode mode; - GArray *bands; - guint i, j; - - mode = supported_modes_per_model (model); - bands = g_array_new (FALSE, FALSE, sizeof (MMModemBand)); - - for (i = 0; i < G_N_ELEMENTS (band_configuration); i++) { - if (g_str_has_prefix (model, band_configuration[i].model)) { - mm_obj_dbg (log_object, "known supported bands found for model: %s", band_configuration[i].model); - break; - } - } - - if (i == G_N_ELEMENTS (band_configuration)) { - mm_obj_warn (log_object, "unknown model name given when looking for supported bands: %s", model); - return NULL; - } - - mode = band_configuration[i].mode; - - if (mode & MM_MODEM_MODE_2G) { - for (j = 0; j < G_N_ELEMENTS (band_configuration[i].bands_2g) && band_configuration[i].bands_2g[j]; j++) { - bands = g_array_append_val (bands, band_configuration[i].bands_2g[j]); - } - } - - if (mode & MM_MODEM_MODE_3G) { - for (j = 0; j < G_N_ELEMENTS (band_configuration[i].bands_3g) && band_configuration[i].bands_3g[j]; j++) { - bands = g_array_append_val (bands, band_configuration[i].bands_3g[j]); - } - } - - if (mode & MM_MODEM_MODE_4G) { - for (j = 0; j < G_N_ELEMENTS (band_configuration[i].bands_4g) && band_configuration[i].bands_4g[j]; j++) { - bands = g_array_append_val (bands, band_configuration[i].bands_4g[j]); - } - } - - if (bands->len == 0) { - g_array_unref (bands); - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "No valid supported bands loaded"); - return NULL; - } - - return bands; -} - -typedef struct { - guint num; - MMModemBand band[4]; -} NumToBand; - -/* 2G GSM Band Frequencies */ -static const NumToBand num_bands_2g [] = { - { .num = 850, .band = { MM_MODEM_BAND_G850 } }, - { .num = 900, .band = { MM_MODEM_BAND_EGSM } }, - { .num = 1900, .band = { MM_MODEM_BAND_PCS } }, - { .num = 1800, .band = { MM_MODEM_BAND_DCS } }, -}; - -/* 3G UMTS Band Frequencies */ -static const NumToBand num_bands_3g [] = { - { .num = 800, .band = { MM_MODEM_BAND_UTRAN_6 } }, - { .num = 850, .band = { MM_MODEM_BAND_UTRAN_5 } }, - { .num = 900, .band = { MM_MODEM_BAND_UTRAN_8 } }, - { .num = 1700, .band = { MM_MODEM_BAND_UTRAN_4 } }, - { .num = 1900, .band = { MM_MODEM_BAND_UTRAN_2 } }, - { .num = 2100, .band = { MM_MODEM_BAND_UTRAN_1 } }, -}; - -/* 4G LTE Band Frequencies */ -static const NumToBand num_bands_4g [] = { - { .num = 700, .band = { MM_MODEM_BAND_EUTRAN_12, MM_MODEM_BAND_EUTRAN_13, MM_MODEM_BAND_EUTRAN_17 } }, - { .num = 800, .band = { MM_MODEM_BAND_EUTRAN_20, MM_MODEM_BAND_EUTRAN_27 } }, - { .num = 850, .band = { MM_MODEM_BAND_EUTRAN_5, MM_MODEM_BAND_EUTRAN_18, MM_MODEM_BAND_EUTRAN_19, MM_MODEM_BAND_EUTRAN_26 } }, - { .num = 900, .band = { MM_MODEM_BAND_EUTRAN_8 } }, - { .num = 1700, .band = { MM_MODEM_BAND_EUTRAN_4, MM_MODEM_BAND_EUTRAN_10 } }, - { .num = 1800, .band = { MM_MODEM_BAND_EUTRAN_3 } }, - { .num = 1900, .band = { MM_MODEM_BAND_EUTRAN_2, MM_MODEM_BAND_EUTRAN_39 } }, - { .num = 2100, .band = { MM_MODEM_BAND_EUTRAN_1 } }, - { .num = 2300, .band = { MM_MODEM_BAND_EUTRAN_40 } }, - { .num = 2500, .band = { MM_MODEM_BAND_EUTRAN_41 } }, - { .num = 2600, .band = { MM_MODEM_BAND_EUTRAN_7, MM_MODEM_BAND_EUTRAN_38 } }, -}; -/*****************************************************************************/ -/* +UBANDSEL? response parser */ - -static MMModemBand -num_to_band_2g (guint num) -{ - guint i; - - for (i = 0; i < G_N_ELEMENTS (num_bands_2g); i++) { - if (num == num_bands_2g[i].num) - return num_bands_2g[i].band[0]; - } - return MM_MODEM_BAND_UNKNOWN; -} - -static MMModemBand -num_to_band_3g (guint num) -{ - guint i; - - for (i = 0; i < G_N_ELEMENTS (num_bands_3g); i++) { - if (num == num_bands_3g[i].num) - return num_bands_3g[i].band[0]; - } - return MM_MODEM_BAND_UNKNOWN; -} - -static guint -band_to_num (MMModemBand band) -{ - guint i, j; - - /* Search 2G list */ - for (i = 0; i < G_N_ELEMENTS (num_bands_2g); i++) { - for (j = 0; j < G_N_ELEMENTS (num_bands_2g[i].band) && num_bands_2g[i].band[j]; j++) { - if (band == num_bands_2g[i].band[j]) - return num_bands_2g[i].num; - } - } - - /* Search 3G list */ - for (i = 0; i < G_N_ELEMENTS (num_bands_3g); i++) { - for (j = 0; j < G_N_ELEMENTS (num_bands_3g[i].band) && num_bands_3g[i].band[j]; j++) { - if (band == num_bands_3g[i].band[j]) - return num_bands_3g[i].num; - } - } - - /* Search 4G list */ - for (i = 0; i < G_N_ELEMENTS (num_bands_4g); i++) { - for (j = 0; j < G_N_ELEMENTS (num_bands_4g[i].band) && num_bands_4g[i].band[j]; j++) { - if (band == num_bands_4g[i].band[j]) - return num_bands_4g[i].num; - } - } - - /* Should never happen */ - return 0; -} - -static void -append_bands (GArray *bands, - guint ubandsel_value, - MMModemMode mode, - const gchar *model, - gpointer log_object) -{ - guint i, j, k, x; - MMModemBand band; - - /* Find Modem Model Index in band_configuration */ - for (i = 0; i < G_N_ELEMENTS (band_configuration); i++) { - if (g_str_has_prefix (model, band_configuration[i].model)) { - mm_obj_dbg (log_object, "known bands found for model: %s", band_configuration[i].model); - break; - } - } - - if (i == G_N_ELEMENTS (band_configuration)) { - mm_obj_warn (log_object, "unknown model name given when looking for bands: %s", model); - return; - } - - if (mode & MM_MODEM_MODE_2G) { - band = num_to_band_2g (ubandsel_value); - if (band != MM_MODEM_BAND_UNKNOWN) { - for (x = 0; x < G_N_ELEMENTS (band_configuration[i].bands_2g); x++) { - if (band_configuration[i].bands_2g[x] == band) { - g_array_append_val (bands, band); - break; - } - } - } - } - - if (mode & MM_MODEM_MODE_3G) { - band = num_to_band_3g (ubandsel_value); - if (band != MM_MODEM_BAND_UNKNOWN) { - for (x = 0; x < G_N_ELEMENTS (band_configuration[i].bands_3g); x++) { - if (band_configuration[i].bands_3g[x] == band) { - g_array_append_val (bands, band); - break; - } - } - } - } - - /* Note: The weird code segment below is to separate out specific LTE bands since - * UBANDSEL? reports back the frequency of the band and not the band itself. - */ - - if (mode & MM_MODEM_MODE_4G) { - for (j = 0; j < G_N_ELEMENTS (num_bands_4g); j++) { - if (ubandsel_value == num_bands_4g[j].num) { - for (k = 0; k < G_N_ELEMENTS (num_bands_4g[j].band); k++) { - band = num_bands_4g[j].band[k]; - if (band != MM_MODEM_BAND_UNKNOWN) { - for (x = 0; x < G_N_ELEMENTS (band_configuration[i].bands_4g); x++) { - if (band_configuration[i].bands_4g[x] == band) { - g_array_append_val (bands, band); - break; - } - } - } - } - break; - } - } - } -} - -GArray * -mm_ublox_parse_ubandsel_response (const gchar *response, - const gchar *model, - gpointer log_object, - GError **error) -{ - GArray *array_values = NULL; - GArray *array = NULL; - gchar *dupstr = NULL; - GError *inner_error = NULL; - guint i; - MMModemMode mode; - - if (!g_str_has_prefix (response, "+UBANDSEL")) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Couldn't parse +UBANDSEL response: '%s'", response); - goto out; - } - - /* Response may be e.g.: - * +UBANDSEL: 850,900,1800,1900 - */ - dupstr = g_strchomp (g_strdup (mm_strip_tag (response, "+UBANDSEL:"))); - - array_values = mm_parse_uint_list (dupstr, &inner_error); - if (!array_values) - goto out; - - /* Convert list of ubandsel numbers to MMModemBand values */ - mode = supported_modes_per_model (model); - array = g_array_new (FALSE, FALSE, sizeof (MMModemBand)); - for (i = 0; i < array_values->len; i++) - append_bands (array, g_array_index (array_values, guint, i), mode, model, log_object); - - if (!array->len) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "No known band selection values matched in +UBANDSEL response: '%s'", response); - goto out; - } - -out: - if (inner_error) { - g_propagate_error (error, inner_error); - g_clear_pointer (&array, g_array_unref); - } - g_clear_pointer (&array_values, g_array_unref); - g_free (dupstr); - return array; -} - -/*****************************************************************************/ -/* UBANDSEL=X command builder */ - -static gint -ubandsel_num_cmp (const guint *a, const guint *b) -{ - return (*a - *b); -} - -gchar * -mm_ublox_build_ubandsel_set_command (GArray *bands, - const gchar *model, - GError **error) -{ - GString *command = NULL; - GArray *ubandsel_nums; - guint num; - guint i, j, k; - - if (bands->len == 1 && g_array_index (bands, MMModemBand, 0) == MM_MODEM_BAND_ANY) - return g_strdup ("+UBANDSEL=0"); - - for (i = 0; i < G_N_ELEMENTS (band_configuration); i++) { - if (g_str_has_prefix (model, band_configuration[i].model)) - break; - } - - if (i == G_N_ELEMENTS (band_configuration)) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Unknown modem model %s", model); - return NULL; - } - - ubandsel_nums = g_array_sized_new (FALSE, FALSE, sizeof (guint), bands->len); - - for (j = 0; j < bands->len; j++) { - MMModemBand band; - gboolean found = FALSE; - - band = g_array_index (bands, MMModemBand, j); - - /* Check to see if band is supported by the model */ - for (k = 0; !found && k < G_N_ELEMENTS (band_configuration[i].bands_2g) && band_configuration[i].bands_2g[k]; k++) { - if (band == band_configuration[i].bands_2g[k]) - found = TRUE; - } - - for (k = 0; !found && k < G_N_ELEMENTS (band_configuration[i].bands_3g) && band_configuration[i].bands_3g[k]; k++) { - if (band == band_configuration[i].bands_3g[k]) - found = TRUE; - } - - for (k = 0; !found && k < G_N_ELEMENTS (band_configuration[i].bands_4g) && band_configuration[i].bands_4g[k]; k++) { - if (band == band_configuration[i].bands_4g[k]) - found = TRUE; - } - - if (found) { - num = band_to_num (band); - g_assert (num != 0); - g_array_append_val (ubandsel_nums, num); - } - } - - if (ubandsel_nums->len == 0) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, - "Given band combination is unsupported"); - g_array_unref (ubandsel_nums); - return NULL; - } - - if (ubandsel_nums->len > 1) - g_array_sort (ubandsel_nums, (GCompareFunc) ubandsel_num_cmp); - - /* Build command */ - command = g_string_new ("+UBANDSEL="); - for (i = 0; i < ubandsel_nums->len; i++) - g_string_append_printf (command, "%s%u", i == 0 ? "" : ",", g_array_index (ubandsel_nums, guint, i)); - - return g_string_free (command, FALSE); -} - -/*****************************************************************************/ -/* Get mode to apply when ANY */ - -MMModemMode -mm_ublox_get_modem_mode_any (const GArray *combinations) -{ - guint i; - MMModemMode any = MM_MODEM_MODE_NONE; - guint any_bits_set = 0; - - for (i = 0; i < combinations->len; i++) { - MMModemModeCombination *combination; - guint bits_set; - - combination = &g_array_index (combinations, MMModemModeCombination, i); - if (combination->preferred != MM_MODEM_MODE_NONE) - continue; - bits_set = mm_count_bits_set (combination->allowed); - if (bits_set > any_bits_set) { - any_bits_set = bits_set; - any = combination->allowed; - } - } - - /* If combinations were processed via mm_ublox_parse_urat_test_response(), - * we're sure that there will be at least one combination with preferred - * 'none', so there must be some valid combination as result */ - g_assert (any != MM_MODEM_MODE_NONE); - return any; -} - -/*****************************************************************************/ -/* UACT common config */ - -typedef struct { - guint num; - MMModemBand band; -} UactBandConfig; - -static const UactBandConfig uact_band_config[] = { - /* GSM bands */ - { .num = 900, .band = MM_MODEM_BAND_EGSM }, - { .num = 1800, .band = MM_MODEM_BAND_DCS }, - { .num = 1900, .band = MM_MODEM_BAND_PCS }, - { .num = 850, .band = MM_MODEM_BAND_G850 }, - { .num = 450, .band = MM_MODEM_BAND_G450 }, - { .num = 480, .band = MM_MODEM_BAND_G480 }, - { .num = 750, .band = MM_MODEM_BAND_G750 }, - { .num = 380, .band = MM_MODEM_BAND_G380 }, - { .num = 410, .band = MM_MODEM_BAND_G410 }, - { .num = 710, .band = MM_MODEM_BAND_G710 }, - { .num = 810, .band = MM_MODEM_BAND_G810 }, - /* UMTS bands */ - { .num = 1, .band = MM_MODEM_BAND_UTRAN_1 }, - { .num = 2, .band = MM_MODEM_BAND_UTRAN_2 }, - { .num = 3, .band = MM_MODEM_BAND_UTRAN_3 }, - { .num = 4, .band = MM_MODEM_BAND_UTRAN_4 }, - { .num = 5, .band = MM_MODEM_BAND_UTRAN_5 }, - { .num = 6, .band = MM_MODEM_BAND_UTRAN_6 }, - { .num = 7, .band = MM_MODEM_BAND_UTRAN_7 }, - { .num = 8, .band = MM_MODEM_BAND_UTRAN_8 }, - { .num = 9, .band = MM_MODEM_BAND_UTRAN_9 }, - { .num = 10, .band = MM_MODEM_BAND_UTRAN_10 }, - { .num = 11, .band = MM_MODEM_BAND_UTRAN_11 }, - { .num = 12, .band = MM_MODEM_BAND_UTRAN_12 }, - { .num = 13, .band = MM_MODEM_BAND_UTRAN_13 }, - { .num = 14, .band = MM_MODEM_BAND_UTRAN_14 }, - { .num = 19, .band = MM_MODEM_BAND_UTRAN_19 }, - { .num = 20, .band = MM_MODEM_BAND_UTRAN_20 }, - { .num = 21, .band = MM_MODEM_BAND_UTRAN_21 }, - { .num = 22, .band = MM_MODEM_BAND_UTRAN_22 }, - { .num = 25, .band = MM_MODEM_BAND_UTRAN_25 }, - /* LTE bands */ - { .num = 101, .band = MM_MODEM_BAND_EUTRAN_1 }, - { .num = 102, .band = MM_MODEM_BAND_EUTRAN_2 }, - { .num = 103, .band = MM_MODEM_BAND_EUTRAN_3 }, - { .num = 104, .band = MM_MODEM_BAND_EUTRAN_4 }, - { .num = 105, .band = MM_MODEM_BAND_EUTRAN_5 }, - { .num = 106, .band = MM_MODEM_BAND_EUTRAN_6 }, - { .num = 107, .band = MM_MODEM_BAND_EUTRAN_7 }, - { .num = 108, .band = MM_MODEM_BAND_EUTRAN_8 }, - { .num = 109, .band = MM_MODEM_BAND_EUTRAN_9 }, - { .num = 110, .band = MM_MODEM_BAND_EUTRAN_10 }, - { .num = 111, .band = MM_MODEM_BAND_EUTRAN_11 }, - { .num = 112, .band = MM_MODEM_BAND_EUTRAN_12 }, - { .num = 113, .band = MM_MODEM_BAND_EUTRAN_13 }, - { .num = 114, .band = MM_MODEM_BAND_EUTRAN_14 }, - { .num = 117, .band = MM_MODEM_BAND_EUTRAN_17 }, - { .num = 118, .band = MM_MODEM_BAND_EUTRAN_18 }, - { .num = 119, .band = MM_MODEM_BAND_EUTRAN_19 }, - { .num = 120, .band = MM_MODEM_BAND_EUTRAN_20 }, - { .num = 121, .band = MM_MODEM_BAND_EUTRAN_21 }, - { .num = 122, .band = MM_MODEM_BAND_EUTRAN_22 }, - { .num = 123, .band = MM_MODEM_BAND_EUTRAN_23 }, - { .num = 124, .band = MM_MODEM_BAND_EUTRAN_24 }, - { .num = 125, .band = MM_MODEM_BAND_EUTRAN_25 }, - { .num = 126, .band = MM_MODEM_BAND_EUTRAN_26 }, - { .num = 127, .band = MM_MODEM_BAND_EUTRAN_27 }, - { .num = 128, .band = MM_MODEM_BAND_EUTRAN_28 }, - { .num = 129, .band = MM_MODEM_BAND_EUTRAN_29 }, - { .num = 130, .band = MM_MODEM_BAND_EUTRAN_30 }, - { .num = 131, .band = MM_MODEM_BAND_EUTRAN_31 }, - { .num = 132, .band = MM_MODEM_BAND_EUTRAN_32 }, - { .num = 133, .band = MM_MODEM_BAND_EUTRAN_33 }, - { .num = 134, .band = MM_MODEM_BAND_EUTRAN_34 }, - { .num = 135, .band = MM_MODEM_BAND_EUTRAN_35 }, - { .num = 136, .band = MM_MODEM_BAND_EUTRAN_36 }, - { .num = 137, .band = MM_MODEM_BAND_EUTRAN_37 }, - { .num = 138, .band = MM_MODEM_BAND_EUTRAN_38 }, - { .num = 139, .band = MM_MODEM_BAND_EUTRAN_39 }, - { .num = 140, .band = MM_MODEM_BAND_EUTRAN_40 }, - { .num = 141, .band = MM_MODEM_BAND_EUTRAN_41 }, - { .num = 142, .band = MM_MODEM_BAND_EUTRAN_42 }, - { .num = 143, .band = MM_MODEM_BAND_EUTRAN_43 }, - { .num = 144, .band = MM_MODEM_BAND_EUTRAN_44 }, - { .num = 145, .band = MM_MODEM_BAND_EUTRAN_45 }, - { .num = 146, .band = MM_MODEM_BAND_EUTRAN_46 }, - { .num = 147, .band = MM_MODEM_BAND_EUTRAN_47 }, - { .num = 148, .band = MM_MODEM_BAND_EUTRAN_48 }, -}; - -static MMModemBand -uact_num_to_band (guint num) -{ - guint i; - - for (i = 0; i < G_N_ELEMENTS (uact_band_config); i++) { - if (num == uact_band_config[i].num) - return uact_band_config[i].band; - } - return MM_MODEM_BAND_UNKNOWN; -} - -static guint -uact_band_to_num (MMModemBand band) -{ - guint i; - - for (i = 0; i < G_N_ELEMENTS (uact_band_config); i++) { - if (band == uact_band_config[i].band) - return uact_band_config[i].num; - } - return 0; -} - -/*****************************************************************************/ -/* UACT? response parser */ - -static GArray * -uact_num_array_to_band_array (GArray *nums) -{ - GArray *bands = NULL; - guint i; - - if (!nums) - return NULL; - - bands = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), nums->len); - for (i = 0; i < nums->len; i++) { - MMModemBand band; - - band = uact_num_to_band (g_array_index (nums, guint, i)); - g_array_append_val (bands, band); - } - - return bands; -} - -GArray * -mm_ublox_parse_uact_response (const gchar *response, - GError **error) -{ - g_autoptr(GRegex) r = NULL; - g_autoptr(GMatchInfo) match_info = NULL; - GError *inner_error = NULL; - GArray *nums = NULL; - GArray *bands = NULL; - - /* - * AT+UACT? - * +UACT: ,,,900,1800,1,8,101,103,107,108,120,138 - */ - r = g_regex_new ("\\+UACT: ([^,]*),([^,]*),([^,]*),(.*)(?:\\r\\n)?", - G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW, 0, NULL); - g_assert (r != NULL); - - g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error); - if (!inner_error && g_match_info_matches (match_info)) { - g_autofree gchar *bandstr = NULL; - - bandstr = mm_get_string_unquoted_from_match_info (match_info, 4); - nums = mm_parse_uint_list (bandstr, &inner_error); - } - - if (inner_error) { - g_propagate_error (error, inner_error); - return NULL; - } - - /* Convert to MMModemBand values */ - if (nums) { - bands = uact_num_array_to_band_array (nums); - g_array_unref (nums); - } - - if (!bands) - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "No known band selection values matched in +UACT response: '%s'", response); - - return bands; -} - -/*****************************************************************************/ -/* UACT=? response parser */ - -static GArray * -parse_bands_from_string (const gchar *str, - const gchar *group, - gpointer log_object) -{ - GArray *bands = NULL; - GError *inner_error = NULL; - GArray *nums; - - nums = mm_parse_uint_list (str, &inner_error); - if (nums) { - gchar *tmpstr; - - bands = uact_num_array_to_band_array (nums); - tmpstr = mm_common_build_bands_string ((MMModemBand *)(gpointer)(bands->data), bands->len); - mm_obj_dbg (log_object, "modem reports support for %s bands: %s", group, tmpstr); - g_free (tmpstr); - - g_array_unref (nums); - } else if (inner_error) { - mm_obj_warn (log_object, "couldn't parse list of supported %s bands: %s", group, inner_error->message); - g_clear_error (&inner_error); - } - - return bands; -} - -gboolean -mm_ublox_parse_uact_test (const gchar *response, - gpointer log_object, - GArray **bands2g_out, - GArray **bands3g_out, - GArray **bands4g_out, - GError **error) -{ - g_autoptr(GRegex) r = NULL; - g_autoptr(GMatchInfo) match_info = NULL; - g_auto(GStrv) split = NULL; - GError *inner_error = NULL; - const gchar *bands2g_str = NULL; - const gchar *bands3g_str = NULL; - const gchar *bands4g_str = NULL; - GArray *bands2g = NULL; - GArray *bands3g = NULL; - GArray *bands4g = NULL; - - g_assert (bands2g_out && bands3g_out && bands4g_out); - - /* - * AT+UACT=? - * +UACT: ,,,(900,1800),(1,8),(101,103,107,108,120),(138) - */ - r = g_regex_new ("\\+UACT: ([^,]*),([^,]*),([^,]*),(.*)(?:\\r\\n)?", - G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW, 0, NULL); - g_assert (r != NULL); - - g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error); - if (inner_error) - goto out; - - if (g_match_info_matches (match_info)) { - g_autofree gchar *aux = NULL; - guint n_groups; - - aux = mm_get_string_unquoted_from_match_info (match_info, 4); - split = mm_split_string_groups (aux); - n_groups = g_strv_length (split); - if (n_groups >= 1) - bands2g_str = split[0]; - if (n_groups >= 2) - bands3g_str = split[1]; - if (n_groups >= 3) - bands4g_str = split[2]; - } - - if (!bands2g_str && !bands3g_str && !bands4g_str) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "frequency groups not found: %s", response); - goto out; - } - - bands2g = parse_bands_from_string (bands2g_str, "2G", log_object); - bands3g = parse_bands_from_string (bands3g_str, "3G", log_object); - bands4g = parse_bands_from_string (bands4g_str, "4G", log_object); - - if (!bands2g->len && !bands3g->len && !bands4g->len) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "no supported frequencies reported: %s", response); - goto out; - } - - /* success */ - -out: - if (inner_error) { - if (bands2g) - g_array_unref (bands2g); - if (bands3g) - g_array_unref (bands3g); - if (bands4g) - g_array_unref (bands4g); - g_propagate_error (error, inner_error); - return FALSE; - } - - *bands2g_out = bands2g; - *bands3g_out = bands3g; - *bands4g_out = bands4g; - return TRUE; -} - -/*****************************************************************************/ -/* UACT=X command builder */ - -gchar * -mm_ublox_build_uact_set_command (GArray *bands, - GError **error) -{ - GString *command; - - /* Build command */ - command = g_string_new ("+UACT=,,,"); - - if (bands->len == 1 && g_array_index (bands, MMModemBand, 0) == MM_MODEM_BAND_ANY) - g_string_append (command, "0"); - else { - guint i; - - for (i = 0; i < bands->len; i++) { - MMModemBand band; - guint num; - - band = g_array_index (bands, MMModemBand, i); - num = uact_band_to_num (band); - if (!num) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, - "Band unsupported by this plugin: %s", mm_modem_band_get_string (band)); - g_string_free (command, TRUE); - return NULL; - } - - g_string_append_printf (command, "%s%u", i == 0 ? "" : ",", num); - } - } - - return g_string_free (command, FALSE); -} - -/*****************************************************************************/ -/* URAT? response parser */ - -gboolean -mm_ublox_parse_urat_read_response (const gchar *response, - gpointer log_object, - MMModemMode *out_allowed, - MMModemMode *out_preferred, - GError **error) -{ - g_autoptr(GRegex) r = NULL; - g_autoptr(GMatchInfo) match_info = NULL; - GError *inner_error = NULL; - MMModemMode allowed = MM_MODEM_MODE_NONE; - MMModemMode preferred = MM_MODEM_MODE_NONE; - g_autofree gchar *allowed_str = NULL; - g_autofree gchar *preferred_str = NULL; - - g_assert (out_allowed != NULL && out_preferred != NULL); - - /* Response may be e.g.: - * +URAT: 1,2 - * +URAT: 1 - */ - r = g_regex_new ("\\+URAT: (\\d+)(?:,(\\d+))?(?:\\r\\n)?", 0, 0, NULL); - g_assert (r != NULL); - - g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error); - if (!inner_error && g_match_info_matches (match_info)) { - guint value = 0; - - /* Selected item is mandatory */ - if (!mm_get_uint_from_match_info (match_info, 1, &value)) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Couldn't read AcT selected value"); - goto out; - } - if (value >= G_N_ELEMENTS (ublox_combinations)) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Unexpected AcT selected value: %u", value); - goto out; - } - allowed = ublox_combinations[value]; - allowed_str = mm_modem_mode_build_string_from_mask (allowed); - mm_obj_dbg (log_object, "current allowed modes retrieved: %s", allowed_str); - - /* Preferred item is optional */ - if (mm_get_uint_from_match_info (match_info, 2, &value)) { - if (value >= G_N_ELEMENTS (ublox_combinations)) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Unexpected AcT preferred value: %u", value); - goto out; - } - preferred = ublox_combinations[value]; - preferred_str = mm_modem_mode_build_string_from_mask (preferred); - mm_obj_dbg (log_object, "current preferred modes retrieved: %s", preferred_str); - if (mm_count_bits_set (preferred) != 1) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "AcT preferred value should be a single AcT: %s", preferred_str); - goto out; - } - if (!(allowed & preferred)) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "AcT preferred value (%s) not a subset of the allowed value (%s)", - preferred_str, allowed_str); - goto out; - } - } - } - -out: - if (inner_error) { - g_propagate_error (error, inner_error); - return FALSE; - } - - if (allowed == MM_MODEM_MODE_NONE) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Couldn't parse +URAT response: %s", response); - return FALSE; - } - - *out_allowed = allowed; - *out_preferred = preferred; - return TRUE; -} - -/*****************************************************************************/ -/* URAT=X command builder */ - -static gboolean -append_rat_value (GString *str, - MMModemMode mode, - GError **error) -{ - guint i; - - for (i = 0; i < G_N_ELEMENTS (ublox_combinations); i++) { - if (ublox_combinations[i] == mode) { - g_string_append_printf (str, "%u", i); - return TRUE; - } - } - - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "No AcT value matches requested mode"); - return FALSE; -} - -gchar * -mm_ublox_build_urat_set_command (MMModemMode allowed, - MMModemMode preferred, - GError **error) -{ - GString *command; - - command = g_string_new ("+URAT="); - if (!append_rat_value (command, allowed, error)) { - g_string_free (command, TRUE); - return NULL; - } - - if (preferred != MM_MODEM_MODE_NONE) { - g_string_append (command, ","); - if (!append_rat_value (command, preferred, error)) { - g_string_free (command, TRUE); - return NULL; - } - } - - return g_string_free (command, FALSE); -} - -/*****************************************************************************/ -/* +UAUTHREQ=? test parser */ - -MMUbloxBearerAllowedAuth -mm_ublox_parse_uauthreq_test (const char *response, - gpointer log_object, - GError **error) -{ - MMUbloxBearerAllowedAuth mask = MM_UBLOX_BEARER_ALLOWED_AUTH_UNKNOWN; - GError *inner_error = NULL; - GArray *allowed_auths = NULL; - gchar **split; - guint split_len; - - /* - * Response may be like: - * AT+UAUTHREQ=? - * +UAUTHREQ: (1-4),(0-2),, - */ - response = mm_strip_tag (response, "+UAUTHREQ:"); - split = mm_split_string_groups (response); - split_len = g_strv_length (split); - if (split_len < 2) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Unexpected number of groups in +UAUTHREQ=? response: %u", g_strv_length (split)); - goto out; - } - - allowed_auths = mm_parse_uint_list (split[1], &inner_error); - if (inner_error) - goto out; - - if (allowed_auths) { - guint i; - - for (i = 0; i < allowed_auths->len; i++) { - guint val; - - val = g_array_index (allowed_auths, guint, i); - switch (val) { - case 0: - mask |= MM_UBLOX_BEARER_ALLOWED_AUTH_NONE; - break; - case 1: - mask |= MM_UBLOX_BEARER_ALLOWED_AUTH_PAP; - break; - case 2: - mask |= MM_UBLOX_BEARER_ALLOWED_AUTH_CHAP; - break; - case 3: - mask |= MM_UBLOX_BEARER_ALLOWED_AUTH_AUTO; - break; - default: - mm_obj_warn (log_object, "unexpected +UAUTHREQ value: %u", val); - break; - } - } - } - - if (!mask) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "No supported authentication methods in +UAUTHREQ=? response"); - goto out; - } - -out: - g_strfreev (split); - - if (allowed_auths) - g_array_unref (allowed_auths); - - if (inner_error) { - g_propagate_error (error, inner_error); - return MM_UBLOX_BEARER_ALLOWED_AUTH_UNKNOWN; - } - - return mask; -} - -/*****************************************************************************/ -/* +UGCNTRD response parser */ - -gboolean -mm_ublox_parse_ugcntrd_response_for_cid (const gchar *response, - guint in_cid, - guint64 *out_session_tx_bytes, - guint64 *out_session_rx_bytes, - guint64 *out_total_tx_bytes, - guint64 *out_total_rx_bytes, - GError **error) -{ - g_autoptr(GRegex) r = NULL; - g_autoptr(GMatchInfo) match_info = NULL; - GError *inner_error = NULL; - guint64 session_tx_bytes = 0; - guint64 session_rx_bytes = 0; - guint64 total_tx_bytes = 0; - guint64 total_rx_bytes = 0; - gboolean matched = FALSE; - - /* Response may be e.g.: - * +UGCNTRD: 31,2704,1819,2724,1839 - * We assume only ONE line is returned. - */ - r = g_regex_new ("\\+UGCNTRD:\\s*(\\d+),\\s*(\\d+),\\s*(\\d+),\\s*(\\d+),\\s*(\\d+)", - G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW, 0, NULL); - g_assert (r != NULL); - - /* Report invalid CID given */ - if (!in_cid) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Invalid CID given"); - goto out; - } - - g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error); - while (!inner_error && g_match_info_matches (match_info)) { - guint cid = 0; - - /* Matched CID? */ - if (!mm_get_uint_from_match_info (match_info, 1, &cid) || cid != in_cid) { - g_match_info_next (match_info, &inner_error); - continue; - } - - if (out_session_tx_bytes && !mm_get_u64_from_match_info (match_info, 2, &session_tx_bytes)) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Error parsing session TX bytes"); - goto out; - } - - if (out_session_rx_bytes && !mm_get_u64_from_match_info (match_info, 3, &session_rx_bytes)) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Error parsing session RX bytes"); - goto out; - } - - if (out_total_tx_bytes && !mm_get_u64_from_match_info (match_info, 4, &total_tx_bytes)) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Error parsing total TX bytes"); - goto out; - } - - if (out_total_rx_bytes && !mm_get_u64_from_match_info (match_info, 5, &total_rx_bytes)) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Error parsing total RX bytes"); - goto out; - } - - matched = TRUE; - break; - } - - if (!matched) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "No statistics found for CID %u", in_cid); - goto out; - } - -out: - if (inner_error) { - g_propagate_error (error, inner_error); - return FALSE; - } - - if (out_session_tx_bytes) - *out_session_tx_bytes = session_tx_bytes; - if (out_session_rx_bytes) - *out_session_rx_bytes = session_rx_bytes; - if (out_total_tx_bytes) - *out_total_tx_bytes = total_tx_bytes; - if (out_total_rx_bytes) - *out_total_rx_bytes = total_rx_bytes; - return TRUE; -} |