aboutsummaryrefslogtreecommitdiff
path: root/plugins/cinterion/mm-modem-helpers-cinterion.c
diff options
context:
space:
mode:
authorGiacinto Cifelli <gciofono@gmail.com>2020-05-19 11:09:26 +0200
committerAleksander Morgado <aleksander@aleksander.es>2020-05-26 15:05:52 +0200
commit793132d56d346ea1968c92c67156f3d8759bd395 (patch)
tree4a46237d24358dea22bfe8a50736e824569eb653 /plugins/cinterion/mm-modem-helpers-cinterion.c
parent09260311196c110493dd1d713d7341f3a2c02c14 (diff)
cinterion: radio/band handling for LTE modems
Diffstat (limited to 'plugins/cinterion/mm-modem-helpers-cinterion.c')
-rw-r--r--plugins/cinterion/mm-modem-helpers-cinterion.c495
1 files changed, 393 insertions, 102 deletions
diff --git a/plugins/cinterion/mm-modem-helpers-cinterion.c b/plugins/cinterion/mm-modem-helpers-cinterion.c
index 1bc43c61..6a1364ae 100644
--- a/plugins/cinterion/mm-modem-helpers-cinterion.c
+++ b/plugins/cinterion/mm-modem-helpers-cinterion.c
@@ -37,6 +37,12 @@ typedef struct {
MMModemBand mm_band;
} CinterionBand;
+typedef struct {
+ MMCinterionRbBlock cinterion_band_block;
+ guint32 cinterion_band_flag;
+ MMModemBand mm_band;
+} CinterionBandEx;
+
/* Table checked in PLS8-X/E/J/V/US, HC25 & PHS8 references. The table includes 2/3/4G
* frequencies. Depending on which one is configured, one access technology or
* the other will be used. This may conflict with the allowed mode configuration
@@ -68,6 +74,68 @@ static const CinterionBand cinterion_bands[] = {
{ (1 << 24), MM_MODEM_BAND_EUTRAN_19 }
};
+static const CinterionBandEx cinterion_bands_ex[] = {
+ { MM_CINTERION_RB_BLOCK_GSM, 0x00000001, MM_MODEM_BAND_EGSM },
+ { MM_CINTERION_RB_BLOCK_GSM, 0x00000002, MM_MODEM_BAND_DCS },
+ { MM_CINTERION_RB_BLOCK_GSM, 0x00000004, MM_MODEM_BAND_G850 },
+ { MM_CINTERION_RB_BLOCK_GSM, 0x00000008, MM_MODEM_BAND_PCS },
+ { MM_CINTERION_RB_BLOCK_UMTS, 0x00000001, MM_MODEM_BAND_UTRAN_1 },
+ { MM_CINTERION_RB_BLOCK_UMTS, 0x00000002, MM_MODEM_BAND_UTRAN_2 },
+ { MM_CINTERION_RB_BLOCK_UMTS, 0x00000004, MM_MODEM_BAND_UTRAN_3 },
+ { MM_CINTERION_RB_BLOCK_UMTS, 0x00000008, MM_MODEM_BAND_UTRAN_4 },
+ { MM_CINTERION_RB_BLOCK_UMTS, 0x00000010, MM_MODEM_BAND_UTRAN_5 },
+ { MM_CINTERION_RB_BLOCK_UMTS, 0x00000020, MM_MODEM_BAND_UTRAN_6 },
+ { MM_CINTERION_RB_BLOCK_UMTS, 0x00000080, MM_MODEM_BAND_UTRAN_8 },
+ { MM_CINTERION_RB_BLOCK_UMTS, 0x00000100, MM_MODEM_BAND_UTRAN_9 },
+ { MM_CINTERION_RB_BLOCK_UMTS, 0x00040000, MM_MODEM_BAND_UTRAN_19 },
+ { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000001, MM_MODEM_BAND_EUTRAN_1 },
+ { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000002, MM_MODEM_BAND_EUTRAN_2 },
+ { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000004, MM_MODEM_BAND_EUTRAN_3 },
+ { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000008, MM_MODEM_BAND_EUTRAN_4 },
+ { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000010, MM_MODEM_BAND_EUTRAN_5 },
+ { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000040, MM_MODEM_BAND_EUTRAN_7 },
+ { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000080, MM_MODEM_BAND_EUTRAN_8 },
+ { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000800, MM_MODEM_BAND_EUTRAN_12 },
+ { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00001000, MM_MODEM_BAND_EUTRAN_13 },
+ { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00010000, MM_MODEM_BAND_EUTRAN_17 },
+ { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00020000, MM_MODEM_BAND_EUTRAN_18 },
+ { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00040000, MM_MODEM_BAND_EUTRAN_19 },
+ { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00080000, MM_MODEM_BAND_EUTRAN_20 },
+ { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x02000000, MM_MODEM_BAND_EUTRAN_26 },
+ { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x08000000, MM_MODEM_BAND_EUTRAN_28 },
+ { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x10000000, MM_MODEM_BAND_EUTRAN_29 },
+ { MM_CINTERION_RB_BLOCK_LTE_HIGH, 0x00000020, MM_MODEM_BAND_EUTRAN_38 },
+ { MM_CINTERION_RB_BLOCK_LTE_HIGH, 0x00000040, MM_MODEM_BAND_EUTRAN_39 },
+ { MM_CINTERION_RB_BLOCK_LTE_HIGH, 0x00000080, MM_MODEM_BAND_EUTRAN_40 },
+ { MM_CINTERION_RB_BLOCK_LTE_HIGH, 0x00000100, MM_MODEM_BAND_EUTRAN_41 }
+};
+
+static const CinterionBandEx cinterion_bands_imt[] = {
+ { MM_CINTERION_RB_BLOCK_GSM, 0x00000004, MM_MODEM_BAND_EGSM },
+ { MM_CINTERION_RB_BLOCK_GSM, 0x00000010, MM_MODEM_BAND_DCS },
+ { MM_CINTERION_RB_BLOCK_GSM, 0x00000020, MM_MODEM_BAND_PCS },
+ { MM_CINTERION_RB_BLOCK_GSM, 0x00000040, MM_MODEM_BAND_G850 },
+ { MM_CINTERION_RB_BLOCK_UMTS, 0x00000001, MM_MODEM_BAND_UTRAN_1 },
+ { MM_CINTERION_RB_BLOCK_UMTS, 0x00000002, MM_MODEM_BAND_UTRAN_2 },
+ { MM_CINTERION_RB_BLOCK_UMTS, 0x00000008, MM_MODEM_BAND_UTRAN_4 },
+ { MM_CINTERION_RB_BLOCK_UMTS, 0x00000010, MM_MODEM_BAND_UTRAN_5 },
+ { MM_CINTERION_RB_BLOCK_UMTS, 0x00000080, MM_MODEM_BAND_UTRAN_8 },
+ { MM_CINTERION_RB_BLOCK_UMTS, 0x00000100, MM_MODEM_BAND_UTRAN_9 },
+ { MM_CINTERION_RB_BLOCK_UMTS, 0x00040000, MM_MODEM_BAND_UTRAN_19 },
+ { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000001, MM_MODEM_BAND_EUTRAN_1 },
+ { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000002, MM_MODEM_BAND_EUTRAN_2 },
+ { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000004, MM_MODEM_BAND_EUTRAN_3 },
+ { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000008, MM_MODEM_BAND_EUTRAN_4 },
+ { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000010, MM_MODEM_BAND_EUTRAN_5 },
+ { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000040, MM_MODEM_BAND_EUTRAN_7 },
+ { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000080, MM_MODEM_BAND_EUTRAN_8 },
+ { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000800, MM_MODEM_BAND_EUTRAN_12 },
+ { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00020000, MM_MODEM_BAND_EUTRAN_18 },
+ { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00040000, MM_MODEM_BAND_EUTRAN_19 },
+ { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00080000, MM_MODEM_BAND_EUTRAN_20 },
+ { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x08000000, MM_MODEM_BAND_EUTRAN_28 }
+};
+
/* Check valid combinations in 2G-only devices */
#define VALIDATE_2G_BAND(cinterion_mask) \
(cinterion_mask == 1 || \
@@ -81,46 +149,127 @@ static const CinterionBand cinterion_bands[] = {
cinterion_mask == 15)
/*****************************************************************************/
-/* ^SCFG (3G) test parser
+/* ^SCFG (3G+LTE) test parser
*
- * Example:
+ * Example 3G:
* AT^SCFG=?
* ...
* ^SCFG: "MEShutdown/OnIgnition",("on","off")
* ^SCFG: "Radio/Band",("1-511","0-1")
* ^SCFG: "Radio/NWSM",("0","1","2")
* ...
- *
* ^SCFG: "Radio/Band\",("1"-"147")
+ *
+ * Example LTE1 (GSM charset):
+ * AT^SCFG=?
+ * ...
+ * ^SCFG: "Radio/Band/2G",("0x00000004"-"0x00000074")
+ * ^SCFG: "Radio/Band/3G",("0x00000001"-"0x0004019B")
+ * ^SCFG: "Radio/Band/4G",("0x00000001"-"0x080E08DF")
+ * ...
+ *
+ * Example LTE1 (UCS2 charset):
+ * AT^SCFG=?
+ * ...
+ * ^SCFG: "Radio/Band/2G",("0030007800300030003000300030003000300034"-"0030007800300030003000300030003000370034")
+ * ^SCFG: "Radio/Band/3G",("0030007800300030003000300030003000300031"-"0030007800300030003000340030003100390042")
+ * ^SCFG: "Radio/Band/4G",("0030007800300030003000300030003000300031"-"0030007800300038003000450030003800440046")
+ * ...
+ *
+ * Example LTE2 (all charsets):
+ * AT^SCFG=?
+ * ...
+ * ^SCFG: "Radio/Band/2G",("00000001-0000000f"),,("0","1")
+ * ^SCFG: "Radio/Band/3G",("00000001-000400b5"),,("0","1")
+ * ^SCFG: "Radio/Band/4G",("00000001-8a0e00d5"),("00000002-000001e2"),("0","1")
+ * ...
*/
+static void
+parse_bands (guint bandlist,
+ GArray **bands,
+ MMCinterionRbBlock block,
+ MMCinterionModemFamily modem_family)
+{
+ guint i;
+ const CinterionBandEx *ref_bands;
+ guint nb_ref_bands;
+
+ if (!bandlist)
+ return;
+
+ if (modem_family == MM_CINTERION_MODEM_FAMILY_IMT) {
+ ref_bands = cinterion_bands_imt;
+ nb_ref_bands = G_N_ELEMENTS (cinterion_bands_imt);
+ } else {
+ ref_bands = cinterion_bands_ex;
+ nb_ref_bands = G_N_ELEMENTS (cinterion_bands_ex);
+ }
+
+ for (i = 0; i < nb_ref_bands; i++) {
+ if (block == ref_bands[i].cinterion_band_block && (bandlist & ref_bands[i].cinterion_band_flag)) {
+ if (G_UNLIKELY (!*bands))
+ *bands = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), 23);
+ g_array_append_val (*bands, ref_bands[i].mm_band);
+ }
+ }
+}
+
+static guint
+take_and_convert_from_matched_string (gchar *str,
+ MMModemCharset charset,
+ MMCinterionModemFamily modem_family)
+{
+ guint val = 0;
+
+ if (!str)
+ return 0;
+
+ if (modem_family == MM_CINTERION_MODEM_FAMILY_IMT && charset == MM_MODEM_CHARSET_UCS2)
+ str = mm_charset_take_and_convert_to_utf8 (str, charset);
+
+ mm_get_uint_from_hex_str (str, &val);
+ g_free (str);
+
+ return val;
+}
+
gboolean
mm_cinterion_parse_scfg_test (const gchar *response,
+ MMCinterionModemFamily modem_family,
MMModemCharset charset,
GArray **supported_bands,
+ MMCinterionRadioBandFormat *format,
GError **error)
{
- GRegex *r;
- GMatchInfo *match_info;
+ g_autoptr(GRegex) r1 = NULL;
+ g_autoptr(GMatchInfo) match_info1 = NULL;
+ g_autoptr(GRegex) r2 = NULL;
+ g_autoptr(GMatchInfo) match_info2 = NULL;
GError *inner_error = NULL;
GArray *bands = NULL;
+ g_assert (format);
+
if (!response) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Missing response");
return FALSE;
}
- r = g_regex_new ("\\^SCFG:\\s*\"Radio/Band\",\\((?:\")?([0-9]*)(?:\")?-(?:\")?([0-9]*)(?:\")?.*\\)",
- G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW,
- 0, NULL);
- g_assert (r != NULL);
+ r1 = g_regex_new ("\\^SCFG:\\s*\"Radio/Band\",\\((?:\")?([0-9]*)(?:\")?-(?:\")?([0-9]*)(?:\")?.*\\)",
+ G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW, 0, NULL);
+ g_assert (r1 != NULL);
- g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error);
- if (!inner_error && g_match_info_matches (match_info)) {
- gchar *maxbandstr;
+ g_regex_match_full (r1, response, strlen (response), 0, 0, &match_info1, &inner_error);
+ if (inner_error)
+ goto finish;
+ if (g_match_info_matches (match_info1)) {
+ g_autofree gchar *maxbandstr = NULL;
guint maxband = 0;
- maxbandstr = mm_get_string_unquoted_from_match_info (match_info, 2);
+ *format = MM_CINTERION_RADIO_BAND_FORMAT_SINGLE;
+
+ maxbandstr = mm_get_string_unquoted_from_match_info (match_info1, 2);
if (maxbandstr) {
/* Handle charset conversion if the number is given in UCS2 */
if (charset != MM_MODEM_CHARSET_UNKNOWN)
@@ -144,14 +293,47 @@ mm_cinterion_parse_scfg_test (const gchar *response,
}
}
}
-
- g_free (maxbandstr);
+ goto finish;
}
- g_match_info_free (match_info);
- g_regex_unref (r);
+ r2 = g_regex_new ("\\^SCFG:\\s*\"Radio/Band/([234]G)\",\\(\"?([0-9A-Fa-fx]*)\"?-\"?([0-9A-Fa-fx]*)\"?\\)(,*\\(\"?([0-9A-Fa-fx]*)\"?-\"?([0-9A-Fa-fx]*)\"?\\))?",
+ 0, 0, NULL);
+ g_assert (r2 != NULL);
+ g_regex_match_full (r2, response, strlen (response), 0, 0, &match_info2, &inner_error);
+ if (inner_error)
+ goto finish;
+ while (g_match_info_matches (match_info2)) {
+ g_autofree gchar *techstr = NULL;
+ guint maxband;
+
+ *format = MM_CINTERION_RADIO_BAND_FORMAT_MULTIPLE;
+
+ techstr = mm_get_string_unquoted_from_match_info (match_info2, 1);
+ if (g_strcmp0 (techstr, "2G") == 0) {
+ maxband = take_and_convert_from_matched_string (mm_get_string_unquoted_from_match_info (match_info2, 3), charset, modem_family);
+ parse_bands (maxband, &bands, MM_CINTERION_RB_BLOCK_GSM, modem_family);
+ } else if (g_strcmp0 (techstr, "3G") == 0) {
+ maxband = take_and_convert_from_matched_string (mm_get_string_unquoted_from_match_info (match_info2, 3), charset, modem_family);
+ parse_bands (maxband, &bands, MM_CINTERION_RB_BLOCK_UMTS, modem_family);
+ } else if (g_strcmp0 (techstr, "4G") == 0) {
+ maxband = take_and_convert_from_matched_string (mm_get_string_unquoted_from_match_info (match_info2, 3), charset, modem_family);
+ parse_bands (maxband, &bands, MM_CINTERION_RB_BLOCK_LTE_LOW, modem_family);
+ if (modem_family == MM_CINTERION_MODEM_FAMILY_DEFAULT) {
+ maxband = take_and_convert_from_matched_string (mm_get_string_unquoted_from_match_info (match_info2, 6), charset, modem_family);
+ parse_bands (maxband, &bands, MM_CINTERION_RB_BLOCK_LTE_HIGH, modem_family);
+ }
+ } else {
+ inner_error = g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Couldn't parse ^SCFG=? response");
+ break;
+ }
+
+ g_match_info_next (match_info2, NULL);
+ }
- if (!bands)
+finish:
+ if (!bands && !inner_error) /* set error only if not already given */
inner_error = g_error_new (MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
"No valid bands found in ^SCFG=? response");
@@ -168,7 +350,7 @@ mm_cinterion_parse_scfg_test (const gchar *response,
}
/*****************************************************************************/
-/* ^SCFG response parser
+/* ^SCFG response parser (2 types: 2G/3G and LTE)
*
* Example (3G):
* AT^SCFG="Radio/Band"
@@ -181,16 +363,42 @@ mm_cinterion_parse_scfg_test (const gchar *response,
* Example (2G):
* AT+SCFG="Radio/Band"
* ^SCFG: "Radio/Band","3","3"
+ *
+ * Example LTE1 (GSM charset):
+ * AT^SCFG=?
+ * ...
+ * ^SCFG: "Radio/Band/2G","0x00000074"
+ * ^SCFG: "Radio/Band/3G","0x0004019B"
+ * ^SCFG: "Radio/Band/4G","0x080E08DF"
+ * ...
+ * AT^SCFG=?
+ * ...
+ * Example LTE1 (UCS2 charset):
+ * AT^SCFG=?
+ * ...
+ * ^SCFG: "Radio/Band/2G","0030007800300030003000300030003000370034"
+ * ^SCFG: "Radio/Band/3G","0030007800300030003000340030003100390042"
+ * ^SCFG: "Radio/Band/4G","0030007800300038003000450030003800440046"
+ * ...
+ * Example LTE2 (all charsets):
+ * AT^SCFG=?
+ * ...
+ * ^SCFG: "Radio/Band/2G","0000000f"
+ * ^SCFG: "Radio/Band/3G","000400b5"
+ * ^SCFG: "Radio/Band/4G","8a0e00d5","000000e2"
+ * ...
*/
gboolean
-mm_cinterion_parse_scfg_response (const gchar *response,
- MMModemCharset charset,
- GArray **current_bands,
- GError **error)
+mm_cinterion_parse_scfg_response (const gchar *response,
+ MMCinterionModemFamily modem_family,
+ MMModemCharset charset,
+ GArray **current_bands,
+ MMCinterionRadioBandFormat format,
+ GError **error)
{
- GRegex *r;
- GMatchInfo *match_info;
+ g_autoptr(GRegex) r = NULL;
+ g_autoptr(GMatchInfo) match_info = NULL;
GError *inner_error = NULL;
GArray *bands = NULL;
@@ -199,45 +407,79 @@ mm_cinterion_parse_scfg_response (const gchar *response,
return FALSE;
}
- r = g_regex_new ("\\^SCFG:\\s*\"Radio/Band\",\\s*\"?([0-9a-fA-F]*)\"?", 0, 0, NULL);
- g_assert (r != NULL);
-
- if (g_regex_match (r, response, 0, &match_info)) {
- gchar *currentstr;
- guint current = 0;
-
- currentstr = mm_get_string_unquoted_from_match_info (match_info, 1);
- if (currentstr) {
- /* Handle charset conversion if the number is given in UCS2 */
- if (charset != MM_MODEM_CHARSET_UNKNOWN)
- currentstr = mm_charset_take_and_convert_to_utf8 (currentstr, charset);
-
- mm_get_uint_from_str (currentstr, &current);
- }
-
- if (current == 0) {
- inner_error = g_error_new (MM_CORE_ERROR,
- MM_CORE_ERROR_FAILED,
- "Couldn't parse ^SCFG response");
- } else {
- guint i;
+ if (format == MM_CINTERION_RADIO_BAND_FORMAT_SINGLE) {
+ r = g_regex_new ("\\^SCFG:\\s*\"Radio/Band\",\\s*\"?([0-9a-fA-F]*)\"?", 0, 0, NULL);
+ g_assert (r != NULL);
+ g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error);
+ if (inner_error)
+ goto finish;
+ if (g_match_info_matches (match_info)) {
+ g_autofree gchar *currentstr = NULL;
+ guint current = 0;
+
+ currentstr = mm_get_string_unquoted_from_match_info (match_info, 1);
+ if (currentstr) {
+ /* Handle charset conversion if the number is given in UCS2 */
+ if (charset != MM_MODEM_CHARSET_UNKNOWN)
+ currentstr = mm_charset_take_and_convert_to_utf8 (currentstr, charset);
+ mm_get_uint_from_str (currentstr, &current);
+ }
- for (i = 0; i < G_N_ELEMENTS (cinterion_bands); i++) {
- if (current & cinterion_bands[i].cinterion_band_flag) {
- if (G_UNLIKELY (!bands))
- bands = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), 9);
- g_array_append_val (bands, cinterion_bands[i].mm_band);
+ if (current == 0) {
+ inner_error = g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Couldn't parse ^SCFG? response");
+ } else {
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS (cinterion_bands); i++) {
+ if (current & cinterion_bands[i].cinterion_band_flag) {
+ if (G_UNLIKELY (!bands))
+ bands = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), 9);
+ g_array_append_val (bands, cinterion_bands[i].mm_band);
+ }
}
}
}
+ } else { /* format == MM_CINTERION_RADIO_BAND_FORMAT_MULTIPLE */
+ r = g_regex_new ("\\^SCFG:\\s*\"Radio/Band/([234]G)\",\"?([0-9A-Fa-fx]*)\"?,?\"?([0-9A-Fa-fx]*)?\"?",
+ 0, 0, NULL);
+ g_assert (r != NULL);
+ g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error);
+ if (inner_error)
+ goto finish;
+ while (g_match_info_matches (match_info)) {
+ g_autofree gchar *techstr = NULL;
+ guint current;
+
+ techstr = mm_get_string_unquoted_from_match_info (match_info, 1);
+ if (g_strcmp0(techstr, "2G") == 0) {
+ current = take_and_convert_from_matched_string (mm_get_string_unquoted_from_match_info (match_info, 2), charset, modem_family);
+ parse_bands (current, &bands, MM_CINTERION_RB_BLOCK_GSM, modem_family);
+
+ } else if (g_strcmp0(techstr, "3G") == 0) {
+ current = take_and_convert_from_matched_string (mm_get_string_unquoted_from_match_info (match_info, 2), charset, modem_family);
+ parse_bands (current, &bands, MM_CINTERION_RB_BLOCK_UMTS, modem_family);
+ } else if (g_strcmp0(techstr, "4G") == 0) {
+ current = take_and_convert_from_matched_string (mm_get_string_unquoted_from_match_info (match_info, 2), charset, modem_family);
+ parse_bands (current, &bands, MM_CINTERION_RB_BLOCK_LTE_LOW, modem_family);
+ if (modem_family == MM_CINTERION_MODEM_FAMILY_DEFAULT) {
+ current = take_and_convert_from_matched_string (mm_get_string_unquoted_from_match_info (match_info, 3), charset, modem_family);
+ parse_bands (current, &bands, MM_CINTERION_RB_BLOCK_LTE_HIGH, modem_family);
+ }
+ } else {
+ inner_error = g_error_new (MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Couldn't parse ^SCFG? response");
+ break;
+ }
- g_free (currentstr);
+ g_match_info_next (match_info, NULL);
+ }
}
- g_match_info_free (match_info);
- g_regex_unref (r);
-
- if (!bands)
+finish:
+ if (!bands && !inner_error) /* set error only if not already given */
inner_error = g_error_new (MM_CORE_ERROR,
MM_CORE_ERROR_FAILED,
"No valid bands found in ^SCFG response");
@@ -371,52 +613,101 @@ out:
/* Build Cinterion-specific band value */
gboolean
-mm_cinterion_build_band (GArray *bands,
- guint supported,
- gboolean only_2g,
- guint *out_band,
- GError **error)
+mm_cinterion_build_band (GArray *bands,
+ guint *supported,
+ gboolean only_2g,
+ MMCinterionRadioBandFormat format,
+ MMCinterionModemFamily modem_family,
+ guint *out_band,
+ GError **error)
{
- guint band = 0;
+ guint band[MM_CINTERION_RB_BLOCK_N] = { 0 };
- /* The special case of ANY should be treated separately. */
- if (bands->len == 1 && g_array_index (bands, MMModemBand, 0) == MM_MODEM_BAND_ANY) {
- band = supported;
- } else {
- guint i;
+ if (format == MM_CINTERION_RADIO_BAND_FORMAT_SINGLE) {
+ /* The special case of ANY should be treated separately. */
+ if (bands->len == 1 && g_array_index (bands, MMModemBand, 0) == MM_MODEM_BAND_ANY) {
+ if (supported)
+ band[MM_CINTERION_RB_BLOCK_LEGACY] = supported[MM_CINTERION_RB_BLOCK_LEGACY];
+ } else {
+ guint i;
- for (i = 0; i < G_N_ELEMENTS (cinterion_bands); i++) {
- guint j;
+ for (i = 0; i < G_N_ELEMENTS (cinterion_bands); i++) {
+ guint j;
- for (j = 0; j < bands->len; j++) {
- if (g_array_index (bands, MMModemBand, j) == cinterion_bands[i].mm_band) {
- band |= cinterion_bands[i].cinterion_band_flag;
- break;
+ for (j = 0; j < bands->len; j++) {
+ if (g_array_index (bands, MMModemBand, j) == cinterion_bands[i].mm_band) {
+ band[MM_CINTERION_RB_BLOCK_LEGACY] |= cinterion_bands[i].cinterion_band_flag;
+ break;
+ }
}
}
+
+ /* 2G-only modems only support a subset of the possible band
+ * combinations. Detect it early and error out.
+ */
+ if (only_2g && !VALIDATE_2G_BAND (band[MM_CINTERION_RB_BLOCK_LEGACY]))
+ band[MM_CINTERION_RB_BLOCK_LEGACY] = 0;
}
- /* 2G-only modems only support a subset of the possible band
- * combinations. Detect it early and error out.
- */
- if (only_2g && !VALIDATE_2G_BAND (band))
- band = 0;
- }
+ if (band[MM_CINTERION_RB_BLOCK_LEGACY] == 0) {
+ g_autofree gchar *bands_string = NULL;
- if (band == 0) {
- gchar *bands_string;
+ bands_string = mm_common_build_bands_string ((MMModemBand *)(gpointer)bands->data, bands->len);
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "The given band combination is not supported: '%s'",
+ bands_string);
+ return FALSE;
+ }
- bands_string = mm_common_build_bands_string ((MMModemBand *)(gpointer)bands->data, bands->len);
- g_set_error (error,
- MM_CORE_ERROR,
- MM_CORE_ERROR_FAILED,
- "The given band combination is not supported: '%s'",
- bands_string);
- g_free (bands_string);
- return FALSE;
+ } else { /* format == MM_CINTERION_RADIO_BAND_FORMAT_MULTIPLE */
+ if (bands->len == 1 && g_array_index (bands, MMModemBand, 0) == MM_MODEM_BAND_ANY) {
+ if (supported)
+ memcpy (band, supported, sizeof (guint) * MM_CINTERION_RB_BLOCK_N);
+ } else {
+ guint i;
+ const CinterionBandEx *ref_bands;
+ guint nb_ref_bands;
+
+ if (modem_family == MM_CINTERION_MODEM_FAMILY_IMT) {
+ ref_bands = cinterion_bands_imt;
+ nb_ref_bands = G_N_ELEMENTS (cinterion_bands_imt);
+ } else {
+ ref_bands = cinterion_bands_ex;
+ nb_ref_bands = G_N_ELEMENTS (cinterion_bands_ex);
+ }
+
+ for (i = 0; i < nb_ref_bands; i++) {
+ guint j;
+
+ for (j = 0; j < bands->len; j++) {
+ if (g_array_index (bands, MMModemBand, j) == ref_bands[i].mm_band) {
+ band[ref_bands[i].cinterion_band_block] |= ref_bands[i].cinterion_band_flag;
+ break;
+ }
+ }
+ }
+ }
+
+ /* this modem family does not allow disabling all bands in a given technology through this command */
+ if (modem_family == MM_CINTERION_MODEM_FAMILY_IMT &&
+ (!band[MM_CINTERION_RB_BLOCK_GSM] ||
+ !band[MM_CINTERION_RB_BLOCK_UMTS] ||
+ !band[MM_CINTERION_RB_BLOCK_LTE_LOW])) {
+ g_autofree gchar *bands_string = NULL;
+
+ bands_string = mm_common_build_bands_string ((MMModemBand *)(gpointer)bands->data, bands->len);
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "The given band combination is not supported: '%s'",
+ bands_string);
+ return FALSE;
+ }
}
- *out_band = band;
+ memcpy (out_band, band, sizeof (guint) * MM_CINTERION_RB_BLOCK_N);
return TRUE;
}
@@ -875,7 +1166,7 @@ mm_cinterion_parse_ctzu_urc (GMatchInfo *match_info,
gboolean
mm_cinterion_parse_smoni_query_response (const gchar *response,
- MMCinterionSmoniTech *out_tech,
+ MMCinterionRadioGen *out_tech,
gdouble *out_rssi,
gdouble *out_ecn0,
gdouble *out_rscp,
@@ -888,7 +1179,7 @@ mm_cinterion_parse_smoni_query_response (const gchar *response,
g_autoptr(GMatchInfo) match_info = NULL;
g_autoptr(GMatchInfo) match_info_pre = NULL;
GError *inner_error = NULL;
- MMCinterionSmoniTech tech = MM_CINTERION_SMONI_NO_TECH;
+ MMCinterionRadioGen tech = MM_CINTERION_RADIO_GEN_NONE;
gdouble rssi = -G_MAXDOUBLE;
gdouble ecn0 = -G_MAXDOUBLE;
gdouble rscp = -G_MAXDOUBLE;
@@ -970,7 +1261,7 @@ mm_cinterion_parse_smoni_query_response (const gchar *response,
}
#define FLOAT "([-+]?[0-9]+\\.?[0-9]*)"
switch (tech) {
- case MM_CINTERION_SMONI_2G:
+ case MM_CINTERION_RADIO_GEN_2G:
r = g_regex_new ("\\^SMONI:\\s*2G,(\\d+),"FLOAT, 0, 0, NULL);
g_assert (r != NULL);
g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error);
@@ -982,7 +1273,7 @@ mm_cinterion_parse_smoni_query_response (const gchar *response,
}
}
break;
- case MM_CINTERION_SMONI_3G:
+ case MM_CINTERION_RADIO_GEN_3G:
r = g_regex_new ("\\^SMONI:\\s*3G,(\\d+),(\\d+),"FLOAT","FLOAT, 0, 0, NULL);
g_assert (r != NULL);
g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error);
@@ -999,7 +1290,7 @@ mm_cinterion_parse_smoni_query_response (const gchar *response,
}
}
break;
- case MM_CINTERION_SMONI_4G:
+ case MM_CINTERION_RADIO_GEN_4G:
r = g_regex_new ("\\^SMONI:\\s*4G,(\\d+),(\\d+),(\\d+),(\\d+),(\\w+),(\\d+),(\\d+),(\\w+),(\\w+),(\\d+),([^,]*),"FLOAT","FLOAT, 0, 0, NULL);
g_assert (r != NULL);
g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error);
@@ -1025,7 +1316,7 @@ mm_cinterion_parse_smoni_query_response (const gchar *response,
}
}
break;
- case MM_CINTERION_SMONI_NO_TECH:
+ case MM_CINTERION_RADIO_GEN_NONE:
default:
goto out;
}
@@ -1064,7 +1355,7 @@ mm_cinterion_smoni_response_to_signal_info (const gchar *response,
MMSignal **out_lte,
GError **error)
{
- MMCinterionSmoniTech tech = MM_CINTERION_SMONI_NO_TECH;
+ MMCinterionRadioGen tech = MM_CINTERION_RADIO_GEN_NONE;
gdouble rssi = MM_SIGNAL_UNKNOWN;
gdouble ecn0 = MM_SIGNAL_UNKNOWN;
gdouble rscp = MM_SIGNAL_UNKNOWN;
@@ -1082,21 +1373,21 @@ mm_cinterion_smoni_response_to_signal_info (const gchar *response,
return FALSE;
switch (tech) {
- case MM_CINTERION_SMONI_2G:
+ case MM_CINTERION_RADIO_GEN_2G:
gsm = mm_signal_new ();
mm_signal_set_rssi (gsm, rssi);
break;
- case MM_CINTERION_SMONI_3G:
+ case MM_CINTERION_RADIO_GEN_3G:
umts = mm_signal_new ();
mm_signal_set_rscp (umts, rscp);
mm_signal_set_ecio (umts, ecn0); /* UMTS EcIo (assumed EcN0) */
break;
- case MM_CINTERION_SMONI_4G:
+ case MM_CINTERION_RADIO_GEN_4G:
lte = mm_signal_new ();
mm_signal_set_rsrp (lte, rsrp);
mm_signal_set_rsrq (lte, rsrq);
break;
- case MM_CINTERION_SMONI_NO_TECH: /* not registered, searching */
+ case MM_CINTERION_RADIO_GEN_NONE: /* not registered, searching */
break; /* no error case */
default: /* should not happen, so if it does, error */
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,