telit: override load revision

Currently, firmware revision string is obtained via AT+CGMR or AT+GMR
commands from the default mm-broadband-modem. For a class of Telit
modems however this command does not return the actual Telit Software
Package version, but the "Modem FW Version", which is only a component
of the whole firmware. For this class of modems, the correct string is
obtained with "AT#SWPKGV" command.

This change overrides load_revision* functions to add the ability to
parse "AT#SWPKGV" command for the modems that support it, and falls back
to the same logic that was implemented in mm-broadband-modem otherwise.
This commit is contained in:
Carlo Lobrano
2022-03-29 14:18:55 +00:00
committed by Aleksander Morgado
parent afd3ce86c9
commit 3df96a4255
6 changed files with 175 additions and 0 deletions
+2
View File
@@ -1420,6 +1420,8 @@ iface_modem_init (MMIfaceModem *iface)
iface->set_current_bands_finish = mm_shared_telit_modem_set_current_bands_finish;
iface->load_current_bands = mm_shared_telit_modem_load_current_bands;
iface->load_current_bands_finish = mm_shared_telit_modem_load_current_bands_finish;
iface->load_revision = mm_shared_telit_modem_load_revision;
iface->load_revision_finish = mm_shared_telit_modem_load_revision_finish;
iface->load_supported_bands = mm_shared_telit_modem_load_supported_bands;
iface->load_supported_bands_finish = mm_shared_telit_modem_load_supported_bands_finish;
iface->load_unlock_retries_finish = modem_load_unlock_retries_finish;
+51
View File
@@ -852,3 +852,54 @@ mm_telit_build_modes_list (void)
return combinations;
}
/*****************************************************************************/
/* Software Package version response parser */
gchar *
mm_telit_parse_swpkgv_response (const gchar *response)
{
gchar *version = NULL;
g_autofree gchar *base_version = NULL;
g_autofree gchar *ext_version = NULL;
g_autofree gchar *production_version = NULL;
g_autoptr(GRegex) r = NULL;
g_autoptr(GMatchInfo) match_info = NULL;
guint matches;
/* We are interested only in the first line: "Telit Software Package version"
* which is composed by up to three parts:
* - base version: "ab.cde.fgh"
* - extended version (e.g. alpha, beta, test version): "Axyz", "Bxyz", or "Txyz"
* - production parameter version (e.g. P0F.012345)
*/
r = g_regex_new ("(?P<Base>\\d{2}.\\d{2}.\\d{3})(?P<Ext>-[ABT]\\d{3})?(?P<Prod>-\\w\\d\\w\\.\\d+)?",
G_REGEX_RAW | G_REGEX_MULTILINE | G_REGEX_NEWLINE_CRLF,
G_REGEX_MATCH_NEWLINE_CR,
NULL);
g_assert (r != NULL);
if (!g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, NULL)) {
return NULL;
}
matches = g_match_info_get_match_count (match_info);
if (matches < 2 || matches > 4) {
return NULL;
}
base_version = g_match_info_fetch_named (match_info, "Base");
ext_version = g_match_info_fetch_named (match_info, "Ext");
production_version = g_match_info_fetch_named (match_info, "Prod");
if (base_version && !ext_version && !production_version)
version = g_strdup (base_version);
else if (base_version && ext_version && !production_version)
version = g_strdup_printf("%s%s", base_version, ext_version);
else if (base_version && !ext_version && production_version)
version = g_strdup_printf("%s%s", base_version, production_version);
else if (base_version && ext_version && production_version)
version = g_strdup_printf("%s%s%s", base_version, ext_version, production_version);
return version;
}
+2
View File
@@ -65,4 +65,6 @@ typedef enum { /*< underscore_name=mm_telit_csim_lock_state >*/
GArray *mm_telit_build_modes_list (void);
gchar *mm_telit_parse_swpkgv_response (const gchar *response);
#endif /* MM_MODEM_HELPERS_TELIT_H */
+84
View File
@@ -615,6 +615,90 @@ mm_shared_telit_set_current_modes (MMIfaceModem *self,
g_free (command);
}
/*****************************************************************************/
/* Revision loading */
gchar *
mm_shared_telit_modem_load_revision_finish (MMIfaceModem *self,
GAsyncResult *res,
GError **error)
{
GVariant *result;
gchar *revision = NULL;
result = mm_base_modem_at_sequence_finish (MM_BASE_MODEM (self), res, NULL, error);
if (result) {
revision = g_variant_dup_string (result, NULL);
}
return revision;
}
/*
* parse AT#SWPKGV command
* Execution command returns the software package version without #SWPKGV: command echo.
* The response is as follows:
*
* AT#SWPKGV
* <Telit Software Package Version>-<Production Parameters Version>
* <Modem FW Version> (Usually the same value returned by AT+GMR)
* <Production Parameters Version>
* <Application FW Version>
*/
static MMBaseModemAtResponseProcessorResult
software_package_version_ready (MMBaseModem *self,
gpointer none,
const gchar *command,
const gchar *response,
gboolean last_command,
const GError *error,
GVariant **result,
GError **result_error)
{
gchar *version = NULL;
if (error) {
*result = NULL;
/* Ignore AT errors (ie, ERROR or CMx ERROR) */
if (error->domain != MM_MOBILE_EQUIPMENT_ERROR || last_command) {
*result_error = g_error_copy (error);
return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_FAILURE;
}
*result_error = NULL;
return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_CONTINUE;
}
version = mm_telit_parse_swpkgv_response (response);
if (!version)
return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_CONTINUE;
*result = g_variant_new_take_string (version);
return MM_BASE_MODEM_AT_RESPONSE_PROCESSOR_RESULT_SUCCESS;
}
static const MMBaseModemAtCommand revisions[] = {
{ "#SWPKGV", 3, TRUE, software_package_version_ready },
{ "+CGMR", 3, TRUE, mm_base_modem_response_processor_string_ignore_at_errors },
{ "+GMR", 3, TRUE, mm_base_modem_response_processor_string_ignore_at_errors },
{ NULL }
};
void
mm_shared_telit_modem_load_revision (MMIfaceModem *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
mm_obj_dbg (self, "loading revision...");
mm_base_modem_at_sequence (
MM_BASE_MODEM (self),
revisions,
NULL, /* response_processor_context */
NULL, /* response_processor_context_free */
callback,
user_data);
}
/*****************************************************************************/
static void
+8
View File
@@ -90,4 +90,12 @@ void mm_shared_telit_modem_set_current_bands (MMIfaceModem *self,
GAsyncReadyCallback callback,
gpointer user_data);
void mm_shared_telit_modem_load_revision (MMIfaceModem *self,
GAsyncReadyCallback callback,
gpointer user_data);
gchar * mm_shared_telit_modem_load_revision_finish (MMIfaceModem *self,
GAsyncResult *res,
GError **error);
#endif /* MM_SHARED_TELIT_H */
@@ -611,6 +611,33 @@ test_telit_parse_qss_query (void)
}
}
static void
test_telit_parse_swpkgv_response (void)
{
static struct {
const gchar *response;
const gchar *expected;
} tt [] = {
{"\n\r12.34.567\n\rM0F.223004-B001\n\rP0F.224700\n\rA0F.223004-B001\n\r\n\rOK\n\r", "12.34.567"},
{"\n\r13.35.568-A123\n\rM0F.223004-B001\n\rP0F.224700\n\rA0F.223004-B001\n\r\n\rOK\n\r", "13.35.568-A123"},
{"\n\r14.36.569-B124\n\rM0F.223004-B001\n\rP0F.224700\n\rA0F.223004-B001\n\r\n\rOK\n\r", "14.36.569-B124"},
{"\n\r15.37.570-T125\n\rM0F.223004-B001\n\rP0F.224700\n\rA0F.223004-B001\n\r\n\rOK\n\r", "15.37.570-T125"},
{"\n\r16.38.571-P0F.224700\n\rM0F.223004-B001\n\rP0F.224700\n\rA0F.223004-B001\n\r\n\rOK\n\r", "16.38.571-P0F.224700"},
/* real example from LE910C1-EUX */
{"\n\r25.30.224-B001-P0F.224700\n\rM0F.223004-B001\n\rP0F.224700\n\rA0F.223004-B001\n\r\n\rOK\n\r", "25.30.224-B001-P0F.224700"},
};
guint i;
for (i = 0; i < G_N_ELEMENTS (tt); i++) {
gchar *actual = NULL;
actual = mm_telit_parse_swpkgv_response(tt[i].response);
g_assert_cmpstr (tt[i].expected, ==, actual);
g_free (actual);
}
}
/******************************************************************************/
int main (int argc, char **argv)
@@ -625,5 +652,6 @@ int main (int argc, char **argv)
g_test_add_func ("/MM/telit/bands/current/set_bands/3g", test_telit_get_3g_bnd_flag);
g_test_add_func ("/MM/telit/bands/current/set_bands/4g", test_telit_get_4g_bnd_flag);
g_test_add_func ("/MM/telit/qss/query", test_telit_parse_qss_query);
g_test_add_func ("/MM/telit/swpkv/parse_response", test_telit_parse_swpkgv_response);
return g_test_run ();
}