aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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 ();
}