aports: the two modemmanager GNSS patches were never committed
git -C <repo> format-patch -o . writes relative to the -C directory, not the caller's cwd - the files landed in work/ModemManager and the aport shipped an APKBUILD referencing patches that did not exist. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
7578b2149c
commit
45caa3ac65
2 changed files with 506 additions and 0 deletions
|
|
@ -0,0 +1,255 @@
|
|||
From 2924dab906b3dc9e3b48e766637618ce53615c23 Mon Sep 17 00:00:00 2001
|
||||
From: Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net>
|
||||
Date: Thu, 2 Jul 2026 15:30:48 +0200
|
||||
Subject: [PATCH 2/3] shared-qmi: unlock AFW-gated GNSS engines at LOC start
|
||||
|
||||
Newer Snapdragon GNSS engines (e.g. gnss8 in the SM7635/Fairphone 6)
|
||||
only allow positioning for clients registered as application framework
|
||||
("AFW", i.e. the Android framework) clients: for anyone else,
|
||||
QMI_LOC_REG_EVENTS fails with INVALID_ARGUMENT and QMI_LOC_START with
|
||||
GENERAL_FAILURE ("IsPosRequestAllowed: FORCED_DISABLED" in the
|
||||
engine's own logic). ModemManager issued START first and never
|
||||
identified itself, so GPS could not be enabled at all on these devices.
|
||||
|
||||
Reorder the LOC bring-up to register-events -> start (the order the
|
||||
Qualcomm location HAL uses), identifying as an AFW client with the
|
||||
client identification TLVs added in libqmi 1.39.1, and bump the libqmi
|
||||
requirement accordingly.
|
||||
|
||||
Isolating the TLVs on the gated engine showed the client type is the
|
||||
only TLV actually checked (the client string and Enable Positioning
|
||||
Request Notification are ignored for AFW clients, matching their
|
||||
documentation in location_service_v02.h), so only the client type and
|
||||
an informational "MM" client string are sent. Should an engine reject
|
||||
the registration carrying the identification TLVs, it is retried once
|
||||
without them, i.e. exactly what was always sent before.
|
||||
|
||||
This changes the LOC messages every QMI modem sees, and it has only
|
||||
been tested on the Fairphone 6: the effect of the new TLVs and of the
|
||||
reordering on other LOC engines is unknown (the retry above bounds the
|
||||
worst case for the TLVs, not for the reordering). Regression testing
|
||||
on other QMI modems would be very welcome.
|
||||
|
||||
The tracking-events registration that previously followed a successful
|
||||
START is thereby folded into the initial register-events; the LOC
|
||||
client and NMEA handler are still only recorded in the private info
|
||||
once START has succeeded. This also fixes a pre-existing issue where a
|
||||
register-events failure after a successful START returned an error
|
||||
while leaving the engine running with no indication handlers connected.
|
||||
|
||||
Signed-off-by: Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net>
|
||||
---
|
||||
meson.build | 2 +-
|
||||
src/mm-shared-qmi.c | 139 +++++++++++++++++++++++++++-----------------
|
||||
2 files changed, 86 insertions(+), 55 deletions(-)
|
||||
|
||||
diff --git a/meson.build b/meson.build
|
||||
index 3cf29e80..e5e3d0be 100644
|
||||
--- a/meson.build
|
||||
+++ b/meson.build
|
||||
@@ -277,7 +277,7 @@ config_h.set('WITH_MBIM', enable_mbim)
|
||||
# QMI support (enabled by default)
|
||||
enable_qmi = get_option('qmi')
|
||||
if enable_qmi
|
||||
- qmi_glib_dep = dependency('qmi-glib', version: '>= 1.37.95',
|
||||
+ qmi_glib_dep = dependency('qmi-glib', version: '>= 1.39.1',
|
||||
required: not get_option('subproject-fallback'))
|
||||
|
||||
if not qmi_glib_dep.found() and get_option('subproject-fallback')
|
||||
diff --git a/src/mm-shared-qmi.c b/src/mm-shared-qmi.c
|
||||
index d93698a6..09aa987a 100644
|
||||
--- a/src/mm-shared-qmi.c
|
||||
+++ b/src/mm-shared-qmi.c
|
||||
@@ -5646,33 +5646,67 @@ pds_gps_service_state_start_ready (QmiClientPds *client,
|
||||
qmi_message_pds_set_auto_tracking_state_input_unref (input);
|
||||
}
|
||||
|
||||
+static void loc_register_events_ready (QmiClientLoc *client, GAsyncResult *res, GTask *task);
|
||||
+
|
||||
+/* Send the LOC event registration, optionally identifying as an
|
||||
+ * application framework ("AFW", i.e. the Android framework) client: some
|
||||
+ * GNSS engines (e.g. gnss8 in the SM7635) only allow positioning for AFW
|
||||
+ * clients, and reject both event registration and QMI_LOC_START for
|
||||
+ * unidentified clients. */
|
||||
static void
|
||||
-loc_register_events_ready (QmiClientLoc *client,
|
||||
- GAsyncResult *res,
|
||||
- GTask *task)
|
||||
+gps_engine_loc_register_events (QmiClientLoc *client,
|
||||
+ GTask *task,
|
||||
+ gboolean identify)
|
||||
{
|
||||
- MMSharedQmi *self;
|
||||
- Private *priv;
|
||||
- QmiMessageLocRegisterEventsOutput *output;
|
||||
- GError *error = NULL;
|
||||
+ QmiMessageLocRegisterEventsInput *input;
|
||||
+ guint64 event_mask;
|
||||
+
|
||||
+ event_mask = QMI_LOC_EVENT_REGISTRATION_FLAG_NMEA |
|
||||
+ QMI_LOC_EVENT_REGISTRATION_FLAG_INJECT_TIME_REQUEST |
|
||||
+ QMI_LOC_EVENT_REGISTRATION_FLAG_INJECT_POSITION_REQUEST;
|
||||
+ input = qmi_message_loc_register_events_input_new ();
|
||||
+ qmi_message_loc_register_events_input_set_event_registration_mask (input, event_mask, NULL);
|
||||
+ if (identify) {
|
||||
+ qmi_message_loc_register_events_input_set_client_type (input, QMI_LOC_CLIENT_TYPE_AFW, NULL);
|
||||
+ qmi_message_loc_register_events_input_set_client_string_id (input, "MM", NULL);
|
||||
+ }
|
||||
+ g_task_set_task_data (task, GUINT_TO_POINTER (identify), NULL);
|
||||
+ qmi_client_loc_register_events (client,
|
||||
+ input,
|
||||
+ 10,
|
||||
+ NULL,
|
||||
+ (GAsyncReadyCallback) loc_register_events_ready,
|
||||
+ task);
|
||||
+ qmi_message_loc_register_events_input_unref (input);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+loc_start_ready (QmiClientLoc *client,
|
||||
+ GAsyncResult *res,
|
||||
+ GTask *task)
|
||||
+{
|
||||
+ MMSharedQmi *self;
|
||||
+ Private *priv;
|
||||
+ QmiMessageLocStartOutput *output;
|
||||
+ GError *error = NULL;
|
||||
|
||||
- output = qmi_client_loc_register_events_finish (client, res, &error);
|
||||
- if (!output) {
|
||||
+ output = qmi_client_loc_start_finish (client, res, &error);
|
||||
+ if (!output) {
|
||||
g_prefix_error (&error, "QMI operation failed: ");
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
- }
|
||||
+ }
|
||||
|
||||
- if (!qmi_message_loc_register_events_output_get_result (output, &error)) {
|
||||
- g_prefix_error (&error, "Couldn't not register tracking events: ");
|
||||
+ if (!qmi_message_loc_start_output_get_result (output, &error)) {
|
||||
+ g_prefix_error (&error, "Couldn't start GPS engine: ");
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
- qmi_message_loc_register_events_output_unref (output);
|
||||
+ qmi_message_loc_start_output_unref (output);
|
||||
return;
|
||||
}
|
||||
|
||||
- qmi_message_loc_register_events_output_unref (output);
|
||||
+ qmi_message_loc_start_output_unref (output);
|
||||
|
||||
self = g_task_get_source_object (task);
|
||||
priv = get_private (self);
|
||||
@@ -5691,16 +5725,16 @@ loc_register_events_ready (QmiClientLoc *client,
|
||||
}
|
||||
|
||||
static void
|
||||
-loc_start_ready (QmiClientLoc *client,
|
||||
- GAsyncResult *res,
|
||||
- GTask *task)
|
||||
+loc_register_events_ready (QmiClientLoc *client,
|
||||
+ GAsyncResult *res,
|
||||
+ GTask *task)
|
||||
{
|
||||
- QmiMessageLocRegisterEventsInput *input;
|
||||
- QmiMessageLocStartOutput *output;
|
||||
- guint64 event_mask;
|
||||
- GError *error = NULL;
|
||||
+ MMSharedQmi *self;
|
||||
+ QmiMessageLocRegisterEventsOutput *output;
|
||||
+ QmiMessageLocStartInput *input;
|
||||
+ GError *error = NULL;
|
||||
|
||||
- output = qmi_client_loc_start_finish (client, res, &error);
|
||||
+ output = qmi_client_loc_register_events_finish (client, res, &error);
|
||||
if (!output) {
|
||||
g_prefix_error (&error, "QMI operation failed: ");
|
||||
g_task_return_error (task, error);
|
||||
@@ -5708,32 +5742,40 @@ loc_start_ready (QmiClientLoc *client,
|
||||
return;
|
||||
}
|
||||
|
||||
- if (!qmi_message_loc_start_output_get_result (output, &error)) {
|
||||
- g_prefix_error (&error, "Couldn't start GPS engine: ");
|
||||
+ if (!qmi_message_loc_register_events_output_get_result (output, &error)) {
|
||||
+ qmi_message_loc_register_events_output_unref (output);
|
||||
+ /* Engines predating the client identification TLVs may reject the
|
||||
+ * identified registration; retry once without identifying, which
|
||||
+ * matches what was always sent before */
|
||||
+ if (g_task_get_task_data (task)) {
|
||||
+ self = g_task_get_source_object (task);
|
||||
+ mm_obj_dbg (self, "couldn't register location events as AFW client: %s; retrying without client identification", error->message);
|
||||
+ g_clear_error (&error);
|
||||
+ gps_engine_loc_register_events (client, task, FALSE);
|
||||
+ return;
|
||||
+ }
|
||||
+ g_prefix_error (&error, "Couldn't register location events: ");
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
- qmi_message_loc_start_output_unref (output);
|
||||
return;
|
||||
}
|
||||
|
||||
- qmi_message_loc_start_output_unref (output);
|
||||
+ qmi_message_loc_register_events_output_unref (output);
|
||||
|
||||
- input = qmi_message_loc_register_events_input_new ();
|
||||
- event_mask = QMI_LOC_EVENT_REGISTRATION_FLAG_NMEA |
|
||||
- QMI_LOC_EVENT_REGISTRATION_FLAG_INJECT_TIME_REQUEST |
|
||||
- QMI_LOC_EVENT_REGISTRATION_FLAG_INJECT_POSITION_REQUEST;
|
||||
- qmi_message_loc_register_events_input_set_event_registration_mask (
|
||||
- input, event_mask, NULL);
|
||||
- qmi_client_loc_register_events (client,
|
||||
- input,
|
||||
- 10,
|
||||
- NULL,
|
||||
- (GAsyncReadyCallback) loc_register_events_ready,
|
||||
- task);
|
||||
- qmi_message_loc_register_events_input_unref (input);
|
||||
+ input = qmi_message_loc_start_input_new ();
|
||||
+ qmi_message_loc_start_input_set_session_id (input, DEFAULT_LOC_SESSION_ID, NULL);
|
||||
+ qmi_message_loc_start_input_set_intermediate_report_state (input, QMI_LOC_INTERMEDIATE_REPORT_STATE_DISABLE, NULL);
|
||||
+ qmi_message_loc_start_input_set_minimum_interval_between_position_reports (input, 1000, NULL);
|
||||
+ qmi_message_loc_start_input_set_fix_recurrence_type (input, QMI_LOC_FIX_RECURRENCE_TYPE_REQUEST_PERIODIC_FIXES, NULL);
|
||||
+ qmi_client_loc_start (client,
|
||||
+ input,
|
||||
+ 10,
|
||||
+ NULL,
|
||||
+ (GAsyncReadyCallback) loc_start_ready,
|
||||
+ task);
|
||||
+ qmi_message_loc_start_input_unref (input);
|
||||
}
|
||||
|
||||
-
|
||||
static void
|
||||
start_gps_engine (MMSharedQmi *self,
|
||||
GAsyncReadyCallback callback,
|
||||
@@ -5771,20 +5813,9 @@ start_gps_engine (MMSharedQmi *self,
|
||||
MM_PORT_QMI_FLAG_DEFAULT,
|
||||
NULL);
|
||||
if (client) {
|
||||
- QmiMessageLocStartInput *input;
|
||||
-
|
||||
- input = qmi_message_loc_start_input_new ();
|
||||
- qmi_message_loc_start_input_set_session_id (input, DEFAULT_LOC_SESSION_ID, NULL);
|
||||
- qmi_message_loc_start_input_set_intermediate_report_state (input, QMI_LOC_INTERMEDIATE_REPORT_STATE_DISABLE, NULL);
|
||||
- qmi_message_loc_start_input_set_minimum_interval_between_position_reports (input, 1000, NULL);
|
||||
- qmi_message_loc_start_input_set_fix_recurrence_type (input, QMI_LOC_FIX_RECURRENCE_TYPE_REQUEST_PERIODIC_FIXES, NULL);
|
||||
- qmi_client_loc_start (QMI_CLIENT_LOC (client),
|
||||
- input,
|
||||
- 10,
|
||||
- NULL,
|
||||
- (GAsyncReadyCallback) loc_start_ready,
|
||||
- task);
|
||||
- qmi_message_loc_start_input_unref (input);
|
||||
+ /* Register events before starting; register-before-start is the
|
||||
+ * order the Qualcomm location HAL uses */
|
||||
+ gps_engine_loc_register_events (QMI_CLIENT_LOC (client), task, TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
--
|
||||
2.55.0
|
||||
|
||||
|
|
@ -0,0 +1,251 @@
|
|||
From 7566587e77d299ab0f67613ae03cab9973e351db Mon Sep 17 00:00:00 2001
|
||||
From: Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net>
|
||||
Date: Thu, 2 Jul 2026 15:44:16 +0200
|
||||
Subject: [PATCH 3/3] shared-qmi: derive location from Position Report
|
||||
indications
|
||||
|
||||
Some GNSS engines (e.g. gnss8 in the SM7635/Fairphone 6) report fixes
|
||||
only via QMI_LOC Position Report indications and never emit NMEA (Set
|
||||
NMEA Types returns NotSupported), while location is derived exclusively
|
||||
from NMEA traces. As a result no location was surfaced even with the
|
||||
engine running and tracking satellites.
|
||||
|
||||
Register for the POSITION_REPORT event and synthesize minimal $GPGGA
|
||||
and $GPRMC sentences from Position Report indications carrying a
|
||||
successful fix (intermediate reports are disabled at engine start),
|
||||
feeding the existing NMEA-based pipeline so that gps-raw and gps-nmea
|
||||
both work on these engines too. Synthesizing NMEA rather than extending
|
||||
the location interface keeps the change local to the QMI backend.
|
||||
|
||||
To avoid polluting the location output of engines that do emit NMEA
|
||||
with duplicate synthesized sentences, position reports are ignored as
|
||||
soon as a real NMEA indication has been seen for the current engine
|
||||
run. In the worst case an NMEA-emitting engine could have a few
|
||||
synthesized sentences slip in before its first real NMEA arrives, but
|
||||
NMEA engines emit sentences immediately (fix or not) while a position
|
||||
report needs a valid fix, so real NMEA wins that race in practice.
|
||||
Values the position report does not carry are left as empty NMEA
|
||||
fields rather than invented, and $GPRMC is only synthesized when the
|
||||
report carries a UTC timestamp, as an RMC sentence without one is
|
||||
meaningless.
|
||||
|
||||
Tested on the Fairphone 6 (SM7635): with both patches applied,
|
||||
enabling gps-nmea/gps-raw via mmcli surfaces a correct live fix
|
||||
(lat/lon/altitude/UTC) from the synthesized sentences; position
|
||||
reports without a valid fix (session status 'timeout' while indoors)
|
||||
are correctly ignored. The effect on other LOC engines (now also
|
||||
receiving the POSITION_REPORT registration) has not been verified on
|
||||
real hardware.
|
||||
|
||||
Signed-off-by: Jorijn van der Graaf <jorijnvdgraaf@catcrafts.net>
|
||||
---
|
||||
src/mm-shared-qmi.c | 147 ++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 147 insertions(+)
|
||||
|
||||
diff --git a/src/mm-shared-qmi.c b/src/mm-shared-qmi.c
|
||||
index 09aa987a..cad75080 100644
|
||||
--- a/src/mm-shared-qmi.c
|
||||
+++ b/src/mm-shared-qmi.c
|
||||
@@ -88,6 +88,8 @@ typedef struct {
|
||||
gulong pds_location_event_report_indication_id;
|
||||
QmiClient *loc_client;
|
||||
gulong loc_location_nmea_indication_id;
|
||||
+ gulong loc_location_position_report_indication_id;
|
||||
+ gboolean loc_location_nmea_received;
|
||||
gchar **loc_assistance_data_servers;
|
||||
guint32 loc_assistance_data_max_file_size;
|
||||
guint32 loc_assistance_data_max_part_size;
|
||||
@@ -126,6 +128,8 @@ private_free (Private *priv)
|
||||
g_object_unref (priv->pds_client);
|
||||
if (priv->loc_location_nmea_indication_id)
|
||||
g_signal_handler_disconnect (priv->loc_client, priv->loc_location_nmea_indication_id);
|
||||
+ if (priv->loc_location_position_report_indication_id)
|
||||
+ g_signal_handler_disconnect (priv->loc_client, priv->loc_location_position_report_indication_id);
|
||||
if (priv->loc_assistance_inject_time_req_indication_id)
|
||||
g_signal_handler_disconnect (priv->loc_client, priv->loc_assistance_inject_time_req_indication_id);
|
||||
if (priv->loc_assistance_inject_position_req_indication_id)
|
||||
@@ -5161,6 +5165,10 @@ loc_stop_ready (QmiClientLoc *client,
|
||||
g_signal_handler_disconnect (priv->loc_client, priv->loc_location_nmea_indication_id);
|
||||
priv->loc_location_nmea_indication_id = 0;
|
||||
}
|
||||
+ if (priv->loc_location_position_report_indication_id != 0) {
|
||||
+ g_signal_handler_disconnect (priv->loc_client, priv->loc_location_position_report_indication_id);
|
||||
+ priv->loc_location_position_report_indication_id = 0;
|
||||
+ }
|
||||
g_clear_object (&priv->loc_client);
|
||||
}
|
||||
|
||||
@@ -5264,11 +5272,142 @@ loc_location_nmea_indication_cb (QmiClientLoc *client,
|
||||
if (!nmea)
|
||||
return;
|
||||
|
||||
+ priv->loc_location_nmea_received = TRUE;
|
||||
+
|
||||
mm_obj_dbg (self, "[NMEA] %s", nmea);
|
||||
mm_iface_modem_location_gps_update (MM_IFACE_MODEM_LOCATION (self), nmea);
|
||||
mm_location_cache_update_from_nmea (priv->location_cache, nmea);
|
||||
}
|
||||
|
||||
+/* Build a NMEA sentence ("$" + body + "*" + XOR checksum) from its body */
|
||||
+static gchar *
|
||||
+nmea_sentence_new (const gchar *body)
|
||||
+{
|
||||
+ guint8 checksum = 0;
|
||||
+ const gchar *p;
|
||||
+
|
||||
+ for (p = body; *p; p++)
|
||||
+ checksum ^= (guint8) *p;
|
||||
+ return g_strdup_printf ("$%s*%02X", body, checksum);
|
||||
+}
|
||||
+
|
||||
+/* Some GNSS engines (e.g. gnss8 in the SM7635) report fixes only via
|
||||
+ * Position Report indications and never emit NMEA. Synthesize minimal
|
||||
+ * $GPGGA/$GPRMC sentences from the position report so that the existing
|
||||
+ * NMEA-based location pipeline (gps-raw and gps-nmea) also works on those
|
||||
+ * engines. Not used on engines seen emitting NMEA themselves. */
|
||||
+static void
|
||||
+loc_location_position_report_indication_cb (QmiClientLoc *client,
|
||||
+ QmiIndicationLocPositionReportOutput *output,
|
||||
+ MMSharedQmi *self)
|
||||
+{
|
||||
+ Private *priv;
|
||||
+ QmiLocSessionStatus session_status = QMI_LOC_SESSION_STATUS_GENERAL_FAILURE;
|
||||
+ gdouble latitude = 0.0;
|
||||
+ gdouble longitude = 0.0;
|
||||
+ gfloat altitude = 0.0;
|
||||
+ gfloat speed = 0.0;
|
||||
+ gfloat heading = 0.0;
|
||||
+ guint64 timestamp = 0;
|
||||
+ gdouble absolute;
|
||||
+ gdouble minutes;
|
||||
+ guint degrees;
|
||||
+ gchar ns;
|
||||
+ gchar ew;
|
||||
+ gchar latbuf[32];
|
||||
+ gchar lonbuf[32];
|
||||
+ gchar timebuf[16] = "";
|
||||
+ gchar datebuf[8] = "";
|
||||
+ gchar altbuf[16] = "";
|
||||
+ gchar speedbuf[16] = "";
|
||||
+ gchar headingbuf[16] = "";
|
||||
+ g_autofree gchar *gga_body = NULL;
|
||||
+ g_autofree gchar *gga = NULL;
|
||||
+
|
||||
+ priv = get_private (self);
|
||||
+
|
||||
+ /* Engines that emit NMEA themselves don't need synthesized sentences */
|
||||
+ if (priv->loc_location_nmea_received)
|
||||
+ return;
|
||||
+
|
||||
+ /* Only surface reports carrying a valid fix; intermediate reports are
|
||||
+ * disabled at engine start */
|
||||
+ if (!qmi_indication_loc_position_report_output_get_session_status (output, &session_status, NULL) ||
|
||||
+ (session_status != QMI_LOC_SESSION_STATUS_SUCCESS))
|
||||
+ return;
|
||||
+
|
||||
+ if (!qmi_indication_loc_position_report_output_get_latitude (output, &latitude, NULL) ||
|
||||
+ !qmi_indication_loc_position_report_output_get_longitude (output, &longitude, NULL))
|
||||
+ return;
|
||||
+
|
||||
+ /* Unavailable optional values are left as empty NMEA fields */
|
||||
+ if (qmi_indication_loc_position_report_output_get_utc_timestamp (output, ×tamp, NULL)) {
|
||||
+ g_autoptr(GDateTime) utc = NULL;
|
||||
+
|
||||
+ utc = g_date_time_new_from_unix_utc ((gint64) (timestamp / 1000));
|
||||
+ if (utc) {
|
||||
+ g_snprintf (timebuf, sizeof (timebuf), "%02d%02d%02d.%02u",
|
||||
+ g_date_time_get_hour (utc),
|
||||
+ g_date_time_get_minute (utc),
|
||||
+ g_date_time_get_second (utc),
|
||||
+ (guint) ((timestamp % 1000) / 10));
|
||||
+ g_snprintf (datebuf, sizeof (datebuf), "%02d%02d%02d",
|
||||
+ g_date_time_get_day_of_month (utc),
|
||||
+ g_date_time_get_month (utc),
|
||||
+ g_date_time_get_year (utc) % 100);
|
||||
+ }
|
||||
+ }
|
||||
+ if (qmi_indication_loc_position_report_output_get_altitude_from_sealevel (output, &altitude, NULL))
|
||||
+ g_snprintf (altbuf, sizeof (altbuf), "%.1f", (gdouble) altitude);
|
||||
+ if (qmi_indication_loc_position_report_output_get_horizontal_speed (output, &speed, NULL))
|
||||
+ g_snprintf (speedbuf, sizeof (speedbuf), "%.1f", (gdouble) speed * 1.943844); /* m/s -> knots */
|
||||
+ if (qmi_indication_loc_position_report_output_get_heading (output, &heading, NULL))
|
||||
+ g_snprintf (headingbuf, sizeof (headingbuf), "%.1f", (gdouble) heading);
|
||||
+
|
||||
+ ns = (latitude >= 0.0) ? 'N' : 'S';
|
||||
+ absolute = (latitude >= 0.0) ? latitude : -latitude;
|
||||
+ degrees = (guint) absolute;
|
||||
+ minutes = (absolute - degrees) * 60.0;
|
||||
+ /* %.6f rounding must not print out-of-spec 60.000000 minutes */
|
||||
+ if (minutes >= 60.0 - 0.0000005) {
|
||||
+ minutes = 0.0;
|
||||
+ degrees++;
|
||||
+ }
|
||||
+ g_snprintf (latbuf, sizeof (latbuf), "%02u%09.6f", degrees, minutes);
|
||||
+
|
||||
+ ew = (longitude >= 0.0) ? 'E' : 'W';
|
||||
+ absolute = (longitude >= 0.0) ? longitude : -longitude;
|
||||
+ degrees = (guint) absolute;
|
||||
+ minutes = (absolute - degrees) * 60.0;
|
||||
+ if (minutes >= 60.0 - 0.0000005) {
|
||||
+ minutes = 0.0;
|
||||
+ degrees++;
|
||||
+ }
|
||||
+ g_snprintf (lonbuf, sizeof (lonbuf), "%03u%09.6f", degrees, minutes);
|
||||
+
|
||||
+ gga_body = g_strdup_printf ("GPGGA,%s,%s,%c,%s,%c,1,,,%s,M,,M,,",
|
||||
+ timebuf, latbuf, ns, lonbuf, ew, altbuf);
|
||||
+ gga = nmea_sentence_new (gga_body);
|
||||
+
|
||||
+ mm_obj_dbg (self, "[position-report] %s", gga);
|
||||
+ mm_iface_modem_location_gps_update (MM_IFACE_MODEM_LOCATION (self), gga);
|
||||
+ mm_location_cache_update_from_nmea (priv->location_cache, gga);
|
||||
+
|
||||
+ /* An RMC sentence without a UTC timestamp would be meaningless */
|
||||
+ if (timebuf[0]) {
|
||||
+ g_autofree gchar *rmc_body = NULL;
|
||||
+ g_autofree gchar *rmc = NULL;
|
||||
+
|
||||
+ rmc_body = g_strdup_printf ("GPRMC,%s,A,%s,%c,%s,%c,%s,%s,%s,,",
|
||||
+ timebuf, latbuf, ns, lonbuf, ew, speedbuf, headingbuf, datebuf);
|
||||
+ rmc = nmea_sentence_new (rmc_body);
|
||||
+
|
||||
+ mm_obj_dbg (self, "[position-report] %s", rmc);
|
||||
+ mm_iface_modem_location_gps_update (MM_IFACE_MODEM_LOCATION (self), rmc);
|
||||
+ mm_location_cache_update_from_nmea (priv->location_cache, rmc);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/*****************************************************************************/
|
||||
/* Location: internal helper: setup minimum required NMEA traces */
|
||||
|
||||
@@ -5662,6 +5801,7 @@ gps_engine_loc_register_events (QmiClientLoc *client,
|
||||
guint64 event_mask;
|
||||
|
||||
event_mask = QMI_LOC_EVENT_REGISTRATION_FLAG_NMEA |
|
||||
+ QMI_LOC_EVENT_REGISTRATION_FLAG_POSITION_REPORT |
|
||||
QMI_LOC_EVENT_REGISTRATION_FLAG_INJECT_TIME_REQUEST |
|
||||
QMI_LOC_EVENT_REGISTRATION_FLAG_INJECT_POSITION_REQUEST;
|
||||
input = qmi_message_loc_register_events_input_new ();
|
||||
@@ -5713,12 +5853,19 @@ loc_start_ready (QmiClientLoc *client,
|
||||
|
||||
g_assert (!priv->loc_client);
|
||||
g_assert (!priv->loc_location_nmea_indication_id);
|
||||
+ g_assert (!priv->loc_location_position_report_indication_id);
|
||||
priv->loc_client = QMI_CLIENT (g_object_ref (client));
|
||||
+ priv->loc_location_nmea_received = FALSE;
|
||||
priv->loc_location_nmea_indication_id =
|
||||
g_signal_connect (client,
|
||||
"nmea",
|
||||
G_CALLBACK (loc_location_nmea_indication_cb),
|
||||
self);
|
||||
+ priv->loc_location_position_report_indication_id =
|
||||
+ g_signal_connect (client,
|
||||
+ "position-report",
|
||||
+ G_CALLBACK (loc_location_position_report_indication_cb),
|
||||
+ self);
|
||||
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
--
|
||||
2.55.0
|
||||
|
||||
Loading…
Reference in a new issue