aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@aleksander.es>2014-07-01 15:46:12 +0200
committerAleksander Morgado <aleksander@aleksander.es>2014-07-01 15:46:57 +0200
commit15a3ebbd354017347d3d296980c7a7460c916bae (patch)
tree3732d41711eb7dc983a9881d29d5d10deff566d2
parentce5c3f5af6bac03421e329900f0a1eaa1f775eb0 (diff)
cinterion: enable GPS location reporting for the PHS8 in QMI-mode
The PHS8 in QMI-mode doesn't support GPS location retrieval via QMI, so we will fallback to use the AT-based setup and the TTY for reading NMEA traces.
-rw-r--r--plugins/Makefile.am9
-rw-r--r--plugins/cinterion/mm-broadband-modem-cinterion.c344
-rw-r--r--plugins/cinterion/mm-broadband-modem-qmi-cinterion.c92
-rw-r--r--plugins/cinterion/mm-broadband-modem-qmi-cinterion.h48
-rw-r--r--plugins/cinterion/mm-common-cinterion.c445
-rw-r--r--plugins/cinterion/mm-common-cinterion.h51
-rw-r--r--plugins/cinterion/mm-plugin-cinterion.c12
7 files changed, 666 insertions, 335 deletions
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index bf1914ac..d2cbcb1c 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -393,8 +393,17 @@ libmm_plugin_cinterion_la_SOURCES = \
cinterion/mm-plugin-cinterion.h \
cinterion/mm-modem-helpers-cinterion.c \
cinterion/mm-modem-helpers-cinterion.h \
+ cinterion/mm-common-cinterion.c \
+ cinterion/mm-common-cinterion.h \
cinterion/mm-broadband-modem-cinterion.c \
cinterion/mm-broadband-modem-cinterion.h
+
+if WITH_QMI
+libmm_plugin_cinterion_la_SOURCES += \
+ cinterion/mm-broadband-modem-qmi-cinterion.c \
+ cinterion/mm-broadband-modem-qmi-cinterion.h
+endif
+
libmm_plugin_cinterion_la_CPPFLAGS = $(PLUGIN_COMMON_COMPILER_FLAGS)
libmm_plugin_cinterion_la_LDFLAGS = $(PLUGIN_COMMON_LINKER_FLAGS)
diff --git a/plugins/cinterion/mm-broadband-modem-cinterion.c b/plugins/cinterion/mm-broadband-modem-cinterion.c
index 36ebe68f..0135c8d9 100644
--- a/plugins/cinterion/mm-broadband-modem-cinterion.c
+++ b/plugins/cinterion/mm-broadband-modem-cinterion.c
@@ -35,6 +35,7 @@
#include "mm-base-modem-at.h"
#include "mm-broadband-modem-cinterion.h"
#include "mm-modem-helpers-cinterion.h"
+#include "mm-common-cinterion.h"
static void iface_modem_init (MMIfaceModem *iface);
static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface);
@@ -42,7 +43,6 @@ static void iface_modem_messaging_init (MMIfaceModemMessaging *iface);
static void iface_modem_location_init (MMIfaceModemLocation *iface);
static MMIfaceModem *iface_modem_parent;
-static MMIfaceModemLocation *iface_modem_location_parent;
G_DEFINE_TYPE_EXTENDED (MMBroadbandModemCinterion, mm_broadband_modem_cinterion, MM_TYPE_BROADBAND_MODEM, 0,
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)
@@ -69,8 +69,6 @@ struct _MMBroadbandModemCinterionPrivate {
GArray *cnmi_supported_bm;
GArray *cnmi_supported_ds;
GArray *cnmi_supported_bfr;
-
- MMModemLocationSource enabled_sources;
};
/* Setup relationship between the band bitmask in the modem and the bitmask
@@ -340,271 +338,6 @@ messaging_check_support (MMIfaceModemMessaging *self,
}
/*****************************************************************************/
-/* Location capabilities loading (Location interface) */
-
-static MMModemLocationSource
-location_load_capabilities_finish (MMIfaceModemLocation *self,
- GAsyncResult *res,
- GError **error)
-{
- if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
- return MM_MODEM_LOCATION_SOURCE_NONE;
-
- return (MMModemLocationSource) GPOINTER_TO_UINT (g_simple_async_result_get_op_res_gpointer (
- G_SIMPLE_ASYNC_RESULT (res)));
-}
-
-static void
-parent_load_capabilities_ready (MMIfaceModemLocation *self,
- GAsyncResult *res,
- GSimpleAsyncResult *simple)
-{
- MMModemLocationSource sources;
- GError *error = NULL;
-
- sources = iface_modem_location_parent->load_capabilities_finish (self, res, &error);
- if (error) {
- g_simple_async_result_take_error (simple, error);
- g_simple_async_result_complete (simple);
- g_object_unref (simple);
- return;
- }
-
- /* Now our own check. */
- if (mm_base_modem_peek_port_gps (MM_BASE_MODEM (self)))
- sources |= (MM_MODEM_LOCATION_SOURCE_GPS_NMEA | MM_MODEM_LOCATION_SOURCE_GPS_RAW);
-
- /* So we're done, complete */
- g_simple_async_result_set_op_res_gpointer (simple,
- GUINT_TO_POINTER (sources),
- NULL);
- g_simple_async_result_complete (simple);
- g_object_unref (simple);
-}
-
-static void
-location_load_capabilities (MMIfaceModemLocation *self,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- GSimpleAsyncResult *result;
-
- result = g_simple_async_result_new (G_OBJECT (self),
- callback,
- user_data,
- location_load_capabilities);
-
- /* Chain up parent's setup */
- iface_modem_location_parent->load_capabilities (
- self,
- (GAsyncReadyCallback)parent_load_capabilities_ready,
- result);
-}
-
-/*****************************************************************************/
-/* Disable location gathering (Location interface) */
-
-static gboolean
-disable_location_gathering_finish (MMIfaceModemLocation *self,
- GAsyncResult *res,
- GError **error)
-{
- return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
-}
-
-static void
-gps_disabled_ready (MMBaseModem *self,
- GAsyncResult *res,
- GSimpleAsyncResult *simple)
-{
- MMPortSerialGps *gps_port;
- GError *error = NULL;
-
- if (!mm_base_modem_at_command_full_finish (self, res, &error))
- g_simple_async_result_take_error (simple, error);
- else
- g_simple_async_result_set_op_res_gboolean (simple, TRUE);
-
- /* 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));
-
- g_simple_async_result_complete (simple);
- g_object_unref (simple);
-}
-
-static void
-disable_location_gathering (MMIfaceModemLocation *_self,
- MMModemLocationSource source,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self);
- GSimpleAsyncResult *result;
- gboolean stop_gps = FALSE;
-
- result = g_simple_async_result_new (G_OBJECT (self),
- callback,
- user_data,
- disable_location_gathering);
-
- /* Only stop GPS engine if no GPS-related sources enabled */
- if (source & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA |
- MM_MODEM_LOCATION_SOURCE_GPS_RAW)) {
- self->priv->enabled_sources &= ~source;
-
- if (!(self->priv->enabled_sources & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA |
- MM_MODEM_LOCATION_SOURCE_GPS_RAW)))
- stop_gps = TRUE;
- }
-
- if (stop_gps) {
- /* We disable continuous GPS fixes */
- mm_base_modem_at_command_full (MM_BASE_MODEM (self),
- mm_base_modem_peek_best_at_port (MM_BASE_MODEM (self), NULL),
- "AT^SGPSS=0",
- 3,
- FALSE,
- FALSE, /* raw */
- NULL, /* cancellable */
- (GAsyncReadyCallback)gps_disabled_ready,
- result);
- return;
- }
-
- /* For any other location (e.g. 3GPP), or if still some GPS needed, just return */
- g_simple_async_result_set_op_res_gboolean (result, TRUE);
- g_simple_async_result_complete_in_idle (result);
- g_object_unref (result);
-}
-
-/*****************************************************************************/
-/* Enable location gathering (Location interface) */
-
-typedef struct {
- MMBroadbandModemCinterion *self;
- GSimpleAsyncResult *result;
- MMModemLocationSource source;
-} EnableLocationGatheringContext;
-
-static void
-enable_location_gathering_context_complete_and_free (EnableLocationGatheringContext *ctx)
-{
- g_simple_async_result_complete (ctx->result);
- g_object_unref (ctx->result);
- g_object_unref (ctx->self);
- g_slice_free (EnableLocationGatheringContext, ctx);
-}
-
-static gboolean
-enable_location_gathering_finish (MMIfaceModemLocation *self,
- GAsyncResult *res,
- GError **error)
-{
- return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
-}
-
-static void
-gps_enabled_ready (MMBaseModem *self,
- GAsyncResult *res,
- EnableLocationGatheringContext *ctx)
-{
- MMPortSerialGps *gps_port;
- GError *error = NULL;
-
- if (!mm_base_modem_at_command_full_finish (self, res, &error)) {
- g_simple_async_result_take_error (ctx->result, error);
- enable_location_gathering_context_complete_and_free (ctx);
- return;
- }
-
- 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_simple_async_result_take_error (ctx->result, error);
- else
- g_simple_async_result_set_error (ctx->result,
- MM_CORE_ERROR,
- MM_CORE_ERROR_FAILED,
- "Couldn't open raw GPS serial port");
- } else
- g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
-
- enable_location_gathering_context_complete_and_free (ctx);
-}
-
-static void
-parent_enable_location_gathering_ready (MMIfaceModemLocation *self,
- GAsyncResult *res,
- EnableLocationGatheringContext *ctx)
-{
- gboolean start_gps = FALSE;
- GError *error = NULL;
-
- if (!iface_modem_location_parent->enable_location_gathering_finish (self, res, &error)) {
- g_simple_async_result_take_error (ctx->result, error);
- enable_location_gathering_context_complete_and_free (ctx);
- return;
- }
-
- /* Now our own enabling */
-
- /* NMEA and RAW are both enabled in the same way */
- if (ctx->source & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA |
- MM_MODEM_LOCATION_SOURCE_GPS_RAW)) {
- /* Only start GPS engine if not done already */
- if (!(ctx->self->priv->enabled_sources & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA |
- MM_MODEM_LOCATION_SOURCE_GPS_RAW)))
- start_gps = TRUE;
- ctx->self->priv->enabled_sources |= ctx->source;
- }
-
- if (start_gps) {
- /* We enable continuous GPS fixes */
- mm_base_modem_at_command_full (MM_BASE_MODEM (self),
- mm_base_modem_peek_best_at_port (MM_BASE_MODEM (self), NULL),
- "AT^SGPSS=4",
- 3,
- FALSE,
- FALSE, /* raw */
- NULL, /* cancellable */
- (GAsyncReadyCallback)gps_enabled_ready,
- ctx);
- return;
- }
-
- /* For any other location (e.g. 3GPP), or if GPS already running just return */
- g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
- enable_location_gathering_context_complete_and_free (ctx);
-}
-
-static void
-enable_location_gathering (MMIfaceModemLocation *self,
- MMModemLocationSource source,
- GAsyncReadyCallback callback,
- gpointer user_data)
-{
- EnableLocationGatheringContext *ctx;
-
- ctx = g_slice_new (EnableLocationGatheringContext);
- ctx->self = g_object_ref (self);
- ctx->result = g_simple_async_result_new (G_OBJECT (self),
- callback,
- user_data,
- enable_location_gathering);
- ctx->source = source;
-
- /* Chain up parent's gathering enable */
- iface_modem_location_parent->enable_location_gathering (
- self,
- source,
- (GAsyncReadyCallback)parent_enable_location_gathering_ready,
- ctx);
-}
-
-/*****************************************************************************/
/* MODEM POWER DOWN */
static gboolean
@@ -1930,58 +1663,12 @@ after_sim_unlock (MMIfaceModem *self,
/* Setup ports (Broadband modem class) */
static void
-trace_received (MMPortSerialGps *port,
- const gchar *trace,
- MMIfaceModemLocation *self)
-{
- /* Helper to debug GPS location related issues. Don't depend on a real GPS
- * fix for debugging, just use some random values to update */
-#if 0
- if (g_str_has_prefix (trace, "$GPGGA")) {
- GString *str;
- GDateTime *now;
-
- now = g_date_time_new_now_utc ();
- str = g_string_new ("");
- g_string_append_printf (str,
- "$GPGGA,%02u%02u%02u,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47",
- g_date_time_get_hour (now),
- g_date_time_get_minute (now),
- g_date_time_get_second (now));
- mm_iface_modem_location_gps_update (self, str->str);
- g_string_free (str, TRUE);
- g_date_time_unref (now);
- return;
- }
-#endif
-
- mm_iface_modem_location_gps_update (self, trace);
-}
-
-static void
setup_ports (MMBroadbandModem *self)
{
- MMPortSerialGps *gps_data_port;
-
/* Call parent's setup ports first always */
MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_cinterion_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, 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_full (MM_BASE_MODEM (self),
- mm_base_modem_peek_best_at_port (MM_BASE_MODEM (self), NULL),
- "AT^SGPSS=0",
- 3, FALSE, FALSE, NULL, NULL, NULL);
-
- /* Add handler for the NMEA traces */
- mm_port_serial_gps_add_trace_handler (gps_data_port,
- (MMPortSerialGpsTraceFn)trace_received,
- self,
- NULL);
- }
+ mm_common_cinterion_setup_gps_port (self);
}
/*****************************************************************************/
@@ -2012,7 +1699,6 @@ mm_broadband_modem_cinterion_init (MMBroadbandModemCinterion *self)
/* Set defaults */
self->priv->sind_psinfo = TRUE; /* Initially, always try to get psinfo */
- self->priv->enabled_sources = MM_MODEM_LOCATION_SOURCE_NONE;
}
static void
@@ -2038,19 +1724,6 @@ finalize (GObject *object)
}
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
iface_modem_init (MMIfaceModem *iface)
{
iface_modem_parent = g_type_interface_peek_parent (iface);
@@ -2098,6 +1771,19 @@ iface_modem_messaging_init (MMIfaceModemMessaging *iface)
}
static void
+iface_modem_location_init (MMIfaceModemLocation *iface)
+{
+ mm_common_cinterion_peek_parent_location_interface (iface);
+
+ iface->load_capabilities = mm_common_cinterion_location_load_capabilities;
+ iface->load_capabilities_finish = mm_common_cinterion_location_load_capabilities_finish;
+ iface->enable_location_gathering = mm_common_cinterion_enable_location_gathering;
+ iface->enable_location_gathering_finish = mm_common_cinterion_enable_location_gathering_finish;
+ iface->disable_location_gathering = mm_common_cinterion_disable_location_gathering;
+ iface->disable_location_gathering_finish = mm_common_cinterion_disable_location_gathering_finish;
+}
+
+static void
mm_broadband_modem_cinterion_class_init (MMBroadbandModemCinterionClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
diff --git a/plugins/cinterion/mm-broadband-modem-qmi-cinterion.c b/plugins/cinterion/mm-broadband-modem-qmi-cinterion.c
new file mode 100644
index 00000000..05f92e4f
--- /dev/null
+++ b/plugins/cinterion/mm-broadband-modem-qmi-cinterion.c
@@ -0,0 +1,92 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2014 Ammonit Measurement GmbH
+ * Author: Aleksander Morgado <aleksander@aleksander.es>
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#include "ModemManager.h"
+#include "mm-log.h"
+#include "mm-errors-types.h"
+#include "mm-iface-modem-location.h"
+#include "mm-broadband-modem-qmi-cinterion.h"
+#include "mm-common-cinterion.h"
+
+static void iface_modem_location_init (MMIfaceModemLocation *iface);
+
+G_DEFINE_TYPE_EXTENDED (MMBroadbandModemQmiCinterion, mm_broadband_modem_qmi_cinterion, MM_TYPE_BROADBAND_MODEM_QMI, 0,
+ G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init))
+
+/*****************************************************************************/
+/* Setup ports (Broadband modem class) */
+
+static void
+setup_ports (MMBroadbandModem *self)
+{
+ /* Call parent's setup ports first always */
+ MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_qmi_cinterion_parent_class)->setup_ports (self);
+
+ mm_common_cinterion_setup_gps_port (self);
+}
+
+/*****************************************************************************/
+
+MMBroadbandModemQmiCinterion *
+mm_broadband_modem_qmi_cinterion_new (const gchar *device,
+ const gchar **drivers,
+ const gchar *plugin,
+ guint16 vendor_id,
+ guint16 product_id)
+{
+ return g_object_new (MM_TYPE_BROADBAND_MODEM_QMI_CINTERION,
+ MM_BASE_MODEM_DEVICE, device,
+ MM_BASE_MODEM_DRIVERS, drivers,
+ MM_BASE_MODEM_PLUGIN, plugin,
+ MM_BASE_MODEM_VENDOR_ID, vendor_id,
+ MM_BASE_MODEM_PRODUCT_ID, product_id,
+ NULL);
+}
+
+static void
+mm_broadband_modem_qmi_cinterion_init (MMBroadbandModemQmiCinterion *self)
+{
+}
+
+static void
+iface_modem_location_init (MMIfaceModemLocation *iface)
+{
+ mm_common_cinterion_peek_parent_location_interface (iface);
+
+ iface->load_capabilities = mm_common_cinterion_location_load_capabilities;
+ iface->load_capabilities_finish = mm_common_cinterion_location_load_capabilities_finish;
+ iface->enable_location_gathering = mm_common_cinterion_enable_location_gathering;
+ iface->enable_location_gathering_finish = mm_common_cinterion_enable_location_gathering_finish;
+ iface->disable_location_gathering = mm_common_cinterion_disable_location_gathering;
+ iface->disable_location_gathering_finish = mm_common_cinterion_disable_location_gathering_finish;
+}
+
+static void
+mm_broadband_modem_qmi_cinterion_class_init (MMBroadbandModemQmiCinterionClass *klass)
+{
+ MMBroadbandModemClass *broadband_modem_class = MM_BROADBAND_MODEM_CLASS (klass);
+
+ /* Virtual methods */
+ broadband_modem_class->setup_ports = setup_ports;
+}
diff --git a/plugins/cinterion/mm-broadband-modem-qmi-cinterion.h b/plugins/cinterion/mm-broadband-modem-qmi-cinterion.h
new file mode 100644
index 00000000..ac8f68be
--- /dev/null
+++ b/plugins/cinterion/mm-broadband-modem-qmi-cinterion.h
@@ -0,0 +1,48 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2014 Ammonit Measurement GmbH
+ * Author: Aleksander Morgado <aleksander@aleksander.es>
+ */
+
+#ifndef MM_BROADBAND_MODEM_QMI_CINTERION_QMI_H
+#define MM_BROADBAND_MODEM_QMI_CINTERION_QMI_H
+
+#include "mm-broadband-modem-qmi.h"
+
+#define MM_TYPE_BROADBAND_MODEM_QMI_CINTERION (mm_broadband_modem_qmi_cinterion_get_type ())
+#define MM_BROADBAND_MODEM_QMI_CINTERION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_MODEM_QMI_CINTERION, MMBroadbandModemQmiCinterion))
+#define MM_BROADBAND_MODEM_QMI_CINTERION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_MODEM_QMI_CINTERION, MMBroadbandModemQmiCinterionClass))
+#define MM_IS_BROADBAND_MODEM_QMI_CINTERION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_MODEM_QMI_CINTERION))
+#define MM_IS_BROADBAND_MODEM_QMI_CINTERION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_MODEM_QMI_CINTERION))
+#define MM_BROADBAND_MODEM_QMI_CINTERION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_MODEM_QMI_CINTERION, MMBroadbandModemQmiCinterionClass))
+
+typedef struct _MMBroadbandModemQmiCinterion MMBroadbandModemQmiCinterion;
+typedef struct _MMBroadbandModemQmiCinterionClass MMBroadbandModemQmiCinterionClass;
+
+struct _MMBroadbandModemQmiCinterion {
+ MMBroadbandModemQmi parent;
+};
+
+struct _MMBroadbandModemQmiCinterionClass{
+ MMBroadbandModemQmiClass parent;
+};
+
+GType mm_broadband_modem_qmi_cinterion_get_type (void);
+
+MMBroadbandModemQmiCinterion *mm_broadband_modem_qmi_cinterion_new (const gchar *device,
+ const gchar **drivers,
+ const gchar *plugin,
+ guint16 vendor_id,
+ guint16 product_id);
+
+#endif /* MM_BROADBAND_MODEM_QMI_CINTERION_H */
diff --git a/plugins/cinterion/mm-common-cinterion.c b/plugins/cinterion/mm-common-cinterion.c
new file mode 100644
index 00000000..14da0726
--- /dev/null
+++ b/plugins/cinterion/mm-common-cinterion.c
@@ -0,0 +1,445 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2014 Ammonit Measurement GmbH
+ * Author: Aleksander Morgado <aleksander@aleksander.es>
+ */
+
+#include "mm-common-cinterion.h"
+#include "mm-base-modem-at.h"
+
+static MMIfaceModemLocation *iface_modem_location_parent;
+
+/*****************************************************************************/
+
+#define CINTERION_LOCATION_CONTEXT_TAG "cinterion-location-tag"
+static GQuark cinterion_location_context_quark;
+
+/*****************************************************************************/
+
+typedef struct {
+ MMModemLocationSource enabled_sources;
+} LocationContext;
+
+static void
+location_context_free (LocationContext *ctx)
+{
+ g_slice_free (LocationContext, ctx);
+}
+
+static LocationContext *
+get_location_context (MMBaseModem *self)
+{
+ LocationContext *ctx;
+
+ if (G_UNLIKELY (!cinterion_location_context_quark))
+ cinterion_location_context_quark = (g_quark_from_static_string (
+ CINTERION_LOCATION_CONTEXT_TAG));
+
+ ctx = g_object_get_qdata (G_OBJECT (self), cinterion_location_context_quark);
+ if (!ctx) {
+ /* Create context and keep it as object data */
+ ctx = g_slice_new (LocationContext);
+ ctx->enabled_sources = MM_MODEM_LOCATION_SOURCE_NONE;
+
+ g_object_set_qdata_full (
+ G_OBJECT (self),
+ cinterion_location_context_quark,
+ ctx,
+ (GDestroyNotify)location_context_free);
+ }
+
+ return ctx;
+}
+
+
+/*****************************************************************************/
+/* Location capabilities loading (Location interface) */
+
+MMModemLocationSource
+mm_common_cinterion_location_load_capabilities_finish (MMIfaceModemLocation *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
+ return MM_MODEM_LOCATION_SOURCE_NONE;
+
+ return (MMModemLocationSource) GPOINTER_TO_UINT (g_simple_async_result_get_op_res_gpointer (
+ G_SIMPLE_ASYNC_RESULT (res)));
+}
+
+static void
+parent_load_capabilities_ready (MMIfaceModemLocation *self,
+ GAsyncResult *res,
+ GSimpleAsyncResult *simple)
+{
+ MMModemLocationSource sources;
+ GError *error = NULL;
+
+ sources = iface_modem_location_parent->load_capabilities_finish (self, res, &error);
+ if (error) {
+ g_simple_async_result_take_error (simple, error);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+ return;
+ }
+
+ /* Now our own check. */
+ if (mm_base_modem_peek_port_gps (MM_BASE_MODEM (self)))
+ sources |= (MM_MODEM_LOCATION_SOURCE_GPS_NMEA | MM_MODEM_LOCATION_SOURCE_GPS_RAW);
+
+ /* So we're done, complete */
+ g_simple_async_result_set_op_res_gpointer (simple,
+ GUINT_TO_POINTER (sources),
+ NULL);
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+}
+
+void
+mm_common_cinterion_location_load_capabilities (MMIfaceModemLocation *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *result;
+
+ result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ mm_common_cinterion_location_load_capabilities);
+
+ /* Chain up parent's setup */
+ iface_modem_location_parent->load_capabilities (
+ self,
+ (GAsyncReadyCallback)parent_load_capabilities_ready,
+ result);
+}
+
+/*****************************************************************************/
+/* Enable/Disable location gathering (Location interface) */
+
+typedef struct {
+ MMBaseModem *self;
+ GSimpleAsyncResult *result;
+ MMModemLocationSource source;
+} LocationGatheringContext;
+
+static void
+location_gathering_context_complete_and_free (LocationGatheringContext *ctx)
+{
+ g_simple_async_result_complete_in_idle (ctx->result);
+ g_object_unref (ctx->result);
+ g_object_unref (ctx->self);
+ g_slice_free (LocationGatheringContext, ctx);
+}
+
+/******************************/
+/* Disable location gathering */
+
+gboolean
+mm_common_cinterion_disable_location_gathering_finish (MMIfaceModemLocation *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
+}
+
+static void
+gps_disabled_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ LocationGatheringContext *ctx)
+{
+ MMPortSerialGps *gps_port;
+ GError *error = NULL;
+
+ if (!mm_base_modem_at_command_full_finish (self, res, &error))
+ g_simple_async_result_take_error (ctx->result, error);
+ else
+ g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
+
+ /* 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));
+
+ location_gathering_context_complete_and_free (ctx);
+}
+
+static void
+internal_disable_location_gathering (LocationGatheringContext *ctx)
+{
+ LocationContext *location_ctx;
+ gboolean stop_gps = FALSE;
+
+ location_ctx = get_location_context (MM_BASE_MODEM (ctx->self));
+
+ /* Only stop GPS engine if no GPS-related sources enabled */
+ if (ctx->source & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA |
+ MM_MODEM_LOCATION_SOURCE_GPS_RAW)) {
+ location_ctx->enabled_sources &= ~ctx->source;
+
+ if (!(location_ctx->enabled_sources & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA |
+ MM_MODEM_LOCATION_SOURCE_GPS_RAW)))
+ stop_gps = TRUE;
+ }
+
+ if (stop_gps) {
+ /* We disable continuous GPS fixes */
+ mm_base_modem_at_command_full (MM_BASE_MODEM (ctx->self),
+ mm_base_modem_peek_best_at_port (MM_BASE_MODEM (ctx->self), NULL),
+ "AT^SGPSS=0",
+ 3,
+ FALSE,
+ FALSE, /* raw */
+ NULL, /* cancellable */
+ (GAsyncReadyCallback)gps_disabled_ready,
+ ctx);
+ return;
+ }
+
+ /* For any other location (e.g. 3GPP), or if still some GPS needed, just return */
+ g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
+ location_gathering_context_complete_and_free (ctx);
+}
+
+static void
+parent_disable_location_gathering_ready (MMIfaceModemLocation *self,
+ GAsyncResult *res,
+ LocationGatheringContext *ctx)
+{
+ GError *error = NULL;
+
+ if (!iface_modem_location_parent->disable_location_gathering_finish (self, res, &error)) {
+ if (ctx->source & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA | MM_MODEM_LOCATION_SOURCE_GPS_RAW)) {
+ /* Ignore errors when disabling GPS, we can try with AT commands */
+ g_error_free (error);
+ } else {
+ /* Fatal */
+ g_simple_async_result_take_error (ctx->result, error);
+ location_gathering_context_complete_and_free (ctx);
+ return;
+ }
+ }
+
+ internal_disable_location_gathering (ctx);
+}
+
+void
+mm_common_cinterion_disable_location_gathering (MMIfaceModemLocation *self,
+ MMModemLocationSource source,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ LocationGatheringContext *ctx;
+
+ ctx = g_slice_new (LocationGatheringContext);
+ ctx->self = g_object_ref (self);
+ ctx->result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ mm_common_cinterion_disable_location_gathering);
+ ctx->source = source;
+
+ /* Chain up parent's gathering enable */
+ if (iface_modem_location_parent->disable_location_gathering) {
+ iface_modem_location_parent->disable_location_gathering (
+ self,
+ source,
+ (GAsyncReadyCallback)parent_disable_location_gathering_ready,
+ ctx);
+ return;
+ }
+
+ internal_disable_location_gathering (ctx);
+}
+
+/*****************************************************************************/
+/* Enable location gathering (Location interface) */
+
+gboolean
+mm_common_cinterion_enable_location_gathering_finish (MMIfaceModemLocation *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
+}
+
+static void
+gps_enabled_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ LocationGatheringContext *ctx)
+{
+ MMPortSerialGps *gps_port;
+ GError *error = NULL;
+
+ if (!mm_base_modem_at_command_full_finish (self, res, &error)) {
+ g_simple_async_result_take_error (ctx->result, error);
+ location_gathering_context_complete_and_free (ctx);
+ return;
+ }
+
+ 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_simple_async_result_take_error (ctx->result, error);
+ else
+ g_simple_async_result_set_error (ctx->result,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_FAILED,
+ "Couldn't open raw GPS serial port");
+ } else
+ g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
+
+ location_gathering_context_complete_and_free (ctx);
+}
+
+static void
+parent_enable_location_gathering_ready (MMIfaceModemLocation *self,
+ GAsyncResult *res,
+ LocationGatheringContext *ctx)
+{
+ gboolean start_gps = FALSE;
+ GError *error = NULL;
+ LocationContext *location_ctx;
+
+ if (!iface_modem_location_parent->enable_location_gathering_finish (self, res, &error)) {
+ if (ctx->source & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA | MM_MODEM_LOCATION_SOURCE_GPS_RAW)) {
+ /* Ignore errors when enabling GPS, we can try with AT commands */
+ g_error_free (error);
+ } else {
+ /* Fatal */
+ g_simple_async_result_take_error (ctx->result, error);
+ location_gathering_context_complete_and_free (ctx);
+ return;
+ }
+ }
+
+ /* Now our own enabling */
+
+ location_ctx = get_location_context (MM_BASE_MODEM (self));
+
+ /* NMEA and RAW are both enabled in the same way */
+ if (ctx->source & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA |
+ MM_MODEM_LOCATION_SOURCE_GPS_RAW)) {
+ /* Only start GPS engine if not done already */
+ if (!(location_ctx->enabled_sources & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA |
+ MM_MODEM_LOCATION_SOURCE_GPS_RAW)))
+ start_gps = TRUE;
+ location_ctx->enabled_sources |= ctx->source;
+ }
+
+ if (start_gps) {
+ /* We enable continuous GPS fixes */
+ mm_base_modem_at_command_full (MM_BASE_MODEM (self),
+ mm_base_modem_peek_best_at_port (MM_BASE_MODEM (self), NULL),
+ "AT^SGPSS=4",
+ 3,
+ FALSE,
+ FALSE, /* raw */
+ NULL, /* cancellable */
+ (GAsyncReadyCallback)gps_enabled_ready,
+ ctx);
+ return;
+ }
+
+ /* For any other location (e.g. 3GPP), or if GPS already running just return */
+ g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
+ location_gathering_context_complete_and_free (ctx);
+}
+
+void
+mm_common_cinterion_enable_location_gathering (MMIfaceModemLocation *self,
+ MMModemLocationSource source,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ LocationGatheringContext *ctx;
+
+ ctx = g_slice_new (LocationGatheringContext);
+ ctx->self = g_object_ref (self);
+ ctx->result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ mm_common_cinterion_enable_location_gathering);
+ ctx->source = source;
+
+ /* Chain up parent's gathering enable */
+ iface_modem_location_parent->enable_location_gathering (
+ self,
+ source,
+ (GAsyncReadyCallback)parent_enable_location_gathering_ready,
+ ctx);
+}
+
+/*****************************************************************************/
+/* Setup ports (Broadband modem class) */
+
+static void
+trace_received (MMPortSerialGps *port,
+ const gchar *trace,
+ MMIfaceModemLocation *self)
+{
+ /* Helper to debug GPS location related issues. Don't depend on a real GPS
+ * fix for debugging, just use some random values to update */
+#if 0
+ if (g_str_has_prefix (trace, "$GPGGA")) {
+ GString *str;
+ GDateTime *now;
+
+ now = g_date_time_new_now_utc ();
+ str = g_string_new ("");
+ g_string_append_printf (str,
+ "$GPGGA,%02u%02u%02u,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47",
+ g_date_time_get_hour (now),
+ g_date_time_get_minute (now),
+ g_date_time_get_second (now));
+ mm_iface_modem_location_gps_update (self, str->str);
+ g_string_free (str, TRUE);
+ g_date_time_unref (now);
+ return;
+ }
+#endif
+
+ mm_iface_modem_location_gps_update (self, trace);
+}
+
+void
+mm_common_cinterion_setup_gps_port (MMBroadbandModem *self)
+{
+ MMPortSerialGps *gps_data_port;
+
+ 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, 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_full (MM_BASE_MODEM (self),
+ mm_base_modem_peek_best_at_port (MM_BASE_MODEM (self), NULL),
+ "AT^SGPSS=0",
+ 3, FALSE, FALSE, NULL, NULL, NULL);
+
+ /* Add handler for the NMEA traces */
+ mm_port_serial_gps_add_trace_handler (gps_data_port,
+ (MMPortSerialGpsTraceFn)trace_received,
+ self,
+ NULL);
+ }
+}
+
+/*****************************************************************************/
+
+void
+mm_common_cinterion_peek_parent_location_interface (MMIfaceModemLocation *iface)
+{
+ iface_modem_location_parent = g_type_interface_peek_parent (iface);
+}
diff --git a/plugins/cinterion/mm-common-cinterion.h b/plugins/cinterion/mm-common-cinterion.h
new file mode 100644
index 00000000..02b01751
--- /dev/null
+++ b/plugins/cinterion/mm-common-cinterion.h
@@ -0,0 +1,51 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details:
+ *
+ * Copyright (C) 2014 Ammonit Measurement GmbH
+ * Author: Aleksander Morgado <aleksander@aleksander.es>
+ */
+
+#ifndef MM_COMMON_CINTERION_H
+#define MM_COMMON_CINTERION_H
+
+#include "glib.h"
+#include "mm-broadband-modem.h"
+#include "mm-iface-modem-location.h"
+
+void mm_common_cinterion_location_load_capabilities (MMIfaceModemLocation *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+MMModemLocationSource mm_common_cinterion_location_load_capabilities_finish (MMIfaceModemLocation *self,
+ GAsyncResult *res,
+ GError **error);
+
+void mm_common_cinterion_enable_location_gathering (MMIfaceModemLocation *self,
+ MMModemLocationSource source,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean mm_common_cinterion_enable_location_gathering_finish (MMIfaceModemLocation *self,
+ GAsyncResult *res,
+ GError **error);
+
+void mm_common_cinterion_disable_location_gathering (MMIfaceModemLocation *self,
+ MMModemLocationSource source,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean mm_common_cinterion_disable_location_gathering_finish (MMIfaceModemLocation *self,
+ GAsyncResult *res,
+ GError **error);
+
+void mm_common_cinterion_setup_gps_port (MMBroadbandModem *self);
+
+void mm_common_cinterion_peek_parent_location_interface (MMIfaceModemLocation *iface);
+
+#endif /* MM_COMMON_CINTERION_H */
diff --git a/plugins/cinterion/mm-plugin-cinterion.c b/plugins/cinterion/mm-plugin-cinterion.c
index 18c53199..8af0a2ac 100644
--- a/plugins/cinterion/mm-plugin-cinterion.c
+++ b/plugins/cinterion/mm-plugin-cinterion.c
@@ -32,7 +32,7 @@
#include "mm-log.h"
#if defined WITH_QMI
-#include "mm-broadband-modem-qmi.h"
+#include "mm-broadband-modem-qmi-cinterion.h"
#endif
G_DEFINE_TYPE (MMPluginCinterion, mm_plugin_cinterion, MM_TYPE_PLUGIN)
@@ -140,11 +140,11 @@ create_modem (MMPlugin *self,
#if defined WITH_QMI
if (mm_port_probe_list_has_qmi_port (probes)) {
mm_dbg ("QMI-powered Cinterion modem found...");
- return MM_BASE_MODEM (mm_broadband_modem_qmi_new (sysfs_path,
- drivers,
- mm_plugin_get_name (self),
- vendor,
- product));
+ return MM_BASE_MODEM (mm_broadband_modem_qmi_cinterion_new (sysfs_path,
+ drivers,
+ mm_plugin_get_name (self),
+ vendor,
+ product));
}
#endif