On Wed, 2017-05-17 at 15:24 +0200, Aleksander Morgado wrote: > The AT^SGPSS command provides an easy way to just start/stop GPS, but > unfortunately it isn't supported by all Cinterion modems. > > The AT^SGPSC command instead is more widely available but it requires > several steps to start and stop the different elements of the GPS > receiver. > > Implement support for both, preferring AT^SGPSSS if available and > falling back to AT^SGPSC otherwise. > --- > plugins/cinterion/mm-common-cinterion.c | 209 > +++++++++++++++++++++++++++----- > 1 file changed, 182 insertions(+), 27 deletions(-) > > diff --git a/plugins/cinterion/mm-common-cinterion.c > b/plugins/cinterion/mm-common-cinterion.c > index ce337bd9..6e839c8d 100644 > --- a/plugins/cinterion/mm-common-cinterion.c > +++ b/plugins/cinterion/mm-common-cinterion.c > @@ -36,6 +36,7 @@ typedef enum { > typedef struct { > MMModemLocationSource enabled_sources; > FeatureSupport sgpss_support; > + FeatureSupport sgpsc_support; > } LocationContext; > > static void > @@ -59,6 +60,7 @@ get_location_context (MMBaseModem *self) > ctx = g_slice_new (LocationContext); > ctx->enabled_sources = MM_MODEM_LOCATION_SOURCE_NONE; > ctx->sgpss_support = FEATURE_SUPPORT_UNKNOWN; > + ctx->sgpsc_support = FEATURE_SUPPORT_UNKNOWN; > > g_object_set_qdata_full ( > G_OBJECT (self), > @@ -131,6 +133,30 @@ mm_common_cinterion_location_load_capabilities_finish > (MMIfaceModemLocation *se > static void probe_gps_features (GTask *task); > > static void > +sgpsc_test_ready (MMBaseModem *self, > + GAsyncResult *res, > + GTask *task) > +{ > + LocationContext *location_ctx; > + > + location_ctx = get_location_context (self); > + if (!mm_base_modem_at_command_finish (self, res, NULL)) > + location_ctx->sgpsc_support = FEATURE_NOT_SUPPORTED; > + else { > + /* ^SGPSC supported! */ > + location_ctx->sgpsc_support = FEATURE_SUPPORTED; > + /* It may happen that the modem was started with GPS already > enabled, or > + * maybe ModemManager got rebooted and it was left enabled before. > We'll > + * make sure that it is disabled when we initialize the modem. */ > + mm_base_modem_at_command (MM_BASE_MODEM (self), > "AT^SGPSC=\"Engine\",\"0\"", 3, FALSE, NULL, NULL); > + mm_base_modem_at_command (MM_BASE_MODEM (self), > "AT^SGPSC=\"Power/Antenna\",\"off\"", 3, FALSE, NULL, NULL); > + mm_base_modem_at_command (MM_BASE_MODEM (self), > "AT^SGPSC=\"NMEA/Output\",\"off\"", 3, FALSE, NULL, NULL); > + } > + > + probe_gps_features (task); > +} > + > +static void > sgpss_test_ready (MMBaseModem *self, > GAsyncResult *res, > GTask *task) > @@ -143,6 +169,11 @@ sgpss_test_ready (MMBaseModem *self, > else { > /* ^SGPSS supported! */ > location_ctx->sgpss_support = FEATURE_SUPPORTED; > + > + /* Flag ^SGPSC as unsupported, even if it may be supported, so that > we > + * only use one set of commands to enable/disable GPS. */ > + location_ctx->sgpsc_support = FEATURE_NOT_SUPPORTED; > + > /* It may happen that the modem was started with GPS already > enabled, or > * maybe ModemManager got rebooted and it was left enabled before. > We'll > * make sure that it is disabled when we initialize the modem. */ > @@ -169,8 +200,14 @@ probe_gps_features (GTask *task) > return; > } > > + /* Need to check if SGPSC supported... */ > + if (location_ctx->sgpsc_support == FEATURE_SUPPORT_UNKNOWN) { > + mm_base_modem_at_command (self, "AT^SGPSC=?", 3, TRUE, > (GAsyncReadyCallback) sgpsc_test_ready, task); > + return; > + } > + > /* All GPS features probed, check if GPS supported */ > - if (location_ctx->sgpss_support == FEATURE_SUPPORTED) { > + if (location_ctx->sgpss_support == FEATURE_SUPPORTED || > location_ctx->sgpsc_support == FEATURE_SUPPORTED) { > mm_dbg ("GPS commands supported: GPS capabilities enabled"); > ctx->sources |= (MM_MODEM_LOCATION_SOURCE_GPS_NMEA | > MM_MODEM_LOCATION_SOURCE_GPS_RAW | > @@ -244,6 +281,9 @@ mm_common_cinterion_location_load_capabilities > (MMIfaceModemLocation *self, > typedef enum { > DISABLE_LOCATION_GATHERING_GPS_STEP_FIRST, > DISABLE_LOCATION_GATHERING_GPS_STEP_SGPSS, > + DISABLE_LOCATION_GATHERING_GPS_STEP_SGPSC_ENGINE, > + DISABLE_LOCATION_GATHERING_GPS_STEP_SGPSC_ANTENNA, > + DISABLE_LOCATION_GATHERING_GPS_STEP_SGPSC_OUTPUT, > DISABLE_LOCATION_GATHERING_GPS_STEP_LAST, > } DisableLocationGatheringGpsStep; > > @@ -251,6 +291,7 @@ typedef struct { > MMModemLocationSource source; > DisableLocationGatheringGpsStep gps_step; > GError *sgpss_error; > + GError *sgpsc_error; > } DisableLocationGatheringContext; > > static void > @@ -258,6 +299,8 @@ disable_location_gathering_context_free > (DisableLocationGatheringContext *ctx) > { > if (ctx->sgpss_error) > g_error_free (ctx->sgpss_error); > + if (ctx->sgpsc_error) > + g_error_free (ctx->sgpsc_error); > g_slice_free (DisableLocationGatheringContext, ctx); > } > > @@ -272,6 +315,28 @@ mm_common_cinterion_disable_location_gathering_finish > (MMIfaceModemLocation *se > static void disable_location_gathering_context_gps_step (GTask *task); > > static void > +disable_sgpsc_ready (MMBaseModem *self, > + GAsyncResult *res, > + GTask *task) > +{ > + DisableLocationGatheringContext *ctx; > + GError *error = NULL; > + > + ctx = (DisableLocationGatheringContext *) g_task_get_task_data (task); > + > + /* Store error, if not one available already, and continue */ > + if (!mm_base_modem_at_command_finish (self, res, &error)) { > + if (!ctx->sgpsc_error) > + ctx->sgpsc_error = error; > + else > + g_error_free (error); > + } > + > + ctx->gps_step++; > + disable_location_gathering_context_gps_step (task); > +} > + > +static void > disable_sgpss_ready (MMBaseModem *self, > GAsyncResult *res, > GTask *task) > @@ -299,22 +364,61 @@ disable_location_gathering_context_gps_step (GTask > *task) > ctx = (DisableLocationGatheringContext *) g_task_get_task_data (task); > location_ctx = get_location_context (MM_BASE_MODEM (self)); > > + /* Only one of both supported */ > + g_assert ((location_ctx->sgpss_support == FEATURE_SUPPORTED) || > (location_ctx->sgpsc_support == FEATURE_SUPPORTED)); > + g_assert (!((location_ctx->sgpss_support == FEATURE_SUPPORTED) && > (location_ctx->sgpsc_support == FEATURE_SUPPORTED))); > + > switch (ctx->gps_step) { > case DISABLE_LOCATION_GATHERING_GPS_STEP_FIRST: > ctx->gps_step++; > /* Fall down to next step */ > > case DISABLE_LOCATION_GATHERING_GPS_STEP_SGPSS: > - g_assert (location_ctx->sgpss_support == FEATURE_SUPPORTED); > - mm_base_modem_at_command (MM_BASE_MODEM (self), > - "AT^SGPSS=0", > - 3, FALSE, (GAsyncReadyCallback) > disable_sgpss_ready, task); > - return; > + if (location_ctx->sgpss_support == FEATURE_SUPPORTED) { > + mm_base_modem_at_command (MM_BASE_MODEM (self), > + "AT^SGPSS=0", > + 3, FALSE, (GAsyncReadyCallback) > disable_sgpss_ready, task); > + return; > + } > + ctx->gps_step++; > + /* Fall down to next step */ > + > + case DISABLE_LOCATION_GATHERING_GPS_STEP_SGPSC_ENGINE: > + if (location_ctx->sgpsc_support == FEATURE_SUPPORTED) { > + /* Engine off */ > + mm_base_modem_at_command (MM_BASE_MODEM (self), > + "AT^SGPSC=\"Engine\",\"0\"", > + 3, FALSE, (GAsyncReadyCallback) > disable_sgpsc_ready, task); > + return; > + } > + ctx->gps_step++; > + /* Fall down to next step */ > + > + case DISABLE_LOCATION_GATHERING_GPS_STEP_SGPSC_ANTENNA: > + if (location_ctx->sgpsc_support == FEATURE_SUPPORTED) { > + /* Antenna off */ > + mm_base_modem_at_command (MM_BASE_MODEM (self), > + "AT^SGPSC=\"Power/Antenna\",\"off\"", > + 3, FALSE, (GAsyncReadyCallback) > disable_sgpsc_ready, task); > + return; > + } > + ctx->gps_step++; > + /* Fall down to next step */ > + > + case DISABLE_LOCATION_GATHERING_GPS_STEP_SGPSC_OUTPUT: > + if (location_ctx->sgpsc_support == FEATURE_SUPPORTED) { > + /* NMEA output off */ > + mm_base_modem_at_command (MM_BASE_MODEM (self), > + "AT^SGPSC=\"NMEA/Output\",\"off\"", > + 3, FALSE, (GAsyncReadyCallback) > disable_sgpsc_ready, task); > + return; > + } > + ctx->gps_step++; > + /* Fall down to next step */ > > case DISABLE_LOCATION_GATHERING_GPS_STEP_LAST: > /* Only use the GPS port in NMEA/RAW setups */ > - if (ctx->source & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA | > - MM_MODEM_LOCATION_SOURCE_GPS_RAW)) { > + if (ctx->source & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA | > MM_MODEM_LOCATION_SOURCE_GPS_RAW)) { > MMPortSerialGps *gps_port; > > /* Even if we get an error here, we try to close the GPS port */ > @@ -326,6 +430,9 @@ disable_location_gathering_context_gps_step (GTask *task) > if (ctx->sgpss_error) { > g_task_return_error (task, ctx->sgpss_error); > g_clear_error (&ctx->sgpss_error); > + } else if (ctx->sgpsc_error) { > + g_task_return_error (task, ctx->sgpsc_error); > + g_clear_error (&ctx->sgpsc_error); > } else > g_task_return_boolean (task, TRUE); > g_object_unref (task); > @@ -429,13 +536,15 @@ mm_common_cinterion_disable_location_gathering > (MMIfaceModemLocation *self, > typedef enum { > ENABLE_LOCATION_GATHERING_GPS_STEP_FIRST, > ENABLE_LOCATION_GATHERING_GPS_STEP_SGPSS, > + ENABLE_LOCATION_GATHERING_GPS_STEP_SGPSC_OUTPUT, > + ENABLE_LOCATION_GATHERING_GPS_STEP_SGPSC_ANTENNA, > + ENABLE_LOCATION_GATHERING_GPS_STEP_SGPSC_ENGINE, > ENABLE_LOCATION_GATHERING_GPS_STEP_LAST, > } EnableLocationGatheringGpsStep; > > typedef struct { > MMModemLocationSource source; > EnableLocationGatheringGpsStep gps_step; > - gboolean sgpss_success; > } EnableLocationGatheringContext; > > static void > @@ -454,28 +563,35 @@ mm_common_cinterion_enable_location_gathering_finish > (MMIfaceModemLocation *sel > > static void enable_location_gathering_context_gps_step (GTask *task); > > -static void > -enable_sgpss_ready (MMBaseModem *self, > - GAsyncResult *res, > - GTask *task) > +static gboolean > +enable_location_gathering_context_gps_step_next_cb (GTask *task) > { > EnableLocationGatheringContext *ctx; > - GError *error = NULL; > > ctx = (EnableLocationGatheringContext *) g_task_get_task_data (task);
Is there a way we can check a GCancellable here? If the modem gets removed while we're enabling GPS this might call back with a dead object. Dan > + /* We jump to the next step */ > + ctx->gps_step++; > + enable_location_gathering_context_gps_step (task); > + > + return G_SOURCE_REMOVE; > +} > + > +static void > +enable_sgpsc_or_sgpss_ready (MMBaseModem *self, > + GAsyncResult *res, > + GTask *task) > +{ > + GError *error = NULL; > + > if (!mm_base_modem_at_command_finish (self, res, &error)) { > g_task_return_error (task, error); > g_object_unref (task); > return; > } > > - /* Flag as success with this method */ > - ctx->sgpss_success = TRUE; > - > - /* And jump to last step */ > - ctx->gps_step = ENABLE_LOCATION_GATHERING_GPS_STEP_LAST; > - enable_location_gathering_context_gps_step (task); > + /* Cinterion asks for 100ms between GPS commands... */ > + g_timeout_add (100, (GSourceFunc) > enable_location_gathering_context_gps_step_next_cb, task); > } > > static void > @@ -489,21 +605,60 @@ enable_location_gathering_context_gps_step (GTask *task) > ctx = (EnableLocationGatheringContext *) g_task_get_task_data (task); > location_ctx = get_location_context (MM_BASE_MODEM (self)); > > + /* Only one of both supported */ > + g_assert ((location_ctx->sgpss_support == FEATURE_SUPPORTED) || > (location_ctx->sgpsc_support == FEATURE_SUPPORTED)); > + g_assert (!((location_ctx->sgpss_support == FEATURE_SUPPORTED) && > (location_ctx->sgpsc_support == FEATURE_SUPPORTED))); > + > switch (ctx->gps_step) { > case ENABLE_LOCATION_GATHERING_GPS_STEP_FIRST: > ctx->gps_step++; > /* Fall down to next step */ > > case ENABLE_LOCATION_GATHERING_GPS_STEP_SGPSS: > - g_assert (location_ctx->sgpss_support == FEATURE_SUPPORTED); > - mm_base_modem_at_command (MM_BASE_MODEM (self), > - "AT^SGPSS=4", > - 3, FALSE, (GAsyncReadyCallback) > enable_sgpss_ready, task); > - return; > + if (location_ctx->sgpss_support == FEATURE_SUPPORTED) { > + mm_base_modem_at_command (MM_BASE_MODEM (self), > + "AT^SGPSS=4", > + 3, FALSE, (GAsyncReadyCallback) > enable_sgpsc_or_sgpss_ready, task); > + return; > + } > + ctx->gps_step++; > + /* Fall down to next step */ > > - case ENABLE_LOCATION_GATHERING_GPS_STEP_LAST: > - g_assert (ctx->sgpss_success); > + case ENABLE_LOCATION_GATHERING_GPS_STEP_SGPSC_OUTPUT: > + if (location_ctx->sgpsc_support == FEATURE_SUPPORTED) { > + /* NMEA output off */ > + mm_base_modem_at_command (MM_BASE_MODEM (self), > + "AT^SGPSC=\"NMEA/Output\",\"on\"", > + 3, FALSE, (GAsyncReadyCallback) > enable_sgpsc_or_sgpss_ready, task); > + return; > + } > + ctx->gps_step++; > + /* Fall down to next step */ > > + > + case ENABLE_LOCATION_GATHERING_GPS_STEP_SGPSC_ANTENNA: > + if (location_ctx->sgpsc_support == FEATURE_SUPPORTED) { > + /* Antenna off */ > + mm_base_modem_at_command (MM_BASE_MODEM (self), > + "AT^SGPSC=\"Power/Antenna\",\"on\"", > + 3, FALSE, (GAsyncReadyCallback) > enable_sgpsc_or_sgpss_ready, task); > + return; > + } > + ctx->gps_step++; > + /* Fall down to next step */ > + > + case ENABLE_LOCATION_GATHERING_GPS_STEP_SGPSC_ENGINE: > + if (location_ctx->sgpsc_support == FEATURE_SUPPORTED) { > + /* Engine off */ > + mm_base_modem_at_command (MM_BASE_MODEM (self), > + "AT^SGPSC=\"Engine\",\"1\"", > + 3, FALSE, (GAsyncReadyCallback) > enable_sgpsc_or_sgpss_ready, task); > + return; > + } > + ctx->gps_step++; > + /* Fall down to next step */ > + > + case ENABLE_LOCATION_GATHERING_GPS_STEP_LAST: > /* Only use the GPS port in NMEA/RAW setups */ > if (ctx->source & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA | > MM_MODEM_LOCATION_SOURCE_GPS_RAW)) { _______________________________________________ ModemManager-devel mailing list ModemManager-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/modemmanager-devel