aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKrzysztof Drobinski <k.drobinski@camlintechnologies.com>2019-10-14 13:39:11 +0200
committerKrzysztof Drobinski <k.drobinski@camlintechnologies.com>2019-10-30 17:53:22 +0100
commiteb3f17ddccf9d54a1edd028eb0bd65380a93795a (patch)
tree5133d659abe77df99ae18f15be9f86cbf202650f
parentda729943b15f2e769469c0e7644a3d8f21e1768f (diff)
telit: Allow enabling GNSS events if NMEA port was detected
-rw-r--r--plugins/telit/mm-broadband-modem-telit.c342
1 files changed, 341 insertions, 1 deletions
diff --git a/plugins/telit/mm-broadband-modem-telit.c b/plugins/telit/mm-broadband-modem-telit.c
index 373ecaa3..c94d14c8 100644
--- a/plugins/telit/mm-broadband-modem-telit.c
+++ b/plugins/telit/mm-broadband-modem-telit.c
@@ -30,6 +30,7 @@
#include "mm-base-modem-at.h"
#include "mm-iface-modem.h"
#include "mm-iface-modem-3gpp.h"
+#include "mm-iface-modem-location.h"
#include "mm-broadband-modem-telit.h"
#include "mm-modem-helpers-telit.h"
#include "mm-telit-enums-types.h"
@@ -38,14 +39,17 @@
static void iface_modem_init (MMIfaceModem *iface);
static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface);
static void shared_telit_init (MMSharedTelit *iface);
+static void iface_modem_location_init (MMIfaceModemLocation *iface);
static MMIfaceModem *iface_modem_parent;
static MMIfaceModem3gpp *iface_modem_3gpp_parent;
+static MMIfaceModemLocation *iface_modem_location_parent;
G_DEFINE_TYPE_EXTENDED (MMBroadbandModemTelit, mm_broadband_modem_telit, MM_TYPE_BROADBAND_MODEM, 0,
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init)
- G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_TELIT, shared_telit_init));
+ G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_TELIT, shared_telit_init)
+ G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init));
#define CSIM_UNLOCK_MAX_TIMEOUT 3
@@ -62,8 +66,329 @@ struct _MMBroadbandModemTelitPrivate {
GTask *csim_lock_task;
guint csim_lock_timeout_id;
gboolean parse_qss;
+ MMModemLocationSource enabled_sources;
};
+
+typedef struct {
+ MMModemLocationSource source;
+ gint gps_enable_step;
+} LocationGatheringContext;
+
+static const gchar *gps_enable[] = {
+ "$GPSP=1",
+ "$GPSNMUN=2,1,1,1,1,1,1"
+};
+
+static gboolean
+disable_location_gathering_finish (MMIfaceModemLocation *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+gps_disabled_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ LocationGatheringContext *ctx;
+ MMPortSerialGps *gps_port;
+ GError *error = NULL;
+
+ mm_base_modem_at_command_finish (self, res, &error);
+ ctx = g_task_get_task_data (task);
+ /* Only use the GPS port in NMEA/RAW setups */
+ if (ctx->source & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA |
+ MM_MODEM_LOCATION_SOURCE_GPS_RAW)) {
+ /* Even if we get an error here, we try to close the GPS port */
+ gps_port = mm_base_modem_peek_port_gps (self);
+ if (gps_port)
+ mm_port_serial_close (MM_PORT_SERIAL (gps_port));
+ }
+
+ if (error)
+ g_task_return_error (task, error);
+ else
+ g_task_return_boolean (task, TRUE);
+
+ g_object_unref (task);
+}
+
+static void
+disable_location_gathering (MMIfaceModemLocation *self,
+ MMModemLocationSource source,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ MMBroadbandModemTelit *telit = MM_BROADBAND_MODEM_TELIT (self);
+ gboolean stop_gps = FALSE;
+ LocationGatheringContext *ctx;
+ GTask *task;
+
+ ctx = g_new (LocationGatheringContext, 1);
+ ctx->source = source;
+
+ task = g_task_new (self, NULL, callback, user_data);
+ g_task_set_task_data (task, ctx, g_free);
+
+ /* Only stop GPS engine if no GPS-related sources enabled */
+ if (source & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA |
+ MM_MODEM_LOCATION_SOURCE_GPS_RAW |
+ MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED)) {
+ telit->priv->enabled_sources &= ~source;
+
+ if (!(telit->priv->enabled_sources & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA |
+ MM_MODEM_LOCATION_SOURCE_GPS_RAW |
+ MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED)))
+ stop_gps = TRUE;
+ }
+
+ if (stop_gps) {
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ "$GPSP=0",
+ 3,
+ FALSE,
+ (GAsyncReadyCallback)gps_disabled_ready,
+ task);
+ return;
+ }
+ /* For any other location (e.g. 3GPP), or if still some GPS needed, just return */
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+static void
+gps_enabled_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ LocationGatheringContext *ctx;
+ GError *error = NULL;
+
+ ctx = g_task_get_task_data (task);
+ if (!mm_base_modem_at_command_finish (self, res, &error)) {
+ mm_warn ("telit: couldn't power up GNSS controller: '%s'", error->message);
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+ /* After Receiver was powered up we still have to enable unsolicited NMEA events */
+ if (ctx->gps_enable_step < G_N_ELEMENTS (gps_enable)) {
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ gps_enable[ctx->gps_enable_step++],
+ 3,
+ FALSE,
+ (GAsyncReadyCallback)gps_enabled_ready,
+ task);
+ return;
+ }
+ mm_info("telit: GNSS controller is powered up");
+ /* Only use the GPS port in NMEA/RAW setups */
+ if (ctx->source & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA |
+ MM_MODEM_LOCATION_SOURCE_GPS_RAW)) {
+ MMPortSerialGps *gps_port;
+
+ gps_port = mm_base_modem_peek_port_gps (self);
+ if (!gps_port ||
+ !mm_port_serial_open (MM_PORT_SERIAL (gps_port), &error)) {
+ if (error)
+ g_task_return_error (task, error);
+ else
+ g_task_return_new_error (task,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Couldn't open raw GPS serial port");
+ } else
+ g_task_return_boolean (task, TRUE);
+ }
+ else
+ g_task_return_boolean (task, TRUE);
+
+ g_object_unref (task);
+}
+
+static void
+parent_enable_location_gathering_ready (MMIfaceModemLocation *_self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ MMBroadbandModemTelit *self = MM_BROADBAND_MODEM_TELIT (_self);
+ LocationGatheringContext *ctx;
+ gboolean start_gps = FALSE;
+ GError *error = NULL;
+
+ if (!iface_modem_location_parent->enable_location_gathering_finish (_self, res, &error)) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+ /* Now our own enabling */
+ ctx = g_task_get_task_data (task);
+
+ /* NMEA, RAW and UNMANAGED are all enabled in the same way */
+ if (ctx->source & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA |
+ MM_MODEM_LOCATION_SOURCE_GPS_RAW |
+ MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED)) {
+ /* Only start GPS engine if not done already */
+ if (!(self->priv->enabled_sources & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA |
+ MM_MODEM_LOCATION_SOURCE_GPS_RAW |
+ MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED)))
+ start_gps = TRUE;
+ self->priv->enabled_sources |= ctx->source;
+ }
+
+ if (start_gps && ctx->gps_enable_step < G_N_ELEMENTS (gps_enable)) {
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ gps_enable[ctx->gps_enable_step++],
+ 3,
+ FALSE,
+ (GAsyncReadyCallback)gps_enabled_ready,
+ task);
+ return;
+ }
+ /* For any other location (e.g. 3GPP), or if GPS already running just return */
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+static void
+enable_location_gathering (MMIfaceModemLocation *self,
+ MMModemLocationSource source,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ LocationGatheringContext *ctx;
+ GTask *task;
+
+ ctx = g_new (LocationGatheringContext, 1);
+ ctx->source = source;
+ ctx->gps_enable_step = 0;
+ task = g_task_new (self, NULL, callback, user_data);
+ g_task_set_task_data (task, ctx, g_free);
+
+ /* Chain up parent's gathering enable */
+ iface_modem_location_parent->enable_location_gathering (
+ self,
+ source,
+ (GAsyncReadyCallback)parent_enable_location_gathering_ready,
+ task);
+}
+
+static void
+trace_received (MMPortSerialGps *port,
+ const gchar *trace,
+ MMIfaceModemLocation *self)
+{
+ mm_iface_modem_location_gps_update (self, trace);
+}
+
+static gboolean
+enable_location_gathering_finish (MMIfaceModemLocation *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+setup_ports (MMBroadbandModem *self)
+{
+ MMPortSerialGps *gps_data_port;
+
+ /* Call parent's setup ports first always */
+ MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_telit_parent_class)->setup_ports (self);
+
+ gps_data_port = mm_base_modem_peek_port_gps (MM_BASE_MODEM (self));
+ if (gps_data_port) {
+ /* It may happen that the modem was started with GPS already enabled,
+ * in this case GPSP AT command returns always error. Disable it for consistency
+ */
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ "$GPSP=0", 3, FALSE, FALSE, NULL);
+
+ /* Add handler for the NMEA traces */
+ mm_port_serial_gps_add_trace_handler (gps_data_port,
+ (MMPortSerialGpsTraceFn)trace_received,
+ self,
+ NULL);
+ }
+}
+
+static MMModemLocationSource
+location_load_capabilities_finish (MMIfaceModemLocation *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ GError *inner_error = NULL;
+ gssize value;
+
+ value = g_task_propagate_int (G_TASK (res), &inner_error);
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return MM_MODEM_LOCATION_SOURCE_NONE;
+ }
+ return (MMModemLocationSource)value;
+}
+
+static void
+gpsp_test_ready (MMIfaceModemLocation *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+ MMModemLocationSource sources;
+
+ sources = GPOINTER_TO_UINT (g_task_get_task_data (task));
+ mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
+ if (!error && mm_base_modem_get_port_gps (MM_BASE_MODEM (self)))
+ sources |= (MM_MODEM_LOCATION_SOURCE_GPS_NMEA |
+ MM_MODEM_LOCATION_SOURCE_GPS_RAW |
+ MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED);
+ else
+ mm_dbg ("telit: GPS controller not supported: %s", error->message);
+
+ g_clear_error(&error);
+ g_task_return_int (task, sources);
+ g_object_unref (task);
+}
+
+static void
+parent_load_capabilities_ready (MMIfaceModemLocation *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ MMModemLocationSource sources;
+ GError *error = NULL;
+
+ sources = iface_modem_location_parent->load_capabilities_finish (self, res, &error);
+ if (error) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+ return;
+ }
+ g_task_set_task_data (task, GUINT_TO_POINTER (sources), NULL);
+ mm_base_modem_at_command (MM_BASE_MODEM (self),
+ "$GPSP=?",
+ 3,
+ TRUE,
+ (GAsyncReadyCallback)gpsp_test_ready,
+ task);
+}
+
+static void
+location_load_capabilities (MMIfaceModemLocation *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ /* Chain up parent's setup */
+ iface_modem_location_parent->load_capabilities (
+ self,
+ (GAsyncReadyCallback)parent_load_capabilities_ready,
+ g_task_new (self, NULL, callback, user_data));
+}
+
/*****************************************************************************/
/* After Sim Unlock (Modem interface) */
@@ -1071,9 +1396,24 @@ shared_telit_init (MMSharedTelit *iface)
}
static void
+iface_modem_location_init (MMIfaceModemLocation *iface)
+{
+ iface_modem_location_parent = g_type_interface_peek_parent (iface);
+
+ iface->load_capabilities = location_load_capabilities;
+ iface->load_capabilities_finish = location_load_capabilities_finish;
+ iface->enable_location_gathering = enable_location_gathering;
+ iface->enable_location_gathering_finish = enable_location_gathering_finish;
+ iface->disable_location_gathering = disable_location_gathering;
+ iface->disable_location_gathering_finish = disable_location_gathering_finish;
+}
+
+static void
mm_broadband_modem_telit_class_init (MMBroadbandModemTelitClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ MMBroadbandModemClass *broadband_modem_class = MM_BROADBAND_MODEM_CLASS (klass);
g_type_class_add_private (object_class, sizeof (MMBroadbandModemTelitPrivate));
+ broadband_modem_class->setup_ports = setup_ports;
}