aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormank.wang <mank.wang@quectel.com>2023-09-27 14:10:13 +0800
committerAleksander Morgado <aleksandermj@chromium.org>2023-10-18 21:29:06 +0000
commit1b6e4c434998258c9342895593538946c11f6e05 (patch)
treea17a8dfddb376f1dc00625bed9c0f18acdeba6b1 /src
parent7b878765c6c8025ca7a4594af798a3d892e5bc58 (diff)
quectel: avoid incorrect module version report after the upgrade
After LVFS upgrade, the module needs to be restarted. ModemManager queries the module information, sometimes the module is not ready, and the information queried by "mmcli -m any --firmware-status" is incomplete, It is now modified to re query once per second when obtaining incomplete versions, up to a maximum of 16 times. Signed-off-by: mank.wang <mank.wang@quectel.com>
Diffstat (limited to 'src')
-rw-r--r--src/plugins/quectel/mm-modem-helpers-quectel.c49
-rw-r--r--src/plugins/quectel/mm-modem-helpers-quectel.h2
-rw-r--r--src/plugins/quectel/mm-shared-quectel.c134
-rw-r--r--src/plugins/quectel/tests/test-modem-helpers-quectel.c16
4 files changed, 176 insertions, 25 deletions
diff --git a/src/plugins/quectel/mm-modem-helpers-quectel.c b/src/plugins/quectel/mm-modem-helpers-quectel.c
index 262d9794..4335e506 100644
--- a/src/plugins/quectel/mm-modem-helpers-quectel.c
+++ b/src/plugins/quectel/mm-modem-helpers-quectel.c
@@ -89,3 +89,52 @@ mm_quectel_parse_ctzu_test_response (const gchar *response,
return TRUE;
}
+
+/*****************************************************************************/
+/* standard firmware info
+ * Format of the string is:
+ * "[main version]_[modem and app version]"
+ * e.g. EM05GFAR07A07M1G_01.016.01.016
+ */
+#define QUECTEL_STD_FIRMWARE_VERSION_SEG 2
+
+/* Format of the string is:
+ * "modem_main.modem_minor.ap_main.ap_minor"
+ * e.g. 01.016.01.016
+ */
+#define QUECTEL_STD_MODEM_AP_FIRMWARE_VER_SEG 4
+#define QUECTEL_STD_MODEM_AP_FIRMWARE_VER_LEN 13
+
+#define QUECTEL_MAIN_VERSION_INVALID_TAG "00"
+#define QUECTEL_MINOR_VERSION_INVALID_TAG "000"
+
+gboolean
+mm_quectel_check_standard_firmware_version_valid (const gchar *std_str)
+{
+ gboolean valid = TRUE;
+ g_auto(GStrv) split_std_fw = NULL;
+ g_auto(GStrv) split_modem_ap_fw = NULL;
+ const gchar *modem_ap_fw;
+
+ if (std_str) {
+ split_std_fw = g_strsplit (std_str, "_", QUECTEL_STD_FIRMWARE_VERSION_SEG);
+ /* Quectel standard format of the [main version]_[modem and app version]
+ * Sometimes we find that the [modem and app version] query is missing by [AT+QMGR]
+ * for example: we expect EM05GFAR07A07M1G_01.016.01.016,but unexpected EM05GFAR07A07M1G_01.016.00.000 was returned
+ * Quectel will check for this abnormal [modem and app version] and flag it
+ */
+ if (g_strv_length (split_std_fw) == QUECTEL_STD_FIRMWARE_VERSION_SEG) {
+ modem_ap_fw = split_std_fw[1];
+ if (strlen (modem_ap_fw) == QUECTEL_STD_MODEM_AP_FIRMWARE_VER_LEN) {
+ split_modem_ap_fw = g_strsplit (modem_ap_fw, ".", QUECTEL_STD_MODEM_AP_FIRMWARE_VER_SEG);
+
+ if (g_strv_length (split_modem_ap_fw) == QUECTEL_STD_MODEM_AP_FIRMWARE_VER_SEG &&
+ !g_strcmp0 (split_modem_ap_fw[2], QUECTEL_MAIN_VERSION_INVALID_TAG) &&
+ !g_strcmp0 (split_modem_ap_fw[3], QUECTEL_MINOR_VERSION_INVALID_TAG)){
+ valid = FALSE;
+ }
+ }
+ }
+ }
+ return valid;
+}
diff --git a/src/plugins/quectel/mm-modem-helpers-quectel.h b/src/plugins/quectel/mm-modem-helpers-quectel.h
index d4ec0eae..ea9ff5c1 100644
--- a/src/plugins/quectel/mm-modem-helpers-quectel.h
+++ b/src/plugins/quectel/mm-modem-helpers-quectel.h
@@ -29,4 +29,6 @@ gboolean mm_quectel_parse_ctzu_test_response (const gchar *response,
gboolean *supports_enable_update_rtc,
GError **error);
+gboolean mm_quectel_check_standard_firmware_version_valid (const gchar *std_str);
+
#endif /* MM_MODEM_HELPERS_QUECTEL_H */
diff --git a/src/plugins/quectel/mm-shared-quectel.c b/src/plugins/quectel/mm-shared-quectel.c
index 93153fff..c95ab200 100644
--- a/src/plugins/quectel/mm-shared-quectel.c
+++ b/src/plugins/quectel/mm-shared-quectel.c
@@ -59,6 +59,11 @@ typedef struct {
GRegex *rdy_regex;
} Private;
+typedef struct {
+ MMFirmwareUpdateSettings *update_settings;
+ gint get_firmware_maximum_retry_int;
+} LoadUpdateSettingsContext;
+
static void
private_free (Private *priv)
{
@@ -210,22 +215,89 @@ quectel_get_firmware_update_methods (MMBaseModem *modem,
return update_methods;
}
+static gboolean quectel_at_port_get_firmware_version_retry (GTask *task);
+
+/* Eg. Sometimes when the module is booted up and sends the command to acquire the version to the modem,
+ * the modem may not be ready. The standard app version number of the response was not obtained;
+ * Fwupd(LVFS) requires relatively complete version information to update firmware. If the version information is incorrect,
+ * the update may not be possible. Therefore, we will conduct another query, up to 16 times.
+ */
+#define QUECTEL_STD_AP_FIRMWARE_INVALID_MAXIMUM_RETRY 16
+
+static void
+quectel_at_port_get_firmware_version_retry_ready (MMBaseModem *modem,
+ GAsyncResult *res,
+ GTask *task)
+{
+ const gchar *version;
+ LoadUpdateSettingsContext *ctx;
+
+ ctx = g_task_get_task_data (task);
+ version = mm_base_modem_at_command_finish (modem, res, NULL);
+ ctx->get_firmware_maximum_retry_int--;
+
+ if (version) {
+ if (mm_quectel_check_standard_firmware_version_valid (version)) {
+ mm_obj_dbg (modem, "Valid firmware version:%s, re-update", version);
+ mm_firmware_update_settings_set_version (ctx->update_settings, version);
+ g_task_return_pointer (task, g_object_ref (ctx->update_settings), g_object_unref);
+ g_object_unref (task);
+ return;
+ }
+ }
+ /* When the maximum repeat fetch count is greater than or equal to 0,
+ * attempt to retrieve version information again. */
+ if (ctx->get_firmware_maximum_retry_int >= 0)
+ g_timeout_add_seconds (1, (GSourceFunc) quectel_at_port_get_firmware_version_retry, task);
+ else {
+ mm_obj_dbg (modem, "Maximum retries to query firmware version reached: invalid firmware version received");
+ g_task_return_pointer (task, g_object_ref (ctx->update_settings), g_object_unref);
+ g_object_unref (task);
+ }
+}
+
+static gboolean
+quectel_at_port_get_firmware_version_retry (GTask *task)
+{
+ MMBaseModem *self;
+
+ self = g_task_get_source_object (task);
+
+ /* Fetch full firmware info */
+ mm_base_modem_at_command (self,
+ "+QGMR?",
+ 3,
+ FALSE,
+ (GAsyncReadyCallback) quectel_at_port_get_firmware_version_retry_ready,
+ task);
+
+ return G_SOURCE_REMOVE;
+}
+
static void
quectel_at_port_get_firmware_version_ready (MMBaseModem *modem,
GAsyncResult *res,
GTask *task)
{
- MMFirmwareUpdateSettings *update_settings;
- const gchar *version;
+ LoadUpdateSettingsContext *ctx;
+ const gchar *version;
+ gboolean ap_firmware_version_valid = TRUE;
- update_settings = g_task_get_task_data (task);
+ ctx = g_task_get_task_data (task);
version = mm_base_modem_at_command_finish (modem, res, NULL);
if (version)
- mm_firmware_update_settings_set_version (update_settings, version);
+ ap_firmware_version_valid = mm_quectel_check_standard_firmware_version_valid (version);
- g_task_return_pointer (task, g_object_ref (update_settings), g_object_unref);
- g_object_unref (task);
+ if (version && ap_firmware_version_valid) {
+ mm_firmware_update_settings_set_version (ctx->update_settings, version);
+ g_task_return_pointer (task, g_object_ref (ctx->update_settings), g_object_unref);
+ g_object_unref (task);
+ } else {
+ if (version)
+ mm_obj_dbg (modem, "Invalid firmware version %s return, retrying", version);
+ g_timeout_add_seconds (1, (GSourceFunc) quectel_at_port_get_firmware_version_retry, task);
+ }
}
#if defined WITH_MBIM
@@ -237,17 +309,17 @@ quectel_mbim_port_get_firmware_version_ready (MbimDevice *device,
g_autoptr(MbimMessage) response = NULL;
guint32 version_id;
g_autofree gchar *version_str = NULL;
- MMFirmwareUpdateSettings *update_settings;
+ LoadUpdateSettingsContext *ctx;
- update_settings = g_task_get_task_data (task);
+ ctx = g_task_get_task_data (task);
response = mbim_device_command_finish (device, res, NULL);
if (response && mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, NULL) &&
mbim_message_qdu_quectel_read_version_response_parse (response, &version_id, &version_str, NULL)) {
- mm_firmware_update_settings_set_version (update_settings, version_str);
+ mm_firmware_update_settings_set_version (ctx->update_settings, version_str);
}
- g_task_return_pointer (task, g_object_ref (update_settings), g_object_unref);
+ g_task_return_pointer (task, g_object_ref (ctx->update_settings), g_object_unref);
g_object_unref (task);
}
#endif
@@ -257,16 +329,16 @@ qfastboot_test_ready (MMBaseModem *self,
GAsyncResult *res,
GTask *task)
{
- MMFirmwareUpdateSettings *update_settings;
+ LoadUpdateSettingsContext *ctx;
- update_settings = g_task_get_task_data (task);
+ ctx = g_task_get_task_data (task);
/* Set update method */
if (mm_base_modem_at_command_finish (self, res, NULL)) {
- mm_firmware_update_settings_set_method (update_settings, MM_MODEM_FIRMWARE_UPDATE_METHOD_FASTBOOT);
- mm_firmware_update_settings_set_fastboot_at (update_settings, "AT+QFASTBOOT");
+ mm_firmware_update_settings_set_method (ctx->update_settings, MM_MODEM_FIRMWARE_UPDATE_METHOD_FASTBOOT);
+ mm_firmware_update_settings_set_fastboot_at (ctx->update_settings, "AT+QFASTBOOT");
} else
- mm_firmware_update_settings_set_method (update_settings, MM_MODEM_FIRMWARE_UPDATE_METHOD_NONE);
+ mm_firmware_update_settings_set_method (ctx->update_settings, MM_MODEM_FIRMWARE_UPDATE_METHOD_NONE);
/* Fetch full firmware info */
mm_base_modem_at_command (MM_BASE_MODEM (self),
@@ -282,7 +354,7 @@ quectel_at_port_get_firmware_revision_ready (MMBaseModem *self,
GAsyncResult *res,
GTask *task)
{
- MMFirmwareUpdateSettings *update_settings;
+ LoadUpdateSettingsContext *ctx;
MMModemFirmwareUpdateMethod update_methods;
const gchar *revision;
const gchar *name;
@@ -290,8 +362,8 @@ quectel_at_port_get_firmware_revision_ready (MMBaseModem *self,
g_autoptr(GPtrArray) ids = NULL;
GError *error = NULL;
- update_settings = g_task_get_task_data (task);
- update_methods = mm_firmware_update_settings_get_method (update_settings);
+ ctx = g_task_get_task_data (task);
+ update_methods = mm_firmware_update_settings_get_method (ctx->update_settings);
/* Set device ids */
ids = mm_iface_firmware_build_generic_device_ids (MM_IFACE_MODEM_FIRMWARE (self), &error);
@@ -311,7 +383,7 @@ quectel_at_port_get_firmware_revision_ready (MMBaseModem *self,
g_ptr_array_insert (ids, 0, g_strdup_printf ("%s&NAME_%s", id, name));
}
- mm_firmware_update_settings_set_device_ids (update_settings, (const gchar **)ids->pdata);
+ mm_firmware_update_settings_set_device_ids (ctx->update_settings, (const gchar **)ids->pdata);
/* Set update methods */
if (update_methods & MM_MODEM_FIRMWARE_UPDATE_METHOD_FIREHOSE) {
@@ -333,6 +405,15 @@ quectel_at_port_get_firmware_revision_ready (MMBaseModem *self,
}
}
+static void
+load_update_settings_context_free (LoadUpdateSettingsContext *ctx)
+{
+ if (ctx->update_settings)
+ g_object_unref (ctx->update_settings);
+
+ g_free (ctx);
+}
+
void
mm_shared_quectel_firmware_load_update_settings (MMIfaceModemFirmware *self,
GAsyncReadyCallback callback,
@@ -341,15 +422,17 @@ mm_shared_quectel_firmware_load_update_settings (MMIfaceModemFirmware *self,
GTask *task;
MMPortSerialAt *at_port;
MMModemFirmwareUpdateMethod update_methods;
- MMFirmwareUpdateSettings *update_settings;
+ LoadUpdateSettingsContext *ctx;
task = g_task_new (self, NULL, callback, user_data);
-
+ ctx = g_new0 (LoadUpdateSettingsContext, 1);
+
at_port = mm_base_modem_peek_best_at_port (MM_BASE_MODEM (self), NULL);
if (at_port) {
update_methods = quectel_get_firmware_update_methods (MM_BASE_MODEM (self), MM_PORT (at_port));
- update_settings = mm_firmware_update_settings_new (update_methods);
- g_task_set_task_data (task, update_settings, g_object_unref);
+ ctx->update_settings = mm_firmware_update_settings_new (update_methods);
+ ctx->get_firmware_maximum_retry_int = QUECTEL_STD_AP_FIRMWARE_INVALID_MAXIMUM_RETRY;
+ g_task_set_task_data (task, ctx, (GDestroyNotify)load_update_settings_context_free);
/* Fetch modem name */
mm_base_modem_at_command (MM_BASE_MODEM (self),
@@ -373,10 +456,11 @@ mm_shared_quectel_firmware_load_update_settings (MMIfaceModemFirmware *self,
g_autoptr(MbimMessage) message = NULL;
update_methods = quectel_get_firmware_update_methods (MM_BASE_MODEM (self), MM_PORT (mbim));
- update_settings = mm_firmware_update_settings_new (update_methods);
+ ctx->update_settings = mm_firmware_update_settings_new (update_methods);
+ ctx->get_firmware_maximum_retry_int = QUECTEL_STD_AP_FIRMWARE_INVALID_MAXIMUM_RETRY;
/* Fetch firmware info */
- g_task_set_task_data (task, update_settings, g_object_unref);
+ g_task_set_task_data (task, ctx, (GDestroyNotify)load_update_settings_context_free);
message = mbim_message_qdu_quectel_read_version_set_new (MBIM_QDU_QUECTEL_VERSION_TYPE_FW_BUILD_ID, NULL);
mbim_device_command (mm_port_mbim_peek_device (mbim),
message,
diff --git a/src/plugins/quectel/tests/test-modem-helpers-quectel.c b/src/plugins/quectel/tests/test-modem-helpers-quectel.c
index 0e2c7420..dee01865 100644
--- a/src/plugins/quectel/tests/test-modem-helpers-quectel.c
+++ b/src/plugins/quectel/tests/test-modem-helpers-quectel.c
@@ -80,6 +80,20 @@ test_ctzu (void)
}
/*****************************************************************************/
+/* Test ^FIRMVERSION test responses */
+static void
+test_firmversion (void)
+{
+ gboolean valid = TRUE;
+
+ valid = mm_quectel_check_standard_firmware_version_valid ("EM05GFAR07A07M1G_01.016.01.016");
+ g_assert_cmpuint (valid, ==, TRUE);
+
+ valid = mm_quectel_check_standard_firmware_version_valid ("EM05GFAR07A07M1G_01.016.00.000");
+ g_assert_cmpuint (valid, ==, FALSE);
+}
+
+/*****************************************************************************/
int main (int argc, char **argv)
{
@@ -89,5 +103,7 @@ int main (int argc, char **argv)
g_test_add_func ("/MM/quectel/ctzu", test_ctzu);
+ g_test_add_func ("/MM/quectel/firmversion", test_firmversion);
+
return g_test_run ();
}