diff options
Diffstat (limited to 'plugins/cinterion')
-rw-r--r-- | plugins/cinterion/mm-broadband-modem-cinterion.c | 344 | ||||
-rw-r--r-- | plugins/cinterion/mm-broadband-modem-qmi-cinterion.c | 92 | ||||
-rw-r--r-- | plugins/cinterion/mm-broadband-modem-qmi-cinterion.h | 48 | ||||
-rw-r--r-- | plugins/cinterion/mm-common-cinterion.c | 445 | ||||
-rw-r--r-- | plugins/cinterion/mm-common-cinterion.h | 51 | ||||
-rw-r--r-- | plugins/cinterion/mm-plugin-cinterion.c | 12 |
6 files changed, 657 insertions, 335 deletions
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 |