From e68d01a9b9f22e6d021ee7c598c844d14da749b9 Mon Sep 17 00:00:00 2001 From: Aleksander Morgado Date: Thu, 3 Dec 2015 17:06:16 +0100 Subject: [PATCH] location: support updating the GPS refresh time The default setup uses a refresh time of 30s, which means that even if the GPS location updates are received at a higher frequency, the DBus interface will still expose at most one update every 30s. This patch includes a new "SetGpsRefreshTime()" method in the Location interface, which takes a single 'u' parameter, specifying the refresh rate to use, in seconds. This method also allows 0 being passed, which will make the implementation to publish the GPS location updates are soon as ModemManager detects them. Along with the new method, a "GpsRefreshTime" read-only property is exposed to specify the refresh time in effect. The new method and property will only be applicable if the device has GPS capabilities. https://bugs.freedesktop.org/show_bug.cgi?id=89924 --- cli/mmcli-modem-location.c | 93 +++++++++++++++++- docs/reference/libmm-glib/libmm-glib-sections.txt | 10 ++ ...rg.freedesktop.ModemManager1.Modem.Location.xml | 21 +++++ libmm-glib/mm-modem-location.c | 103 ++++++++++++++++++++ libmm-glib/mm-modem-location.h | 15 +++ src/mm-iface-modem-location.c | 104 ++++++++++++++++++++- 6 files changed, 339 insertions(+), 7 deletions(-) diff --git a/cli/mmcli-modem-location.c b/cli/mmcli-modem-location.c index 650ff75..ecfc0ef 100644 --- a/cli/mmcli-modem-location.c +++ b/cli/mmcli-modem-location.c @@ -64,6 +64,7 @@ static gboolean enable_gps_unmanaged_flag; static gboolean disable_gps_unmanaged_flag; static gboolean get_all_flag; static gchar *set_supl_server_str; +static gchar *set_gps_refresh_rate_str; static GOptionEntry entries[] = { { "location-status", 0, 0, G_OPTION_ARG_NONE, &status_flag, @@ -142,6 +143,10 @@ static GOptionEntry entries[] = { "Set SUPL server address", "[IP:PORT] or [URL]" }, + { "location-set-gps-refresh-rate", 0, 0, G_OPTION_ARG_STRING, &set_gps_refresh_rate_str, + "Set GPS refresh rate in seconds, or 0 disable the explicit rate.", + "[RATE]" + }, { NULL } }; @@ -203,7 +208,8 @@ mmcli_modem_location_options_enabled (void) get_gps_nmea_flag + get_gps_raw_flag + get_cdma_bs_flag) + - !!set_supl_server_str); + !!set_supl_server_str + + !!set_gps_refresh_rate_str); if (n_actions > 1) { g_printerr ("error: too many Location actions requested\n"); @@ -269,9 +275,9 @@ print_location_status (void) g_print ("\n" "%s\n" " ----------------------------\n" - " Location | capabilities: '%s'\n" - " | enabled: '%s'\n" - " | signals: '%s'\n", + " Location | capabilities: '%s'\n" + " | enabled: '%s'\n" + " | signals: '%s'\n", mm_modem_location_get_path (ctx->modem_location), capabilities_str, enabled_str, @@ -280,9 +286,22 @@ print_location_status (void) /* If A-GPS supported, show SUPL server setup */ if (mm_modem_location_get_capabilities (ctx->modem_location) & MM_MODEM_LOCATION_SOURCE_AGPS) g_print (" ----------------------------\n" - " A-GPS | SUPL server: '%s'\n", + " A-GPS | SUPL server: '%s'\n", mm_modem_location_get_supl_server (ctx->modem_location)); + /* If GPS supported, show GPS refresh rate */ + if (mm_modem_location_get_capabilities (ctx->modem_location) & (MM_MODEM_LOCATION_SOURCE_GPS_RAW | + MM_MODEM_LOCATION_SOURCE_GPS_NMEA)) { + guint rate; + + rate = mm_modem_location_get_gps_refresh_rate (ctx->modem_location); + g_print (" ----------------------------\n"); + if (rate > 0) + g_print (" GPS | refresh rate: '%u'\n", rate); + else + g_print (" GPS | refresh rate: disabled\n"); + } + g_free (capabilities_str); g_free (enabled_str); } @@ -339,6 +358,32 @@ set_supl_server_ready (MMModemLocation *modem_location, mmcli_async_operation_done (); } +static void +set_gps_refresh_rate_process_reply (gboolean result, + const GError *error) +{ + if (!result) { + g_printerr ("error: couldn't set GPS refresh rate: '%s'\n", + error ? error->message : "unknown error"); + exit (EXIT_FAILURE); + } + + g_print ("successfully set GPS refresh rate\n"); +} + +static void +set_gps_refresh_rate_ready (MMModemLocation *modem_location, + GAsyncResult *result) +{ + gboolean operation_result; + GError *error = NULL; + + operation_result = mm_modem_location_set_gps_refresh_rate_finish (modem_location, result, &error); + set_gps_refresh_rate_process_reply (operation_result, error); + + mmcli_async_operation_done (); +} + static MMModemLocationSource build_sources_from_flags (void) { @@ -587,6 +632,24 @@ get_modem_ready (GObject *source, return; } + /* Request to set GPS refresh rate? */ + if (set_gps_refresh_rate_str) { + guint rate; + + if (!mm_get_uint_from_str (set_gps_refresh_rate_str, &rate)) { + g_printerr ("error: couldn't set GPS refresh rate: invalid rate given: '%s'\n", + set_gps_refresh_rate_str); + exit (EXIT_FAILURE); + } + g_debug ("Asynchronously setting GPS refresh rate..."); + mm_modem_location_set_gps_refresh_rate (ctx->modem_location, + rate, + ctx->cancellable, + (GAsyncReadyCallback)set_gps_refresh_rate_ready, + NULL); + return; + } + g_warn_if_reached (); } @@ -692,5 +755,25 @@ mmcli_modem_location_run_synchronous (GDBusConnection *connection) return; } + /* Request to set GPS refresh rate? */ + if (set_gps_refresh_rate_str) { + gboolean result; + guint rate; + + if (!mm_get_uint_from_str (set_gps_refresh_rate_str, &rate)) { + g_printerr ("error: couldn't set GPS refresh rate: invalid rate given: '%s'\n", + set_gps_refresh_rate_str); + exit (EXIT_FAILURE); + } + + g_debug ("Synchronously setting GPS refresh rate..."); + result = mm_modem_location_set_gps_refresh_rate_sync (ctx->modem_location, + rate, + NULL, + &error); + set_gps_refresh_rate_process_reply (result, error); + return; + } + g_warn_if_reached (); } diff --git a/docs/reference/libmm-glib/libmm-glib-sections.txt b/docs/reference/libmm-glib/libmm-glib-sections.txt index 90c3ac4..27a98cd 100644 --- a/docs/reference/libmm-glib/libmm-glib-sections.txt +++ b/docs/reference/libmm-glib/libmm-glib-sections.txt @@ -382,6 +382,7 @@ mm_modem_location_get_enabled mm_modem_location_signals_location mm_modem_location_dup_supl_server mm_modem_location_get_supl_server +mm_modem_location_get_gps_refresh_rate mm_modem_location_setup mm_modem_location_setup_finish @@ -389,6 +390,9 @@ mm_modem_location_setup_sync mm_modem_location_set_supl_server mm_modem_location_set_supl_server_finish mm_modem_location_set_supl_server_sync +mm_modem_location_set_gps_refresh_rate +mm_modem_location_set_gps_refresh_rate_finish +mm_modem_location_set_gps_refresh_rate_sync mm_modem_location_get_3gpp mm_modem_location_get_3gpp_finish mm_modem_location_get_3gpp_sync @@ -2046,6 +2050,7 @@ mm_gdbus_modem_location_get_location mm_gdbus_modem_location_dup_location mm_gdbus_modem_location_dup_supl_server mm_gdbus_modem_location_get_supl_server +mm_gdbus_modem_location_get_gps_refresh_rate mm_gdbus_modem_location_call_get_location mm_gdbus_modem_location_call_get_location_finish @@ -2056,15 +2061,20 @@ mm_gdbus_modem_location_call_setup_sync mm_gdbus_modem_location_call_set_supl_server mm_gdbus_modem_location_call_set_supl_server_finish mm_gdbus_modem_location_call_set_supl_server_sync +mm_gdbus_modem_location_call_set_gps_refresh_rate +mm_gdbus_modem_location_call_set_gps_refresh_rate_finish +mm_gdbus_modem_location_call_set_gps_refresh_rate_sync mm_gdbus_modem_location_set_capabilities mm_gdbus_modem_location_set_enabled mm_gdbus_modem_location_set_location mm_gdbus_modem_location_set_signals_location mm_gdbus_modem_location_set_supl_server +mm_gdbus_modem_location_set_gps_refresh_rate mm_gdbus_modem_location_complete_get_location mm_gdbus_modem_location_complete_setup mm_gdbus_modem_location_complete_set_supl_server +mm_gdbus_modem_location_complete_set_gps_refresh_rate mm_gdbus_modem_location_interface_info mm_gdbus_modem_location_override_properties diff --git a/introspection/org.freedesktop.ModemManager1.Modem.Location.xml b/introspection/org.freedesktop.ModemManager1.Modem.Location.xml index 93cf640..c38f428 100644 --- a/introspection/org.freedesktop.ModemManager1.Modem.Location.xml +++ b/introspection/org.freedesktop.ModemManager1.Modem.Location.xml @@ -80,6 +80,20 @@ + + + + + + + + diff --git a/libmm-glib/mm-modem-location.c b/libmm-glib/mm-modem-location.c index 229d604..71b4c41 100644 --- a/libmm-glib/mm-modem-location.c +++ b/libmm-glib/mm-modem-location.c @@ -306,6 +306,91 @@ mm_modem_location_set_supl_server_sync (MMModemLocation *self, /*****************************************************************************/ +/** + * mm_modem_location_set_gps_refresh_rate_finish: + * @self: A #MMModemLocation. + * @res: The #GAsyncResult obtained from the #GAsyncReadyCallback passed to mm_modem_location_set_gps_refresh_rate(). + * @error: Return location for error or %NULL. + * + * Finishes an operation started with mm_modem_location_set_gps_refresh_rate(). + * + * Returns: %TRUE if setting the GPS refresh rate was successful, %FALSE if @error is set. + */ +gboolean +mm_modem_location_set_gps_refresh_rate_finish (MMModemLocation *self, + GAsyncResult *res, + GError **error) +{ + g_return_val_if_fail (MM_IS_MODEM_LOCATION (self), FALSE); + + return mm_gdbus_modem_location_call_set_gps_refresh_rate_finish (MM_GDBUS_MODEM_LOCATION (self), res, error); +} + +/** + * mm_modem_location_set_gps_refresh_rate: + * @self: A #MMModemLocation. + * @rate: The GPS refresh rate, in seconds. + * @cancellable: (allow-none): A #GCancellable or %NULL. + * @callback: A #GAsyncReadyCallback to call when the request is satisfied or %NULL. + * @user_data: User data to pass to @callback. + * + * Asynchronously configures the GPS refresh rate. + + * If a 0 rate is used, the GPS location updates will be immediately propagated to the interface. + * + * When the operation is finished, @callback will be invoked in the thread-default main loop of the thread you are calling this method from. + * You can then call mm_modem_location_set_gps_refresh_rate_finish() to get the result of the operation. + * + * See mm_modem_location_set_gps_refresh_rate_sync() for the synchronous, blocking version of this method. + */ +void +mm_modem_location_set_gps_refresh_rate (MMModemLocation *self, + guint rate, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + g_return_if_fail (MM_IS_MODEM_LOCATION (self)); + + mm_gdbus_modem_location_call_set_gps_refresh_rate (MM_GDBUS_MODEM_LOCATION (self), + rate, + cancellable, + callback, + user_data); +} + +/** + * mm_modem_location_set_gps_refresh_rate_sync: + * @self: A #MMModemLocation. + * @rate: The GPS refresh rate, in seconds. + * @cancellable: (allow-none): A #GCancellable or %NULL. + * @error: Return location for error or %NULL. + * + * Synchronously configures the GPS refresh rate. + * + * If a 0 rate is used, the GPS location updates will be immediately propagated to the interface. + * + * The calling thread is blocked until a reply is received. See mm_modem_location_set_gps_refresh_rate() + * for the asynchronous version of this method. + * + * Returns: %TRUE if setting the refresh rate was successful, %FALSE if @error is set. + */ +gboolean +mm_modem_location_set_gps_refresh_rate_sync (MMModemLocation *self, + guint rate, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (MM_IS_MODEM_LOCATION (self), FALSE); + + return mm_gdbus_modem_location_call_set_gps_refresh_rate_sync (MM_GDBUS_MODEM_LOCATION (self), + rate, + cancellable, + error); +} + +/*****************************************************************************/ + static gboolean build_locations (GVariant *dictionary, MMLocation3gpp **location_3gpp, @@ -791,6 +876,24 @@ mm_modem_location_dup_supl_server (MMModemLocation *self) /*****************************************************************************/ +/** + * mm_modem_location_get_gps_refresh_rate: + * @self: A #MMModemLocation. + * + * Gets the GPS refresh rate, in seconds. + * + * Returns: The GPS refresh rate, or 0 if no fixed rate is used. + */ +guint +mm_modem_location_get_gps_refresh_rate (MMModemLocation *self) +{ + g_return_val_if_fail (MM_IS_MODEM_LOCATION (self), 0); + + return mm_gdbus_modem_location_get_gps_refresh_rate (MM_GDBUS_MODEM_LOCATION (self)); +} + +/*****************************************************************************/ + static void mm_modem_location_init (MMModemLocation *self) { diff --git a/libmm-glib/mm-modem-location.h b/libmm-glib/mm-modem-location.h index 279288d..2d806be 100644 --- a/libmm-glib/mm-modem-location.h +++ b/libmm-glib/mm-modem-location.h @@ -79,6 +79,8 @@ gboolean mm_modem_location_signals_location (MMModemLocation *self) const gchar *mm_modem_location_get_supl_server (MMModemLocation *self); gchar *mm_modem_location_dup_supl_server (MMModemLocation *self); +guint mm_modem_location_get_gps_refresh_rate (MMModemLocation *self); + void mm_modem_location_setup (MMModemLocation *self, MMModemLocationSource sources, gboolean signal_location, @@ -107,6 +109,19 @@ gboolean mm_modem_location_set_supl_server_sync (MMModemLocation *self, GCancellable *cancellable, GError **error); +void mm_modem_location_set_gps_refresh_rate (MMModemLocation *self, + guint rate, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); +gboolean mm_modem_location_set_gps_refresh_rate_finish (MMModemLocation *self, + GAsyncResult *res, + GError **error); +gboolean mm_modem_location_set_gps_refresh_rate_sync (MMModemLocation *self, + guint rate, + GCancellable *cancellable, + GError **error); + void mm_modem_location_get_3gpp (MMModemLocation *self, GCancellable *cancellable, GAsyncReadyCallback callback, diff --git a/src/mm-iface-modem-location.c b/src/mm-iface-modem-location.c index bf1e64e..a15942d 100644 --- a/src/mm-iface-modem-location.c +++ b/src/mm-iface-modem-location.c @@ -253,7 +253,7 @@ mm_iface_modem_location_gps_update (MMIfaceModemLocation *self, g_assert (ctx->location_gps_nmea != NULL); if (mm_location_gps_nmea_add_trace (ctx->location_gps_nmea, nmea_trace) && (ctx->location_gps_nmea_last_time == 0 || - time (NULL) - ctx->location_gps_nmea_last_time >= MM_LOCATION_GPS_REFRESH_TIME_SECS)) { + time (NULL) - ctx->location_gps_nmea_last_time >= mm_gdbus_modem_location_get_gps_refresh_rate (skeleton))) { ctx->location_gps_nmea_last_time = time (NULL); update_nmea = TRUE; } @@ -263,7 +263,7 @@ mm_iface_modem_location_gps_update (MMIfaceModemLocation *self, g_assert (ctx->location_gps_raw != NULL); if (mm_location_gps_raw_add_trace (ctx->location_gps_raw, nmea_trace) && (ctx->location_gps_raw_last_time == 0 || - time (NULL) - ctx->location_gps_raw_last_time >= MM_LOCATION_GPS_REFRESH_TIME_SECS)) { + time (NULL) - ctx->location_gps_raw_last_time >= mm_gdbus_modem_location_get_gps_refresh_rate (skeleton))) { ctx->location_gps_raw_last_time = time (NULL); update_raw = TRUE; } @@ -1029,6 +1029,91 @@ typedef struct { MmGdbusModemLocation *skeleton; GDBusMethodInvocation *invocation; MMIfaceModemLocation *self; + guint rate; +} HandleSetGpsRefreshRateContext; + +static void +handle_set_gps_refresh_rate_context_free (HandleSetGpsRefreshRateContext *ctx) +{ + g_object_unref (ctx->skeleton); + g_object_unref (ctx->invocation); + g_object_unref (ctx->self); + g_slice_free (HandleSetGpsRefreshRateContext, ctx); +} + +static void +handle_set_gps_refresh_rate_auth_ready (MMBaseModem *self, + GAsyncResult *res, + HandleSetGpsRefreshRateContext *ctx) +{ + GError *error = NULL; + MMModemState modem_state; + + if (!mm_base_modem_authorize_finish (self, res, &error)) { + g_dbus_method_invocation_take_error (ctx->invocation, error); + handle_set_gps_refresh_rate_context_free (ctx); + return; + } + + modem_state = MM_MODEM_STATE_UNKNOWN; + g_object_get (self, + MM_IFACE_MODEM_STATE, &modem_state, + NULL); + if (modem_state < MM_MODEM_STATE_ENABLED) { + g_dbus_method_invocation_return_error (ctx->invocation, + MM_CORE_ERROR, + MM_CORE_ERROR_WRONG_STATE, + "Cannot set SUPL server: " + "device not yet enabled"); + handle_set_gps_refresh_rate_context_free (ctx); + return; + } + + /* If GPS is NOT supported, set error */ + if (!(mm_gdbus_modem_location_get_capabilities (ctx->skeleton) & ((MM_MODEM_LOCATION_SOURCE_GPS_RAW | + MM_MODEM_LOCATION_SOURCE_GPS_NMEA)))) { + g_dbus_method_invocation_return_error (ctx->invocation, + MM_CORE_ERROR, + MM_CORE_ERROR_UNSUPPORTED, + "Cannot set GPS refresh rate: GPS not supported"); + handle_set_gps_refresh_rate_context_free (ctx); + return; + } + + /* Set the new rate in the interface */ + mm_gdbus_modem_location_set_gps_refresh_rate (ctx->skeleton, ctx->rate); + mm_gdbus_modem_location_complete_set_gps_refresh_rate (ctx->skeleton, ctx->invocation); + handle_set_gps_refresh_rate_context_free (ctx); +} + +static gboolean +handle_set_gps_refresh_rate (MmGdbusModemLocation *skeleton, + GDBusMethodInvocation *invocation, + guint rate, + MMIfaceModemLocation *self) +{ + HandleSetGpsRefreshRateContext *ctx; + + ctx = g_slice_new (HandleSetGpsRefreshRateContext); + ctx->skeleton = g_object_ref (skeleton); + ctx->invocation = g_object_ref (invocation); + ctx->self = g_object_ref (self); + ctx->rate = rate; + + mm_base_modem_authorize (MM_BASE_MODEM (self), + invocation, + MM_AUTHORIZATION_DEVICE_CONTROL, + (GAsyncReadyCallback)handle_set_gps_refresh_rate_auth_ready, + ctx); + return TRUE; +} + +/*****************************************************************************/ + +typedef struct { + MmGdbusModemLocation *skeleton; + GDBusMethodInvocation *invocation; + MMIfaceModemLocation *self; } HandleGetLocationContext; static void @@ -1362,6 +1447,7 @@ typedef enum { INITIALIZATION_STEP_CAPABILITIES, INITIALIZATION_STEP_VALIDATE_CAPABILITIES, INITIALIZATION_STEP_SUPL_SERVER, + INITIALIZATION_STEP_GPS_REFRESH_RATE, INITIALIZATION_STEP_LAST } InitializationStep; @@ -1497,6 +1583,16 @@ interface_initialization_step (InitializationContext *ctx) /* Fall down to next step */ ctx->step++; + case INITIALIZATION_STEP_GPS_REFRESH_RATE: + /* If we have GPS capabilities, expose the GPS refresh rate */ + if (ctx->capabilities & ((MM_MODEM_LOCATION_SOURCE_GPS_RAW | + MM_MODEM_LOCATION_SOURCE_GPS_NMEA))) + /* Set the default rate in the interface */ + mm_gdbus_modem_location_set_gps_refresh_rate (ctx->skeleton, MM_LOCATION_GPS_REFRESH_TIME_SECS); + + /* Fall down to next step */ + ctx->step++; + case INITIALIZATION_STEP_LAST: /* We are done without errors! */ @@ -1510,6 +1606,10 @@ interface_initialization_step (InitializationContext *ctx) G_CALLBACK (handle_set_supl_server), ctx->self); g_signal_connect (ctx->skeleton, + "handle-set-gps-refresh-rate", + G_CALLBACK (handle_set_gps_refresh_rate), + ctx->self); + g_signal_connect (ctx->skeleton, "handle-get-location", G_CALLBACK (handle_get_location), ctx->self); -- 2.6.2