[PATCH 4/5] cinterion: support AT^SGPSC capable modems
Aleksander Morgado
aleksander at aleksander.es
Wed May 17 13:24:03 UTC 2017
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);
+ /* 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)) {
--
2.12.2
More information about the ModemManager-devel
mailing list