/* -*- 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) 2014 Aleksander Morgado */ #include #include #include #include "ModemManager.h" #define _LIBMM_INSIDE_MM #include #include "mm-errors-types.h" #include "mm-modem-helpers-cinterion.h" /* Setup relationship between the 3G band bitmask in the modem and the bitmask * in ModemManager. */ typedef struct { guint32 cinterion_band_flag; MMModemBand mm_band; } CinterionBand3G; /* Table checked in HC25 and PHS8 references. This table includes both 2G and 3G * frequencies. Depending on which one is configured, one access technology or * the other will be used. This may conflict with the allowed mode configuration * set, so you shouldn't for example set 3G frequency bands, and then use a * 2G-only allowed mode. */ static const CinterionBand3G bands_3g[] = { { (1 << 0), MM_MODEM_BAND_EGSM }, { (1 << 1), MM_MODEM_BAND_DCS }, { (1 << 2), MM_MODEM_BAND_PCS }, { (1 << 3), MM_MODEM_BAND_G850 }, { (1 << 4), MM_MODEM_BAND_U2100 }, { (1 << 5), MM_MODEM_BAND_U1900 }, { (1 << 6), MM_MODEM_BAND_U850 }, { (1 << 7), MM_MODEM_BAND_U900 }, { (1 << 8), MM_MODEM_BAND_U800 } }; /*****************************************************************************/ /* ^SCFG (3G) test parser * * Example: * AT^SCFG=? * ... * ^SCFG: "MEShutdown/OnIgnition",("on","off") * ^SCFG: "Radio/Band",("1-511","0-1") * ^SCFG: "Radio/NWSM",("0","1","2") * ... * */ gboolean mm_cinterion_parse_scfg_3g_test (const gchar *response, GArray **supported_bands, GError **error) { GRegex *r; GMatchInfo *match_info; GError *inner_error = NULL; GArray *bands = NULL; 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\",\\(\"(\\d+)-(\\d+)\",.*\\)", 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)) { guint maxband; if (!mm_get_uint_from_match_info (match_info, 2, &maxband)) { 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 (bands_3g); i++) { if (maxband & bands_3g[i].cinterion_band_flag) { if (G_UNLIKELY (!bands)) bands = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), 9); g_array_append_val (bands, bands_3g[i].mm_band); } } } g_free (maxbandstr); } if (match_info) g_match_info_free (match_info); g_regex_unref (r); if (!bands) inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "No valid bands found in ^SCFG=? response"); if (inner_error) { g_propagate_error (error, inner_error); return FALSE; } g_assert (bands != NULL && bands->len > 0); *supported_bands = bands; return TRUE; } /*****************************************************************************/ /* ^SCFG (3G) response parser * * Example: * AT^SCFG="Radio/Band" * ^SCFG: "Radio/Band",127 */ gboolean mm_cinterion_parse_scfg_3g_response (const gchar *response, GArray **current_bands, GError **error) { GRegex *r; GMatchInfo *match_info; GError *inner_error = NULL; GArray *bands = NULL; 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\",\\s*(\\d*)", 0, 0, NULL); g_assert (r != NULL); if (g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, NULL)) { gchar *current; current = g_match_info_fetch (match_info, 1); if (current) { guint32 current_int; guint i; current_int = (guint32) atoi (current); for (i = 0; i < G_N_ELEMENTS (bands_3g); i++) { if (current_int & bands_3g[i].cinterion_band_flag) { if (G_UNLIKELY (!bands)) bands = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), 4); g_array_append_val (bands, bands_3g[i].mm_band); } } g_free (current); } } if (match_info) g_match_info_free (match_info); g_regex_unref (r); if (!bands) inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "No valid bands found in ^SCFG=? response"); if (inner_error) { g_propagate_error (error, inner_error); return FALSE; } g_assert (bands != NULL && bands->len > 0); *current_bands = bands; return TRUE; }