diff options
Diffstat (limited to 'plugins/cinterion')
-rw-r--r-- | plugins/cinterion/77-mm-cinterion-port-types.rules | 71 | ||||
-rw-r--r-- | plugins/cinterion/mm-broadband-bearer-cinterion.c | 796 | ||||
-rw-r--r-- | plugins/cinterion/mm-broadband-bearer-cinterion.h | 54 | ||||
-rw-r--r-- | plugins/cinterion/mm-broadband-modem-cinterion.c | 3356 | ||||
-rw-r--r-- | plugins/cinterion/mm-broadband-modem-cinterion.h | 54 | ||||
-rw-r--r-- | plugins/cinterion/mm-broadband-modem-mbim-cinterion.c | 167 | ||||
-rw-r--r-- | plugins/cinterion/mm-broadband-modem-mbim-cinterion.h | 47 | ||||
-rw-r--r-- | plugins/cinterion/mm-broadband-modem-qmi-cinterion.c | 167 | ||||
-rw-r--r-- | plugins/cinterion/mm-broadband-modem-qmi-cinterion.h | 48 | ||||
-rw-r--r-- | plugins/cinterion/mm-modem-helpers-cinterion.c | 1804 | ||||
-rw-r--r-- | plugins/cinterion/mm-modem-helpers-cinterion.h | 211 | ||||
-rw-r--r-- | plugins/cinterion/mm-plugin-cinterion.c | 218 | ||||
-rw-r--r-- | plugins/cinterion/mm-plugin-cinterion.h | 47 | ||||
-rw-r--r-- | plugins/cinterion/mm-shared-cinterion.c | 1601 | ||||
-rw-r--r-- | plugins/cinterion/mm-shared-cinterion.h | 153 | ||||
-rw-r--r-- | plugins/cinterion/tests/test-modem-helpers-cinterion.c | 1967 |
16 files changed, 0 insertions, 10761 deletions
diff --git a/plugins/cinterion/77-mm-cinterion-port-types.rules b/plugins/cinterion/77-mm-cinterion-port-types.rules deleted file mode 100644 index c1a9bc4a..00000000 --- a/plugins/cinterion/77-mm-cinterion-port-types.rules +++ /dev/null @@ -1,71 +0,0 @@ -# do not edit this file, it will be overwritten on update - -ACTION!="add|change|move|bind", GOTO="mm_cinterion_port_types_end" -SUBSYSTEMS=="usb", ATTRS{idVendor}=="1e2d", GOTO="mm_cinterion_port_types" -GOTO="mm_cinterion_port_types_end" - -LABEL="mm_cinterion_port_types" -SUBSYSTEMS=="usb", ATTRS{bInterfaceNumber}=="?*", ENV{.MM_USBIFNUM}="$attr{bInterfaceNumber}" - -# PHS8 -ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="0053", ENV{.MM_USBIFNUM}=="01", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1" - -# PLS8 port types -# ttyACM0 (if #0): AT port -# ttyACM1 (if #2): AT port -# ttyACM2 (if #4): GPS data port -# ttyACM3 (if #6): unknown -# ttyACM4 (if #8): unknown -ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="0061", ENV{.MM_USBIFNUM}=="00", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1" -ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="0061", ENV{.MM_USBIFNUM}=="02", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1" -ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="0061", ENV{.MM_USBIFNUM}=="04", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1" -ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="0061", ENV{.MM_USBIFNUM}=="06", ENV{ID_MM_PORT_IGNORE}="1" -ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="0061", ENV{.MM_USBIFNUM}=="08", ENV{ID_MM_PORT_IGNORE}="1" - -# PLS62 family non-mbim enumeration uses alternate settings for 2G band management -ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="005b", ENV{ID_MM_CINTERION_MODEM_FAMILY}="imt" -# PLS62 family non-mbim enumeration -# ttyACM0 (if #0): AT port -# ttyACM1 (if #2): AT port -# ttyACM2 (if #4): can be AT or GNSS in some models -# ttyACM3 (if #6): AT port (but just ignore) -# ttyACM4 (if #8): DIAG/QCDM -ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="005b", ENV{.MM_USBIFNUM}=="00", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1" -ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="005b", ENV{.MM_USBIFNUM}=="02", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1" -ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="005b", ENV{.MM_USBIFNUM}=="04", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1" -ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="005b", ENV{.MM_USBIFNUM}=="06", ENV{ID_MM_PORT_IGNORE}="1" -ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="005b", ENV{.MM_USBIFNUM}=="08", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_QCDM}="1" - -# PLS62 family mbim enumeration -# ttyACM0 (if #0): AT port -# ttyACM1 (if #2): AT port -# ttyACM2 (if #4): can be AT or GNSS in some models -# ttyACM3 (if #6): AT port (but just ignore) -# ttyACM4 (if #8): DIAG/QCDM -ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="005d", ENV{.MM_USBIFNUM}=="00", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1" -ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="005d", ENV{.MM_USBIFNUM}=="02", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1" -ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="005d", ENV{.MM_USBIFNUM}=="04", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1" -ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="005d", ENV{.MM_USBIFNUM}=="06", ENV{ID_MM_PORT_IGNORE}="1" -ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="005d", ENV{.MM_USBIFNUM}=="08", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_QCDM}="1" - -# PLS63 -# ttyACM0 (if #0): AT port -# ttyACM1 (if #2): AT port -# ttyACM2 (if #4): GPS data port -# ttyACM3 (if #6): DIAG/QCDM -ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="0069", ENV{.MM_USBIFNUM}=="00", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1" -ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="0069", ENV{.MM_USBIFNUM}=="02", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1" -ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="0069", ENV{.MM_USBIFNUM}=="04", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1" -ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="0069", ENV{.MM_USBIFNUM}=="06", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_QCDM}="1" - -# PLS83 -# ttyACM0 (if #0): AT port -# ttyACM1 (if #2): AT port -# ttyACM2 (if #4): GPS data port -# ttyACM3 (if #6): DIAG/QCDM -ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="006F", ENV{.MM_USBIFNUM}=="00", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_PRIMARY}="1" -ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="006F", ENV{.MM_USBIFNUM}=="02", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_AT_SECONDARY}="1" -ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="006F", ENV{.MM_USBIFNUM}=="04", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_GPS}="1" -ATTRS{idVendor}=="1e2d", ATTRS{idProduct}=="006F", ENV{.MM_USBIFNUM}=="06", SUBSYSTEM=="tty", ENV{ID_MM_PORT_TYPE_QCDM}="1" - -LABEL="mm_cinterion_port_types_end" diff --git a/plugins/cinterion/mm-broadband-bearer-cinterion.c b/plugins/cinterion/mm-broadband-bearer-cinterion.c deleted file mode 100644 index 85fbf69c..00000000 --- a/plugins/cinterion/mm-broadband-bearer-cinterion.c +++ /dev/null @@ -1,796 +0,0 @@ -/* -*- 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) 2016 Trimble Navigation Limited - * Author: Matthew Stanger <matthew_stanger@trimble.com> - */ - -#include <config.h> -#include <stdio.h> -#include <stdlib.h> -#include <unistd.h> -#include <string.h> -#include <ctype.h> -#include <arpa/inet.h> -#include <ModemManager.h> -#include "mm-base-modem-at.h" -#include "mm-broadband-bearer-cinterion.h" -#include "mm-log-object.h" -#include "mm-modem-helpers.h" -#include "mm-modem-helpers-cinterion.h" -#include "mm-daemon-enums-types.h" - -G_DEFINE_TYPE (MMBroadbandBearerCinterion, mm_broadband_bearer_cinterion, MM_TYPE_BROADBAND_BEARER) - -/*****************************************************************************/ -/* WWAN interface mapping */ - -typedef struct { - guint swwan_index; - guint usb_iface_num; -} UsbInterfaceConfig; - -/* Map SWWAN index, USB interface number and preferred PDP context. - * - * The expected USB interface mapping is: - * INTERFACE=usb0 -> ID_USB_INTERFACE_NUM=0a - * INTERFACE=usb1 -> ID_USB_INTERFACE_NUM=0c - * INTERFACE=usb0 -> ID_USB_INTERFACE_NUM=08 (PLSx3w) - */ -static const UsbInterfaceConfig usb_interface_configs[] = { - { - .swwan_index = 1, - .usb_iface_num = 0x0a, - }, - { - .swwan_index = 2, - .usb_iface_num = 0x0c, - }, - { - .swwan_index = 1, - .usb_iface_num = 0x08, - }, -}; - -static gint -get_usb_interface_config_index (MMPort *data, - GError **error) -{ - guint usb_iface_num; - guint i; - - usb_iface_num = (guint) mm_kernel_device_get_interface_number (mm_port_peek_kernel_device (data)); - - for (i = 0; i < G_N_ELEMENTS (usb_interface_configs); i++) { - if (usb_interface_configs[i].usb_iface_num == usb_iface_num) - return (gint) i; - } - - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Unsupported WWAN interface: unexpected interface number: 0x%02x", usb_iface_num); - return -1; -} - -/*****************************************************************************/ -/* Connection status loading - * NOTE: only CONNECTED or DISCONNECTED should be reported here. - */ - -static MMBearerConnectionStatus -load_connection_status_finish (MMBaseBearer *bearer, - GAsyncResult *res, - GError **error) -{ - GError *inner_error = NULL; - gssize aux; - - aux = g_task_propagate_int (G_TASK (res), &inner_error); - if (inner_error) { - g_propagate_error (error, inner_error); - return MM_BEARER_CONNECTION_STATUS_UNKNOWN; - } - return (MMBearerConnectionStatus) aux; -} - -typedef struct { - guint cid; - guint retries; - gboolean delay; - gboolean retry; -} LoadConnectionContext; - -static void -load_connection_context_free (LoadConnectionContext *ctx) -{ - g_slice_free (LoadConnectionContext, ctx); -} - -static gboolean swwan_check_status (GTask *task); - -static void -swwan_check_status_ready (MMBaseModem *modem, - GAsyncResult *res, - GTask *task) -{ - MMBroadbandBearerCinterion *self; - const gchar *response; - GError *error = NULL; - MMBearerConnectionStatus status; - LoadConnectionContext *ctx; - - self = g_task_get_source_object (task); - ctx = g_task_get_task_data (task); - - response = mm_base_modem_at_command_finish (modem, res, &error); - if (!response) { - g_task_return_error (task, error); - goto out; - } - - status = mm_cinterion_parse_swwan_response (response, ctx->cid, self, &error); - if (status == MM_BEARER_CONNECTION_STATUS_UNKNOWN) { - g_task_return_error (task, error); - goto out; - } else if (ctx->retry && status == MM_BEARER_CONNECTION_STATUS_DISCONNECTED) { - mm_obj_dbg (self, "check status retry"); - if (ctx->retries == 0) { - g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "CID %u status check retry exceeded", ctx->cid); - goto out; - } else { - if (ctx->delay) { - g_timeout_add_seconds (1, (GSourceFunc)swwan_check_status, task); - } else { - g_idle_add ((GSourceFunc)swwan_check_status, task); - } - ctx->retries--; - return; - } - } - - g_assert (status == MM_BEARER_CONNECTION_STATUS_DISCONNECTED || - status == MM_BEARER_CONNECTION_STATUS_CONNECTED); - g_task_return_int (task, (gssize) status); - -out: - g_object_unref (task); -} - -static gboolean -swwan_check_status (GTask *task) -{ - MMBroadbandBearerCinterion *bearer; - g_autoptr(MMBaseModem) modem = NULL; - - bearer = g_task_get_source_object (task); - g_object_get (bearer, - MM_BASE_BEARER_MODEM, &modem, - NULL); - mm_base_modem_at_command (modem, - "^SWWAN?", - 5, - FALSE, - (GAsyncReadyCallback) swwan_check_status_ready, - task); - - return G_SOURCE_REMOVE; -} - -static void -load_connection_status_by_cid (MMBroadbandBearerCinterion *bearer, - gint cid, - gboolean delay, - gboolean retry, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GTask *task; - LoadConnectionContext *ctx; - - task = g_task_new (bearer, NULL, callback, user_data); - if (cid == MM_3GPP_PROFILE_ID_UNKNOWN) { - g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Unknown profile id to check connection status"); - g_object_unref (task); - return; - } - - ctx = g_slice_new0 (LoadConnectionContext); - g_task_set_task_data (task, ctx, (GDestroyNotify) load_connection_context_free); - - /* Setup context */ - ctx->cid = cid; - ctx->retries = 5; - ctx->delay = delay; - ctx->retry = retry; - - /* Some modems require a delay before querying the SWWAN status - * This is only needed for step DIAL_3GPP_CONTEXT_STEP_VALIDATE_CONNECTION - * and DISCONNECT_3GPP_CONTEXT_STEP_CONNECTION_STATUS. */ - if (delay) { - g_timeout_add_seconds (1, (GSourceFunc)swwan_check_status, task); - } else { - g_idle_add ((GSourceFunc)swwan_check_status, task); - } -} - -static void -load_connection_status (MMBaseBearer *bearer, - GAsyncReadyCallback callback, - gpointer user_data) -{ - load_connection_status_by_cid (MM_BROADBAND_BEARER_CINTERION (bearer), - mm_base_bearer_get_profile_id (bearer), - FALSE, - FALSE, - callback, - user_data); -} - -/******************************************************************************/ -/* Dial 3GPP */ - -typedef enum { - DIAL_3GPP_CONTEXT_STEP_FIRST = 0, - DIAL_3GPP_CONTEXT_STEP_AUTH, - DIAL_3GPP_CONTEXT_STEP_START_SWWAN, - DIAL_3GPP_CONTEXT_STEP_VALIDATE_CONNECTION, - DIAL_3GPP_CONTEXT_STEP_LAST, -} Dial3gppContextStep; - -typedef struct { - MMBroadbandBearerCinterion *self; - MMBaseModem *modem; - MMPortSerialAt *primary; - guint cid; - MMPort *data; - gint usb_interface_config_index; - Dial3gppContextStep step; -} Dial3gppContext; - -static void -dial_3gpp_context_free (Dial3gppContext *ctx) -{ - g_object_unref (ctx->modem); - g_object_unref (ctx->self); - g_object_unref (ctx->primary); - g_clear_object (&ctx->data); - g_slice_free (Dial3gppContext, ctx); -} - -static MMPort * -dial_3gpp_finish (MMBroadbandBearer *self, - GAsyncResult *res, - GError **error) -{ - return MM_PORT (g_task_propagate_pointer (G_TASK (res), error)); -} - -static void dial_3gpp_context_step (GTask *task); - -static void -dial_connection_status_ready (MMBroadbandBearerCinterion *self, - GAsyncResult *res, - GTask *task) -{ - MMBearerConnectionStatus status; - Dial3gppContext *ctx; - GError *error = NULL; - - ctx = (Dial3gppContext *) g_task_get_task_data (task); - - status = load_connection_status_finish (MM_BASE_BEARER (self), res, &error); - if (status == MM_BEARER_CONNECTION_STATUS_UNKNOWN) { - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - if (status == MM_BEARER_CONNECTION_STATUS_DISCONNECTED) { - g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "CID %u is reported disconnected", ctx->cid); - g_object_unref (task); - return; - } - - g_assert (status == MM_BEARER_CONNECTION_STATUS_CONNECTED); - - /* Go to next step */ - ctx->step++; - dial_3gpp_context_step (task); -} - -static void -common_dial_operation_ready (MMBaseModem *modem, - GAsyncResult *res, - GTask *task) -{ - Dial3gppContext *ctx; - GError *error = NULL; - - ctx = (Dial3gppContext *) g_task_get_task_data (task); - - if (!mm_base_modem_at_command_full_finish (modem, res, &error)) { - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - /* Go to next step */ - ctx->step++; - dial_3gpp_context_step (task); -} - -static void -swwan_dial_operation_ready (MMBaseModem *modem, - GAsyncResult *res, - MMBroadbandBearerCinterion *self) /* full ref! */ -{ - GError *error = NULL; - - if (!mm_base_modem_at_command_full_finish (modem, res, &error)) { - mm_obj_warn (self, "data connection attempt failed: %s", error->message); - mm_base_bearer_report_connection_status (MM_BASE_BEARER (self), - MM_BEARER_CONNECTION_STATUS_DISCONNECTED); - g_error_free (error); - } - - g_object_unref (self); -} - -static void -handle_cancel_dial (GTask *task) -{ - Dial3gppContext *ctx; - gchar *command; - - ctx = (Dial3gppContext *) g_task_get_task_data (task); - - /* Disconnect, may not succeed. Will not check response on cancel */ - command = g_strdup_printf ("^SWWAN=0,%u,%u", - ctx->cid, usb_interface_configs[ctx->usb_interface_config_index].swwan_index); - mm_base_modem_at_command_full (ctx->modem, - ctx->primary, - command, - 3, - FALSE, - FALSE, - NULL, - NULL, - NULL); - g_free (command); -} - -static void -dial_3gpp_context_step (GTask *task) -{ - MMBroadbandBearerCinterion *self; - Dial3gppContext *ctx; - MMCinterionModemFamily modem_family; - gboolean default_swwan_behavior; - - self = g_task_get_source_object (task); - ctx = g_task_get_task_data (task); - - /* Check for cancellation */ - if (g_task_return_error_if_cancelled (task)) { - handle_cancel_dial (task); - g_object_unref (task); - return; - } - - modem_family = mm_broadband_modem_cinterion_get_family (MM_BROADBAND_MODEM_CINTERION (ctx->modem)); - default_swwan_behavior = modem_family == MM_CINTERION_MODEM_FAMILY_DEFAULT; - - switch (ctx->step) { - case DIAL_3GPP_CONTEXT_STEP_FIRST: - ctx->step++; - /* fall through */ - - case DIAL_3GPP_CONTEXT_STEP_AUTH: { - g_autofree gchar *command = NULL; - - command = mm_cinterion_build_auth_string (self, - modem_family, - mm_base_bearer_peek_config (MM_BASE_BEARER (ctx->self)), - ctx->cid); - - if (command) { - mm_obj_dbg (self, "dial step %u/%u: authenticating...", ctx->step, DIAL_3GPP_CONTEXT_STEP_LAST); - /* Send SGAUTH write, if User & Pass are provided. - * advance to next state by callback */ - mm_base_modem_at_command_full (ctx->modem, - ctx->primary, - command, - 10, - FALSE, - FALSE, - NULL, - (GAsyncReadyCallback) common_dial_operation_ready, - task); - return; - } - - mm_obj_dbg (self, "dial step %u/%u: authentication not required", ctx->step, DIAL_3GPP_CONTEXT_STEP_LAST); - ctx->step++; - } /* fall through */ - - case DIAL_3GPP_CONTEXT_STEP_START_SWWAN: { - g_autofree gchar *command = NULL; - - mm_obj_dbg (self, "dial step %u/%u: starting SWWAN interface %u connection...", - ctx->step, DIAL_3GPP_CONTEXT_STEP_LAST, usb_interface_configs[ctx->usb_interface_config_index].swwan_index); - command = g_strdup_printf ("^SWWAN=1,%u,%u", - ctx->cid, - usb_interface_configs[ctx->usb_interface_config_index].swwan_index); - - if (default_swwan_behavior) { - mm_base_modem_at_command_full (ctx->modem, - ctx->primary, - command, - MM_BASE_BEARER_DEFAULT_CONNECTION_TIMEOUT, - FALSE, - FALSE, - NULL, - (GAsyncReadyCallback) common_dial_operation_ready, - task); - return; - } - - /* We "jump" to the last step here here since the modem expects the - * DHCP discover packet while ^SWWAN runs. If the command fails, - * we'll mark the bearer disconnected later in the callback. - */ - mm_base_modem_at_command_full (ctx->modem, - ctx->primary, - command, - MM_BASE_BEARER_DEFAULT_CONNECTION_TIMEOUT, - FALSE, - FALSE, - NULL, - (GAsyncReadyCallback) swwan_dial_operation_ready, - g_object_ref (self)); - ctx->step = DIAL_3GPP_CONTEXT_STEP_LAST; - dial_3gpp_context_step (task); - return; - } - - case DIAL_3GPP_CONTEXT_STEP_VALIDATE_CONNECTION: - g_assert (default_swwan_behavior); - mm_obj_dbg (self, "dial step %u/%u: checking SWWAN interface %u status...", - ctx->step, DIAL_3GPP_CONTEXT_STEP_LAST, usb_interface_configs[ctx->usb_interface_config_index].swwan_index); - load_connection_status_by_cid (ctx->self, - (gint) ctx->cid, - TRUE, - TRUE, - (GAsyncReadyCallback) dial_connection_status_ready, - task); - return; - - case DIAL_3GPP_CONTEXT_STEP_LAST: - mm_obj_dbg (self, "dial step %u/%u: finished", ctx->step, DIAL_3GPP_CONTEXT_STEP_LAST); - g_task_return_pointer (task, g_object_ref (ctx->data), g_object_unref); - g_object_unref (task); - return; - - default: - g_assert_not_reached (); - } -} - -static void -dial_3gpp (MMBroadbandBearer *self, - MMBaseModem *modem, - MMPortSerialAt *primary, - guint cid, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GTask *task; - Dial3gppContext *ctx; - GError *error = NULL; - - g_assert (primary != NULL); - - /* Setup task and create connection context */ - task = g_task_new (self, cancellable, callback, user_data); - ctx = g_slice_new0 (Dial3gppContext); - g_task_set_task_data (task, ctx, (GDestroyNotify) dial_3gpp_context_free); - - /* Setup context */ - ctx->self = MM_BROADBAND_BEARER_CINTERION (g_object_ref (self)); - ctx->modem = g_object_ref (modem); - ctx->primary = g_object_ref (primary); - ctx->cid = cid; - ctx->step = DIAL_3GPP_CONTEXT_STEP_FIRST; - - /* Get a net port to setup the connection on */ - ctx->data = mm_base_modem_peek_best_data_port (MM_BASE_MODEM (modem), MM_PORT_TYPE_NET); - if (!ctx->data) { - g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_NOT_FOUND, - "No valid data port found to launch connection"); - g_object_unref (task); - return; - } - g_object_ref (ctx->data); - - /* Validate configuration */ - ctx->usb_interface_config_index = get_usb_interface_config_index (ctx->data, &error); - if (ctx->usb_interface_config_index < 0) { - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - /* Run! */ - dial_3gpp_context_step (task); -} - -/*****************************************************************************/ -/* Disconnect 3GPP */ - -typedef enum { - DISCONNECT_3GPP_CONTEXT_STEP_FIRST, - DISCONNECT_3GPP_CONTEXT_STEP_STOP_SWWAN, - DISCONNECT_3GPP_CONTEXT_STEP_CONNECTION_STATUS, - DISCONNECT_3GPP_CONTEXT_STEP_LAST, -} Disconnect3gppContextStep; - -typedef struct { - MMBroadbandBearerCinterion *self; - MMBaseModem *modem; - MMPortSerialAt *primary; - MMPort *data; - guint cid; - gint usb_interface_config_index; - Disconnect3gppContextStep step; -} Disconnect3gppContext; - -static void -disconnect_3gpp_context_free (Disconnect3gppContext *ctx) -{ - g_object_unref (ctx->data); - g_object_unref (ctx->primary); - g_object_unref (ctx->self); - g_object_unref (ctx->modem); - g_slice_free (Disconnect3gppContext, ctx); -} - -static gboolean -disconnect_3gpp_finish (MMBroadbandBearer *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void disconnect_3gpp_context_step (GTask *task); - -static void -disconnect_connection_status_ready (MMBroadbandBearerCinterion *self, - GAsyncResult *res, - GTask *task) -{ - MMBearerConnectionStatus status; - Disconnect3gppContext *ctx; - GError *error = NULL; - - ctx = (Disconnect3gppContext *) g_task_get_task_data (task); - - status = load_connection_status_finish (MM_BASE_BEARER (self), res, &error); - switch (status) { - case MM_BEARER_CONNECTION_STATUS_UNKNOWN: - /* Assume disconnected */ - mm_obj_dbg (self, "couldn't get CID %u status, assume disconnected: %s", ctx->cid, error->message); - g_clear_error (&error); - break; - case MM_BEARER_CONNECTION_STATUS_DISCONNECTED: - break; - case MM_BEARER_CONNECTION_STATUS_CONNECTED: - g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "CID %u is reported connected", ctx->cid); - g_object_unref (task); - return; - case MM_BEARER_CONNECTION_STATUS_DISCONNECTING: - case MM_BEARER_CONNECTION_STATUS_CONNECTION_FAILED: - default: - g_assert_not_reached (); - } - - /* Go on to next step */ - ctx->step++; - disconnect_3gpp_context_step (task); -} - -static void -swwan_disconnect_ready (MMBaseModem *modem, - GAsyncResult *res, - GTask *task) -{ - Disconnect3gppContext *ctx; - - ctx = (Disconnect3gppContext *) g_task_get_task_data (task); - - /* We don't bother to check error or response here since, ctx flow's - * next step checks it */ - mm_base_modem_at_command_full_finish (modem, res, NULL); - - /* Go on to next step */ - ctx->step++; - disconnect_3gpp_context_step (task); -} - -static void -disconnect_3gpp_context_step (GTask *task) -{ - MMBroadbandBearerCinterion *self; - Disconnect3gppContext *ctx; - - self = g_task_get_source_object (task); - ctx = g_task_get_task_data (task); - - switch (ctx->step) { - case DISCONNECT_3GPP_CONTEXT_STEP_FIRST: - ctx->step++; - /* fall through */ - - case DISCONNECT_3GPP_CONTEXT_STEP_STOP_SWWAN: { - gchar *command; - - command = g_strdup_printf ("^SWWAN=0,%u,%u", - ctx->cid, usb_interface_configs[ctx->usb_interface_config_index].swwan_index); - mm_obj_dbg (self, "disconnect step %u/%u: disconnecting PDP CID %u...", - ctx->step, DISCONNECT_3GPP_CONTEXT_STEP_LAST, ctx->cid); - mm_base_modem_at_command_full (ctx->modem, - ctx->primary, - command, - MM_BASE_BEARER_DEFAULT_DISCONNECTION_TIMEOUT, - FALSE, - FALSE, - NULL, - (GAsyncReadyCallback) swwan_disconnect_ready, - task); - g_free (command); - return; - } - - case DISCONNECT_3GPP_CONTEXT_STEP_CONNECTION_STATUS: - mm_obj_dbg (self, "disconnect step %u/%u: checking SWWAN interface %u status...", - ctx->step, DISCONNECT_3GPP_CONTEXT_STEP_LAST, - usb_interface_configs[ctx->usb_interface_config_index].swwan_index); - load_connection_status_by_cid (MM_BROADBAND_BEARER_CINTERION (ctx->self), - (gint) ctx->cid, - TRUE, - FALSE, - (GAsyncReadyCallback) disconnect_connection_status_ready, - task); - return; - - case DISCONNECT_3GPP_CONTEXT_STEP_LAST: - mm_obj_dbg (self, "disconnect step %u/%u: finished", - ctx->step, DISCONNECT_3GPP_CONTEXT_STEP_LAST); - g_task_return_boolean (task, TRUE); - g_object_unref (task); - return; - - default: - g_assert_not_reached (); - } -} - -static void -disconnect_3gpp (MMBroadbandBearer *self, - MMBroadbandModem *modem, - MMPortSerialAt *primary, - MMPortSerialAt *secondary, - MMPort *data, - guint cid, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GTask *task; - Disconnect3gppContext *ctx; - GError *error = NULL; - - g_assert (primary != NULL); - g_assert (data != NULL); - - /* Setup task and create connection context */ - task = g_task_new (self, NULL, callback, user_data); - ctx = g_slice_new0 (Disconnect3gppContext); - g_task_set_task_data (task, ctx, (GDestroyNotify) disconnect_3gpp_context_free); - - /* Setup context */ - ctx->self = MM_BROADBAND_BEARER_CINTERION (g_object_ref (self)); - ctx->modem = MM_BASE_MODEM (g_object_ref (modem)); - ctx->primary = g_object_ref (primary); - ctx->data = g_object_ref (data); - ctx->cid = cid; - ctx->step = DISCONNECT_3GPP_CONTEXT_STEP_FIRST; - - /* Validate configuration */ - ctx->usb_interface_config_index = get_usb_interface_config_index (data, &error); - if (ctx->usb_interface_config_index < 0) { - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - /* Start */ - disconnect_3gpp_context_step (task); -} - -/*****************************************************************************/ -/* Setup and Init Bearers */ - -MMBaseBearer * -mm_broadband_bearer_cinterion_new_finish (GAsyncResult *res, - GError **error) -{ - GObject *bearer; - GObject *source; - - source = g_async_result_get_source_object (res); - bearer = g_async_initable_new_finish (G_ASYNC_INITABLE (source), res, error); - g_object_unref (source); - - if (!bearer) - return NULL; - - /* Only export valid bearers */ - mm_base_bearer_export (MM_BASE_BEARER (bearer)); - - return MM_BASE_BEARER (bearer); -} - -void -mm_broadband_bearer_cinterion_new (MMBroadbandModemCinterion *modem, - MMBearerProperties *config, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - g_async_initable_new_async ( - MM_TYPE_BROADBAND_BEARER_CINTERION, - G_PRIORITY_DEFAULT, - cancellable, - callback, - user_data, - MM_BASE_BEARER_MODEM, modem, - MM_BASE_BEARER_CONFIG, config, - NULL); -} - -static void -mm_broadband_bearer_cinterion_init (MMBroadbandBearerCinterion *self) -{ -} - -static void -mm_broadband_bearer_cinterion_class_init (MMBroadbandBearerCinterionClass *klass) -{ - MMBaseBearerClass *base_bearer_class = MM_BASE_BEARER_CLASS (klass); - MMBroadbandBearerClass *broadband_bearer_class = MM_BROADBAND_BEARER_CLASS (klass); - - base_bearer_class->load_connection_status = load_connection_status; - base_bearer_class->load_connection_status_finish = load_connection_status_finish; -#if defined WITH_SUSPEND_RESUME - base_bearer_class->reload_connection_status = load_connection_status; - base_bearer_class->reload_connection_status_finish = load_connection_status_finish; -#endif - - broadband_bearer_class->dial_3gpp = dial_3gpp; - broadband_bearer_class->dial_3gpp_finish = dial_3gpp_finish; - broadband_bearer_class->disconnect_3gpp = disconnect_3gpp; - broadband_bearer_class->disconnect_3gpp_finish = disconnect_3gpp_finish; -} diff --git a/plugins/cinterion/mm-broadband-bearer-cinterion.h b/plugins/cinterion/mm-broadband-bearer-cinterion.h deleted file mode 100644 index d514759d..00000000 --- a/plugins/cinterion/mm-broadband-bearer-cinterion.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -*- 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) 2016 Trimble Navigation Limited - * Author: Matthew Stanger <Matthew_Stanger@trimble.com> - */ - -#ifndef MM_BROADBAND_BEARER_CINTERION_H -#define MM_BROADBAND_BEARER_CINTERION_H - -#include <glib.h> -#include <glib-object.h> - -#include "mm-broadband-bearer.h" -#include "mm-broadband-modem-cinterion.h" - -#define MM_TYPE_BROADBAND_BEARER_CINTERION (mm_broadband_bearer_cinterion_get_type ()) -#define MM_BROADBAND_BEARER_CINTERION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_BEARER_CINTERION, MMBroadbandBearerCinterion)) -#define MM_BROADBAND_BEARER_CINTERION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_BEARER_CINTERION, MMBroadbandBearerCinterionClass)) -#define MM_IS_BROADBAND_BEARER_CINTERION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_BEARER_CINTERION)) -#define MM_IS_BROADBAND_BEARER_CINTERION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_BEARER_CINTERION)) -#define MM_BROADBAND_BEARER_CINTERION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_BEARER_CINTERION, MMBroadbandBearerCinterionClass)) - -typedef struct _MMBroadbandBearerCinterion MMBroadbandBearerCinterion; -typedef struct _MMBroadbandBearerCinterionClass MMBroadbandBearerCinterionClass; - -struct _MMBroadbandBearerCinterion { - MMBroadbandBearer parent; -}; - -struct _MMBroadbandBearerCinterionClass { - MMBroadbandBearerClass parent; -}; - -GType mm_broadband_bearer_cinterion_get_type (void); - -void mm_broadband_bearer_cinterion_new (MMBroadbandModemCinterion *modem, - MMBearerProperties *config, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -MMBaseBearer *mm_broadband_bearer_cinterion_new_finish (GAsyncResult *res, - GError **error); - -#endif /* MM_BROADBAND_BEARER_CINTERION_H */ diff --git a/plugins/cinterion/mm-broadband-modem-cinterion.c b/plugins/cinterion/mm-broadband-modem-cinterion.c deleted file mode 100644 index b063d454..00000000 --- a/plugins/cinterion/mm-broadband-modem-cinterion.c +++ /dev/null @@ -1,3356 +0,0 @@ -/* -*- 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) 2011 Ammonit Measurement GmbH - * Copyright (C) 2011 Google Inc. - * Copyright (C) 2016 Trimble Navigation Limited - * Author: Aleksander Morgado <aleksander@lanedo.com> - * Contributor: Matthew Stanger <matthew_stanger@trimble.com> - */ - -#include <config.h> - -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <ctype.h> - -#include "ModemManager.h" -#include "mm-modem-helpers.h" -#include "mm-serial-parsers.h" -#include "mm-log-object.h" -#include "mm-errors-types.h" -#include "mm-iface-modem.h" -#include "mm-iface-modem-3gpp.h" -#include "mm-iface-modem-messaging.h" -#include "mm-iface-modem-location.h" -#include "mm-iface-modem-voice.h" -#include "mm-base-modem-at.h" -#include "mm-broadband-modem-cinterion.h" -#include "mm-modem-helpers-cinterion.h" -#include "mm-shared-cinterion.h" -#include "mm-broadband-bearer-cinterion.h" -#include "mm-iface-modem-signal.h" - -static void iface_modem_init (MMIfaceModem *iface); -static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface); -static void iface_modem_messaging_init (MMIfaceModemMessaging *iface); -static void iface_modem_location_init (MMIfaceModemLocation *iface); -static void iface_modem_voice_init (MMIfaceModemVoice *iface); -static void iface_modem_time_init (MMIfaceModemTime *iface); -static void iface_modem_signal_init (MMIfaceModemSignal *iface); -static void shared_cinterion_init (MMSharedCinterion *iface); - -static MMIfaceModem *iface_modem_parent; -static MMIfaceModem3gpp *iface_modem_3gpp_parent; -static MMIfaceModemLocation *iface_modem_location_parent; -static MMIfaceModemVoice *iface_modem_voice_parent; -static MMIfaceModemTime *iface_modem_time_parent; -static MMIfaceModemSignal *iface_modem_signal_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) - G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_3GPP, iface_modem_3gpp_init) - G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_MESSAGING, iface_modem_messaging_init) - G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init) - G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_VOICE, iface_modem_voice_init) - G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_TIME, iface_modem_time_init) - G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_SIGNAL, iface_modem_signal_init) - G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_CINTERION, shared_cinterion_init)) - -typedef enum { - FEATURE_SUPPORT_UNKNOWN, - FEATURE_NOT_SUPPORTED, - FEATURE_SUPPORTED, -} FeatureSupport; - -struct _MMBroadbandModemCinterionPrivate { - /* Command to go into sleep mode */ - gchar *sleep_mode_cmd; - - /* Cached supported bands in Cinterion format */ - guint supported_bands[MM_CINTERION_RB_BLOCK_N]; - - /* Cached supported modes for SMS setup */ - GArray *cnmi_supported_mode; - GArray *cnmi_supported_mt; - GArray *cnmi_supported_bm; - GArray *cnmi_supported_ds; - GArray *cnmi_supported_bfr; - - /* Cached supported rats for SXRAT */ - GArray *sxrat_supported_rat; - GArray *sxrat_supported_pref1; - - /* ignore regex */ - GRegex *sysstart_regex; - /* +CIEV indications as configured via AT^SIND */ - GRegex *ciev_regex; - /* Ignore SIM hotswap SCKS msg, until ready */ - GRegex *scks_regex; - - /* Flags for feature support checks */ - FeatureSupport swwan_support; - FeatureSupport sind_psinfo_support; - FeatureSupport smoni_support; - FeatureSupport sind_simstatus_support; - FeatureSupport sxrat_support; - - /* Mode combination to apply if "any" requested */ - MMModemMode any_allowed; - - /* Flags for model-based behaviors */ - MMCinterionModemFamily modem_family; - MMCinterionRadioBandFormat rb_format; - - /* Initial EPS bearer context number */ - gint initial_eps_bearer_cid; -}; - -/*****************************************************************************/ - -MMCinterionModemFamily -mm_broadband_modem_cinterion_get_family (MMBroadbandModemCinterion *self) -{ - return self->priv->modem_family; -} - -/*****************************************************************************/ -/* Check support (Signal interface) */ - -static gboolean -signal_check_support_finish (MMIfaceModemSignal *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -parent_signal_check_support_ready (MMIfaceModemSignal *self, - GAsyncResult *res, - GTask *task) -{ - GError *error = NULL; - - if (!iface_modem_signal_parent->check_support_finish (self, res, &error)) - g_task_return_error (task, error); - else - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -static void -check_smoni_support (MMBaseModem *_self, - GAsyncResult *res, - GTask *task) -{ - MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self); - - /* Fetch the result to the SMONI test. If no response given (error triggered), assume unsupported */ - if (mm_base_modem_at_command_finish (_self, res, NULL)) { - mm_obj_dbg (self, "SMONI supported"); - self->priv->smoni_support = FEATURE_SUPPORTED; - g_task_return_boolean (task, TRUE); - g_object_unref (task); - return; - } - - mm_obj_dbg (self, "SMONI unsupported"); - self->priv->smoni_support = FEATURE_NOT_SUPPORTED; - - /* Otherwise, check if the parent CESQ-based implementation works */ - g_assert (iface_modem_signal_parent->check_support && iface_modem_signal_parent->check_support_finish); - iface_modem_signal_parent->check_support (MM_IFACE_MODEM_SIGNAL (self), - (GAsyncReadyCallback) parent_signal_check_support_ready, - task); -} - -static void -signal_check_support (MMIfaceModemSignal *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GTask *task; - - task = g_task_new (self, NULL, callback, user_data); - mm_base_modem_at_command (MM_BASE_MODEM (self), - "^SMONI=?", - 3, - TRUE, - (GAsyncReadyCallback) check_smoni_support, - task); -} - -/*****************************************************************************/ -/* Load extended signal information (Signal interface) */ - -static gboolean -signal_load_values_finish (MMIfaceModemSignal *_self, - GAsyncResult *res, - MMSignal **cdma, - MMSignal **evdo, - MMSignal **gsm, - MMSignal **umts, - MMSignal **lte, - MMSignal **nr5g, - GError **error) -{ - MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self); - const gchar *response; - - if (self->priv->smoni_support == FEATURE_NOT_SUPPORTED) - return iface_modem_signal_parent->load_values_finish (_self, res, cdma, evdo, gsm, umts, lte, nr5g, error); - - response = mm_base_modem_at_command_finish (MM_BASE_MODEM (_self), res, error); - if (!response || !mm_cinterion_smoni_response_to_signal_info (response, gsm, umts, lte, error)) - return FALSE; - - if (cdma) - *cdma = NULL; - if (evdo) - *evdo = NULL; - if (nr5g) - *nr5g = NULL; - - return TRUE; -} - -static void -signal_load_values (MMIfaceModemSignal *_self, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self); - - if (self->priv->smoni_support == FEATURE_SUPPORTED) { - mm_base_modem_at_command (MM_BASE_MODEM (self), - "^SMONI", - 3, - FALSE, - callback, - user_data); - return; - } - - /* ^SMONI not supported, fallback to the parent */ - iface_modem_signal_parent->load_values (_self, cancellable, callback, user_data); -} - -/*****************************************************************************/ -/* Enable unsolicited events (SMS indications) (Messaging interface) */ - -static gboolean -messaging_enable_unsolicited_events_finish (MMIfaceModemMessaging *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -cnmi_test_ready (MMBaseModem *self, - GAsyncResult *res, - GTask *task) -{ - GError *error = NULL; - - if (!mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error)) - g_task_return_error (task, error); - else - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -static gboolean -value_supported (const GArray *array, - const guint value) -{ - guint i; - - if (!array) - return FALSE; - - for (i = 0; i < array->len; i++) { - if (g_array_index (array, guint, i) == value) - return TRUE; - } - return FALSE; -} - -static void -messaging_enable_unsolicited_events (MMIfaceModemMessaging *_self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self); - GString *cmd; - GError *error = NULL; - GTask *task; - - task = g_task_new (self, NULL, callback, user_data); - - /* AT+CNMI=<mode>,[<mt>[,<bm>[,<ds>[,<bfr>]]]] */ - cmd = g_string_new ("+CNMI="); - - /* Mode 2 or 1 */ - if (value_supported (self->priv->cnmi_supported_mode, 2)) - g_string_append_printf (cmd, "%u,", 2); - else if (value_supported (self->priv->cnmi_supported_mode, 1)) - g_string_append_printf (cmd, "%u,", 1); - else { - error = g_error_new (MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "SMS settings don't accept [2,1] <mode>"); - goto out; - } - - /* mt 2 or 1 */ - if (value_supported (self->priv->cnmi_supported_mt, 2)) - g_string_append_printf (cmd, "%u,", 2); - else if (value_supported (self->priv->cnmi_supported_mt, 1)) - g_string_append_printf (cmd, "%u,", 1); - else { - error = g_error_new (MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "SMS settings don't accept [2,1] <mt>"); - goto out; - } - - /* bm 2 or 0 */ - if (value_supported (self->priv->cnmi_supported_bm, 2)) - g_string_append_printf (cmd, "%u,", 2); - else if (value_supported (self->priv->cnmi_supported_bm, 0)) - g_string_append_printf (cmd, "%u,", 0); - else { - error = g_error_new (MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "SMS settings don't accept [2,0] <bm>"); - goto out; - } - - /* ds 2, 1 or 0 */ - if (value_supported (self->priv->cnmi_supported_ds, 2)) - g_string_append_printf (cmd, "%u,", 2); - else if (value_supported (self->priv->cnmi_supported_ds, 1)) - g_string_append_printf (cmd, "%u,", 1); - else if (value_supported (self->priv->cnmi_supported_ds, 0)) - g_string_append_printf (cmd, "%u,", 0); - else { - error = g_error_new (MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "SMS settings don't accept [2,1,0] <ds>"); - goto out; - } - - /* bfr 1 */ - if (value_supported (self->priv->cnmi_supported_bfr, 1)) - g_string_append_printf (cmd, "%u", 1); - /* otherwise, skip setting it */ - -out: - /* Early error report */ - if (error) { - g_task_return_error (task, error); - g_object_unref (task); - g_string_free (cmd, TRUE); - return; - } - - mm_base_modem_at_command (MM_BASE_MODEM (self), - cmd->str, - 3, - FALSE, - (GAsyncReadyCallback)cnmi_test_ready, - task); - g_string_free (cmd, TRUE); -} - -/*****************************************************************************/ -/* Check if Messaging supported (Messaging interface) */ - -static gboolean -messaging_check_support_finish (MMIfaceModemMessaging *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -cnmi_format_check_ready (MMBaseModem *_self, - GAsyncResult *res, - GTask *task) -{ - MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self); - GError *error = NULL; - const gchar *response; - - response = mm_base_modem_at_command_finish (_self, res, &error); - if (error) { - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - /* Parse */ - if (!mm_cinterion_parse_cnmi_test (response, - &self->priv->cnmi_supported_mode, - &self->priv->cnmi_supported_mt, - &self->priv->cnmi_supported_bm, - &self->priv->cnmi_supported_ds, - &self->priv->cnmi_supported_bfr, - &error)) { - mm_obj_warn (self, "error reading SMS setup: %s", error->message); - g_error_free (error); - } - - /* CNMI command is supported; assume we have full messaging capabilities */ - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -static void -messaging_check_support (MMIfaceModemMessaging *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GTask *task; - - task = g_task_new (self, NULL, callback, user_data); - - /* We assume that CDMA-only modems don't have messaging capabilities */ - if (mm_iface_modem_is_cdma_only (MM_IFACE_MODEM (self))) { - g_task_return_new_error (task, - MM_CORE_ERROR, - MM_CORE_ERROR_UNSUPPORTED, - "CDMA-only modems don't have messaging capabilities"); - g_object_unref (task); - return; - } - - /* Check CNMI support */ - mm_base_modem_at_command (MM_BASE_MODEM (self), - "+CNMI=?", - 3, - TRUE, - (GAsyncReadyCallback)cnmi_format_check_ready, - task); -} - -/*****************************************************************************/ -/* Power down */ - -static gboolean -modem_power_down_finish (MMIfaceModem *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -sleep_ready (MMBaseModem *self, - GAsyncResult *res, - GTask *task) -{ - g_autoptr(GError) error = NULL; - - if (!mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error)) - mm_obj_dbg (self, "couldn't send power down command: %s", error->message); - - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -static void -send_sleep_mode_command (GTask *task) -{ - MMBroadbandModemCinterion *self; - - self = g_task_get_source_object (task); - - if (self->priv->sleep_mode_cmd && self->priv->sleep_mode_cmd[0]) { - mm_base_modem_at_command (MM_BASE_MODEM (self), - self->priv->sleep_mode_cmd, - 5, - FALSE, - (GAsyncReadyCallback)sleep_ready, - task); - return; - } - - /* No default command; just finish without sending anything */ - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -static void -supported_functionality_status_query_ready (MMBaseModem *_self, - GAsyncResult *res, - GTask *task) -{ - MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self); - const gchar *response; - g_autoptr(GError) error = NULL; - - g_assert (self->priv->sleep_mode_cmd == NULL); - - response = mm_base_modem_at_command_finish (_self, res, &error); - if (!response) { - mm_obj_warn (self, "couldn't query supported functionality status: %s", error->message); - self->priv->sleep_mode_cmd = g_strdup (""); - } else { - /* We need to get which power-off command to use to put the modem in low - * power mode (with serial port open for AT commands, but with RF switched - * off). According to the documentation of various Cinterion modems, some - * support AT+CFUN=4 (HC25) and those which don't support it can use - * AT+CFUN=7 (CYCLIC SLEEP mode with 2s timeout after last character - * received in the serial port). - * - * So, just look for '4' in the reply; if not found, look for '7', and if - * not found, report warning and don't use any. - */ - if (strstr (response, "4") != NULL) { - mm_obj_dbg (self, "device supports CFUN=4 sleep mode"); - self->priv->sleep_mode_cmd = g_strdup ("+CFUN=4"); - } else if (strstr (response, "7") != NULL) { - mm_obj_dbg (self, "device supports CFUN=7 sleep mode"); - self->priv->sleep_mode_cmd = g_strdup ("+CFUN=7"); - } else { - mm_obj_warn (self, "unknown functionality mode to go into sleep mode"); - self->priv->sleep_mode_cmd = g_strdup (""); - } - } - - send_sleep_mode_command (task); -} - -static void -modem_power_down (MMIfaceModem *_self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self); - GTask *task; - - task = g_task_new (self, NULL, callback, user_data); - - /* If sleep command already decided, use it. */ - if (self->priv->sleep_mode_cmd) - send_sleep_mode_command (task); - else - mm_base_modem_at_command ( - MM_BASE_MODEM (self), - "+CFUN=?", - 3, - FALSE, - (GAsyncReadyCallback)supported_functionality_status_query_ready, - task); -} - -/*****************************************************************************/ -/* Modem Power Off */ - -#define MAX_POWER_OFF_WAIT_TIME_SECS 20 - -typedef struct { - MMPortSerialAt *port; - GRegex *shutdown_regex; - gboolean shutdown_received; - gboolean smso_replied; - gboolean serial_open; - guint timeout_id; -} PowerOffContext; - -static void -power_off_context_free (PowerOffContext *ctx) -{ - if (ctx->serial_open) - mm_port_serial_close (MM_PORT_SERIAL (ctx->port)); - if (ctx->timeout_id) - g_source_remove (ctx->timeout_id); - mm_port_serial_at_add_unsolicited_msg_handler (ctx->port, ctx->shutdown_regex, NULL, NULL, NULL); - g_object_unref (ctx->port); - g_regex_unref (ctx->shutdown_regex); - g_slice_free (PowerOffContext, ctx); -} - -static gboolean -modem_power_off_finish (MMIfaceModem *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -complete_power_off (GTask *task) -{ - PowerOffContext *ctx; - - ctx = g_task_get_task_data (task); - - if (!ctx->shutdown_received || !ctx->smso_replied) - return; - - /* remove timeout right away */ - g_assert (ctx->timeout_id); - g_source_remove (ctx->timeout_id); - ctx->timeout_id = 0; - - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -static void -smso_ready (MMBaseModem *self, - GAsyncResult *res, - GTask *task) -{ - PowerOffContext *ctx; - GError *error = NULL; - - ctx = g_task_get_task_data (task); - - if (!mm_base_modem_at_command_full_finish (MM_BASE_MODEM (self), res, &error)) { - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - /* Set as replied and see if we can complete */ - ctx->smso_replied = TRUE; - complete_power_off (task); -} - -static void -shutdown_received (MMPortSerialAt *port, - GMatchInfo *match_info, - GTask *task) -{ - PowerOffContext *ctx; - - ctx = g_task_get_task_data (task); - - /* Cleanup handler right away, we don't want it called any more */ - mm_port_serial_at_add_unsolicited_msg_handler (port, ctx->shutdown_regex, NULL, NULL, NULL); - - /* Set as received and see if we can complete */ - ctx->shutdown_received = TRUE; - complete_power_off (task); -} - -static gboolean -power_off_timeout_cb (GTask *task) -{ - PowerOffContext *ctx; - - ctx = g_task_get_task_data (task); - - ctx->timeout_id = 0; - - /* The SMSO reply should have come earlier */ - g_warn_if_fail (ctx->smso_replied == TRUE); - - /* Cleanup handler right away, we no longer want to receive it */ - mm_port_serial_at_add_unsolicited_msg_handler (ctx->port, ctx->shutdown_regex, NULL, NULL, NULL); - - g_task_return_new_error (task, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Power off operation timed out"); - g_object_unref (task); - - return G_SOURCE_REMOVE; -} - -static void -modem_power_off (MMIfaceModem *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GTask *task; - PowerOffContext *ctx; - GError *error = NULL; - - task = g_task_new (self, NULL, callback, user_data); - - ctx = g_slice_new0 (PowerOffContext); - ctx->port = mm_base_modem_get_port_primary (MM_BASE_MODEM (self)); - ctx->shutdown_regex = g_regex_new ("\\r\\n\\^SHUTDOWN\\r\\n", - G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - ctx->timeout_id = g_timeout_add_seconds (MAX_POWER_OFF_WAIT_TIME_SECS, - (GSourceFunc)power_off_timeout_cb, - task); - g_task_set_task_data (task, ctx, (GDestroyNotify) power_off_context_free); - - /* We'll need to wait for a ^SHUTDOWN before returning the action, which is - * when the modem tells us that it is ready to be shutdown */ - mm_port_serial_at_add_unsolicited_msg_handler ( - ctx->port, - ctx->shutdown_regex, - (MMPortSerialAtUnsolicitedMsgFn)shutdown_received, - task, - NULL); - - /* In order to get the ^SHUTDOWN notification, we must keep the port open - * during the wait time */ - ctx->serial_open = mm_port_serial_open (MM_PORT_SERIAL (ctx->port), &error); - if (G_UNLIKELY (error)) { - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - /* Note: we'll use a timeout < MAX_POWER_OFF_WAIT_TIME_SECS for the AT command, - * so we're sure that the AT command reply will always come before the timeout - * fires */ - g_assert (MAX_POWER_OFF_WAIT_TIME_SECS > 5); - mm_base_modem_at_command_full (MM_BASE_MODEM (self), - ctx->port, - "^SMSO", - 5, - FALSE, /* allow_cached */ - FALSE, /* is_raw */ - NULL, /* cancellable */ - (GAsyncReadyCallback)smso_ready, - task); -} - -/*****************************************************************************/ -/* Access technologies polling */ - -static gboolean -load_access_technologies_finish (MMIfaceModem *self, - GAsyncResult *res, - MMModemAccessTechnology *access_technologies, - guint *mask, - GError **error) -{ - GError *inner_error = NULL; - gssize val; - - val = g_task_propagate_int (G_TASK (res), &inner_error); - if (inner_error) { - g_propagate_error (error, inner_error); - return FALSE; - } - - *access_technologies = (MMModemAccessTechnology) val; - *mask = MM_MODEM_ACCESS_TECHNOLOGY_ANY; - return TRUE; -} - -static void -smong_query_ready (MMBaseModem *self, - GAsyncResult *res, - GTask *task) -{ - const gchar *response; - GError *error = NULL; - MMModemAccessTechnology access_tech; - - response = mm_base_modem_at_command_finish (self, res, &error); - if (!response || !mm_cinterion_parse_smong_response (response, &access_tech, &error)) - g_task_return_error (task, error); - else - g_task_return_int (task, (gssize) access_tech); - g_object_unref (task); -} - -static void -load_access_technologies (MMIfaceModem *_self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self); - GTask *task; - - task = g_task_new (self, NULL, callback, user_data); - - /* Abort access technology polling if ^SIND psinfo URCs are enabled */ - if (self->priv->sind_psinfo_support == FEATURE_SUPPORTED) { - g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED, "No need to poll access technologies"); - g_object_unref (task); - return; - } - - mm_base_modem_at_command ( - MM_BASE_MODEM (self), - "^SMONG", - 3, - FALSE, - (GAsyncReadyCallback)smong_query_ready, - task); -} - -/*****************************************************************************/ -/* Disable unsolicited events (3GPP interface) */ - -static gboolean -modem_3gpp_disable_unsolicited_events_finish (MMIfaceModem3gpp *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -parent_disable_unsolicited_events_ready (MMIfaceModem3gpp *self, - GAsyncResult *res, - GTask *task) -{ - g_autoptr(GError) error = NULL; - - if (!iface_modem_3gpp_parent->disable_unsolicited_events_finish (self, res, &error)) - mm_obj_warn (self, "couldn't disable parent 3GPP unsolicited events: %s", error->message); - - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -static void -parent_disable_unsolicited_messages (GTask *task) -{ - /* Chain up parent's disable */ - iface_modem_3gpp_parent->disable_unsolicited_events ( - MM_IFACE_MODEM_3GPP (g_task_get_source_object (task)), - (GAsyncReadyCallback)parent_disable_unsolicited_events_ready, - task); -} - -static void -sind_psinfo_disable_ready (MMBaseModem *self, - GAsyncResult *res, - GTask *task) -{ - g_autoptr(GError) error = NULL; - - if (!mm_base_modem_at_command_finish (self, res, &error)) - mm_obj_warn (self, "Couldn't disable ^SIND psinfo notifications: %s", error->message); - - parent_disable_unsolicited_messages (task); -} - -static void -modem_3gpp_disable_unsolicited_events (MMIfaceModem3gpp *_self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - MMBroadbandModemCinterion *self; - GTask *task; - - self = MM_BROADBAND_MODEM_CINTERION (_self); - - task = g_task_new (self, NULL, callback, user_data); - - if (self->priv->sind_psinfo_support == FEATURE_SUPPORTED) { - /* Disable access technology update reporting */ - mm_base_modem_at_command (MM_BASE_MODEM (self), - "AT^SIND=\"psinfo\",0", - 3, - FALSE, - (GAsyncReadyCallback)sind_psinfo_disable_ready, - task); - return; - } - - parent_disable_unsolicited_messages (task); -} - -/*****************************************************************************/ -/* Enable unsolicited events (3GPP interface) */ - -static gboolean -modem_3gpp_enable_unsolicited_events_finish (MMIfaceModem3gpp *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -sind_psinfo_enable_ready (MMBaseModem *_self, - GAsyncResult *res, - GTask *task) -{ - MMBroadbandModemCinterion *self; - g_autoptr(GError) error = NULL; - const gchar *response; - guint mode; - guint val; - - self = MM_BROADBAND_MODEM_CINTERION (_self); - if (!(response = mm_base_modem_at_command_finish (_self, res, &error))) { - /* something went wrong, disable indicator */ - self->priv->sind_psinfo_support = FEATURE_NOT_SUPPORTED; - mm_obj_warn (self, "couldn't enable ^SIND psinfo notifications: %s", error->message); - } else if (!mm_cinterion_parse_sind_response (response, NULL, &mode, &val, &error)) { - /* problem with parsing, disable indicator */ - self->priv->sind_psinfo_support = FEATURE_NOT_SUPPORTED; - mm_obj_warn (self, "couldn't parse ^SIND psinfo response: %s", error->message); - } else { - /* Report initial access technology gathered right away */ - mm_obj_dbg (self, "reporting initial access technologies..."); - mm_iface_modem_update_access_technologies (MM_IFACE_MODEM (self), - mm_cinterion_get_access_technology_from_sind_psinfo (val, self), - MM_IFACE_MODEM_3GPP_ALL_ACCESS_TECHNOLOGIES_MASK); - } - - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -static void -set_urc_dest_port_ready (MMBaseModem *_self, - GAsyncResult *res, - GTask *task) -{ - MMBroadbandModemCinterion *self; - g_autoptr(GError) error = NULL; - - self = MM_BROADBAND_MODEM_CINTERION (_self); - - if (!mm_base_modem_at_command_finish (MM_BASE_MODEM (_self), res, &error)) - mm_obj_dbg (self, "couldn't guarantee unsolicited events are sent to the correct port: %s", error->message); - - if (self->priv->sind_psinfo_support == FEATURE_SUPPORTED) { - /* Enable access technology update reporting */ - mm_base_modem_at_command (MM_BASE_MODEM (self), - "AT^SIND=\"psinfo\",1", - 3, - FALSE, - (GAsyncReadyCallback)sind_psinfo_enable_ready, - task); - return; - } - - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -static void -parent_enable_unsolicited_events_ready (MMIfaceModem3gpp *self, - GAsyncResult *res, - GTask *task) -{ - g_autoptr(GError) error = NULL; - - if (!iface_modem_3gpp_parent->enable_unsolicited_events_finish (self, res, &error)) - mm_obj_warn (self, "couldn't enable parent 3GPP unsolicited events: %s", error->message); - - /* Make sure unsolicited events are sent to an AT port (PLS9 can default to DATA port) */ - mm_base_modem_at_command (MM_BASE_MODEM (self), - "^SCFG=\"URC/DstIfc\",\"app\"", - 5, - FALSE, - (GAsyncReadyCallback)set_urc_dest_port_ready, - task); -} - -static void -modem_3gpp_enable_unsolicited_events (MMIfaceModem3gpp *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GTask *task; - - task = g_task_new (self, NULL, callback, user_data); - - /* Chain up parent's enable */ - iface_modem_3gpp_parent->enable_unsolicited_events ( - self, - (GAsyncReadyCallback)parent_enable_unsolicited_events_ready, - task); -} - -/*****************************************************************************/ -/* Setup/Cleanup unsolicited events (3GPP interface) */ - -static void -sind_ciev_received (MMPortSerialAt *port, - GMatchInfo *match_info, - MMBroadbandModemCinterion *self) -{ - guint val = 0; - gchar *indicator; - - indicator = mm_get_string_unquoted_from_match_info (match_info, 1); - if (!mm_get_uint_from_match_info (match_info, 2, &val)) - mm_obj_dbg (self, "couldn't parse indicator '%s' value", indicator); - else { - mm_obj_dbg (self, "received indicator '%s' update: %u", indicator, val); - if (g_strcmp0 (indicator, "psinfo") == 0) { - mm_iface_modem_update_access_technologies (MM_IFACE_MODEM (self), - mm_cinterion_get_access_technology_from_sind_psinfo (val, self), - MM_IFACE_MODEM_3GPP_ALL_ACCESS_TECHNOLOGIES_MASK); - } - } - g_free (indicator); -} - -static void -set_unsolicited_events_handlers (MMBroadbandModemCinterion *self, - gboolean enable) -{ - MMPortSerialAt *ports[2]; - guint i; - - ports[0] = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)); - ports[1] = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self)); - - /* Enable unsolicited events in given port */ - for (i = 0; i < G_N_ELEMENTS (ports); i++) { - if (!ports[i]) - continue; - - mm_port_serial_at_add_unsolicited_msg_handler ( - ports[i], - self->priv->ciev_regex, - enable ? (MMPortSerialAtUnsolicitedMsgFn)sind_ciev_received : NULL, - enable ? self : NULL, - NULL); - } -} - -static gboolean -modem_3gpp_setup_cleanup_unsolicited_events_finish (MMIfaceModem3gpp *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -parent_setup_unsolicited_events_ready (MMIfaceModem3gpp *self, - GAsyncResult *res, - GTask *task) -{ - GError *error = NULL; - - if (!iface_modem_3gpp_parent->setup_unsolicited_events_finish (self, res, &error)) - g_task_return_error (task, error); - else { - /* Our own setup now */ - set_unsolicited_events_handlers (MM_BROADBAND_MODEM_CINTERION (self), TRUE); - g_task_return_boolean (task, TRUE); - } - g_object_unref (task); -} - -static void -modem_3gpp_setup_unsolicited_events (MMIfaceModem3gpp *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GTask *task; - - task = g_task_new (self, NULL, callback, user_data); - - /* Chain up parent's setup */ - iface_modem_3gpp_parent->setup_unsolicited_events ( - self, - (GAsyncReadyCallback)parent_setup_unsolicited_events_ready, - task); -} - -static void -parent_cleanup_unsolicited_events_ready (MMIfaceModem3gpp *self, - GAsyncResult *res, - GTask *task) -{ - GError *error = NULL; - - if (!iface_modem_3gpp_parent->cleanup_unsolicited_events_finish (self, res, &error)) - g_task_return_error (task, error); - else - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -static void -modem_3gpp_cleanup_unsolicited_events (MMIfaceModem3gpp *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GTask *task; - - task = g_task_new (self, NULL, callback, user_data); - - /* Our own cleanup first */ - set_unsolicited_events_handlers (MM_BROADBAND_MODEM_CINTERION (self), FALSE); - - /* And now chain up parent's cleanup */ - iface_modem_3gpp_parent->cleanup_unsolicited_events ( - self, - (GAsyncReadyCallback)parent_cleanup_unsolicited_events_ready, - task); -} - -/*****************************************************************************/ -/* Common operation to load expected CID for the initial EPS bearer */ - -static gboolean -load_initial_eps_bearer_cid_finish (MMBroadbandModemCinterion *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -scfg_prov_cfg_query_ready (MMBaseModem *_self, - GAsyncResult *res, - GTask *task) -{ - MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self); - g_autoptr(GError) error = NULL; - const gchar *response; - - response = mm_base_modem_at_command_finish (_self, res, &error); - if (!response) - mm_obj_dbg (self, "couldn't query MNO profiles: %s", error->message); - - else if (!mm_cinterion_provcfg_response_to_cid (response, - MM_BROADBAND_MODEM_CINTERION (self)->priv->modem_family, - mm_broadband_modem_get_current_charset (MM_BROADBAND_MODEM (self)), - self, - &self->priv->initial_eps_bearer_cid, - &error)) - mm_obj_dbg (self, "failed processing list of MNO profiles: %s", error->message); - - if (self->priv->initial_eps_bearer_cid < 0) { - mm_obj_dbg (self, "using default EPS bearer context id: 1"); - self->priv->initial_eps_bearer_cid = 1; - } else - mm_obj_dbg (self, "loaded EPS bearer context id from list of MNO profiles: %d", self->priv->initial_eps_bearer_cid); - - /* This operation really never fails */ - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -static void -load_initial_eps_bearer_cid (MMBroadbandModemCinterion *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GTask *task; - - g_assert (self->priv->initial_eps_bearer_cid < 0); - - task = g_task_new (self, NULL, callback, user_data); - mm_base_modem_at_command (MM_BASE_MODEM (self), - "^SCFG=\"MEopMode/Prov/Cfg\"", - 20, - FALSE, - (GAsyncReadyCallback)scfg_prov_cfg_query_ready, - task); -} - -/*****************************************************************************/ -/* Set initial EPS bearer settings */ - -typedef enum { - SET_INITIAL_EPS_STEP_FIRST = 0, - SET_INITIAL_EPS_STEP_CHECK_MODE, - SET_INITIAL_EPS_STEP_RF_OFF, - SET_INITIAL_EPS_STEP_APN, - SET_INITIAL_EPS_STEP_AUTH, - SET_INITIAL_EPS_STEP_RF_ON, - SET_INITIAL_EPS_STEP_LAST, -} SetInitialEpsStep; - -typedef struct { - MMBearerProperties *properties; - SetInitialEpsStep step; - guint initial_cfun_mode; - GError *saved_error; -} SetInitialEpsContext; - -static void -set_initial_eps_context_free (SetInitialEpsContext *ctx) -{ - g_assert (!ctx->saved_error); - g_object_unref (ctx->properties); - g_slice_free (SetInitialEpsContext, ctx); -} - -static gboolean -modem_3gpp_set_initial_eps_bearer_settings_finish (MMIfaceModem3gpp *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void set_initial_eps_step (GTask *task); - -static void -set_initial_eps_rf_on_ready (MMBaseModem *self, - GAsyncResult *res, - GTask *task) -{ - g_autoptr(GError) error = NULL; - SetInitialEpsContext *ctx; - - ctx = (SetInitialEpsContext *) g_task_get_task_data (task); - - if (!mm_base_modem_at_command_finish (self, res, &error)) { - mm_obj_warn (self, "couldn't set RF back on: %s", error->message); - if (!ctx->saved_error) - ctx->saved_error = g_steal_pointer (&error); - } - - /* Go to next step */ - ctx->step++; - set_initial_eps_step (task); -} - -static void -set_initial_eps_auth_ready (MMBaseModem *_self, - GAsyncResult *res, - GTask *task) -{ - MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self); - SetInitialEpsContext *ctx; - - ctx = (SetInitialEpsContext *) g_task_get_task_data (task); - - if (!mm_base_modem_at_command_finish (_self, res, &ctx->saved_error)) { - mm_obj_warn (self, "couldn't configure context %d auth settings: %s", - self->priv->initial_eps_bearer_cid, ctx->saved_error->message); - /* Fallback to recover RF before returning the error */ - ctx->step = SET_INITIAL_EPS_STEP_RF_ON; - } else { - /* Go to next step */ - ctx->step++; - } - set_initial_eps_step (task); -} - -static void -set_initial_eps_cgdcont_ready (MMBaseModem *_self, - GAsyncResult *res, - GTask *task) -{ - MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self); - SetInitialEpsContext *ctx; - - ctx = (SetInitialEpsContext *) g_task_get_task_data (task); - - if (!mm_base_modem_at_command_finish (_self, res, &ctx->saved_error)) { - mm_obj_warn (self, "couldn't configure context %d settings: %s", - self->priv->initial_eps_bearer_cid, ctx->saved_error->message); - /* Fallback to recover RF before returning the error */ - ctx->step = SET_INITIAL_EPS_STEP_RF_ON; - } else { - /* Go to next step */ - ctx->step++; - } - set_initial_eps_step (task); -} - -static void -set_initial_eps_rf_off_ready (MMBaseModem *self, - GAsyncResult *res, - GTask *task) -{ - GError *error = NULL; - SetInitialEpsContext *ctx; - - ctx = (SetInitialEpsContext *) g_task_get_task_data (task); - - if (!mm_base_modem_at_command_finish (self, res, &error)) { - mm_obj_warn (self, "couldn't set RF off: %s", error->message); - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - /* Go to next step */ - ctx->step++; - set_initial_eps_step (task); -} - -static void -set_initial_eps_cfun_mode_load_ready (MMBaseModem *self, - GAsyncResult *res, - GTask *task) -{ - GError *error = NULL; - const gchar *response; - SetInitialEpsContext *ctx; - guint mode; - - ctx = (SetInitialEpsContext *) g_task_get_task_data (task); - response = mm_base_modem_at_command_finish (self, res, &error); - if (!response || !mm_3gpp_parse_cfun_query_response (response, &mode, &error)) { - mm_obj_warn (self, "couldn't load initial functionality mode: %s", error->message); - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - mm_obj_dbg (self, "current functionality mode: %u", mode); - if (mode != 1 && mode != 4) { - g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_WRONG_STATE, - "cannot setup the default LTE bearer settings: " - "the SIM must be powered"); - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - ctx->initial_cfun_mode = mode; - ctx->step++; - set_initial_eps_step (task); -} - -static void -set_initial_eps_step (GTask *task) -{ - MMBroadbandModemCinterion *self; - SetInitialEpsContext *ctx; - - self = g_task_get_source_object (task); - ctx = g_task_get_task_data (task); - - switch (ctx->step) { - case SET_INITIAL_EPS_STEP_FIRST: - ctx->step++; - /* fall through */ - - case SET_INITIAL_EPS_STEP_CHECK_MODE: - mm_base_modem_at_command ( - MM_BASE_MODEM (self), - "+CFUN?", - 5, - FALSE, - (GAsyncReadyCallback)set_initial_eps_cfun_mode_load_ready, - task); - return; - - case SET_INITIAL_EPS_STEP_RF_OFF: - if (ctx->initial_cfun_mode != 4) { - mm_base_modem_at_command ( - MM_BASE_MODEM (self), - "+CFUN=4", - 5, - FALSE, - (GAsyncReadyCallback)set_initial_eps_rf_off_ready, - task); - return; - } - ctx->step++; - /* fall through */ - - case SET_INITIAL_EPS_STEP_APN: { - const gchar *apn; - g_autofree gchar *quoted_apn = NULL; - g_autofree gchar *apn_cmd = NULL; - const gchar *ip_family_str; - MMBearerIpFamily ip_family; - - ip_family = mm_bearer_properties_get_ip_type (ctx->properties); - if (ip_family == MM_BEARER_IP_FAMILY_NONE || ip_family == MM_BEARER_IP_FAMILY_ANY) - ip_family = MM_BEARER_IP_FAMILY_IPV4; - - ip_family_str = mm_3gpp_get_pdp_type_from_ip_family (ip_family); - apn = mm_bearer_properties_get_apn (ctx->properties); - mm_obj_dbg (self, "context %d with APN '%s' and PDP type '%s'", - self->priv->initial_eps_bearer_cid, apn, ip_family_str); - quoted_apn = mm_port_serial_at_quote_string (apn); - apn_cmd = g_strdup_printf ("+CGDCONT=%u,\"%s\",%s", - self->priv->initial_eps_bearer_cid, ip_family_str, quoted_apn); - mm_base_modem_at_command ( - MM_BASE_MODEM (self), - apn_cmd, - 20, - FALSE, - (GAsyncReadyCallback)set_initial_eps_cgdcont_ready, - task); - return; - } - - case SET_INITIAL_EPS_STEP_AUTH: { - g_autofree gchar *auth_cmd = NULL; - - auth_cmd = mm_cinterion_build_auth_string (self, - MM_BROADBAND_MODEM_CINTERION (self)->priv->modem_family, - ctx->properties, - self->priv->initial_eps_bearer_cid); - mm_base_modem_at_command ( - MM_BASE_MODEM (self), - auth_cmd, - 20, - FALSE, - (GAsyncReadyCallback)set_initial_eps_auth_ready, - task); - return; - } - - case SET_INITIAL_EPS_STEP_RF_ON: - if (ctx->initial_cfun_mode == 1) { - mm_base_modem_at_command ( - MM_BASE_MODEM (self), - "+CFUN=1", - 5, - FALSE, - (GAsyncReadyCallback)set_initial_eps_rf_on_ready, - task); - return; - } - ctx->step++; - /* fall through */ - - case SET_INITIAL_EPS_STEP_LAST: - if (ctx->saved_error) - g_task_return_error (task, g_steal_pointer (&ctx->saved_error)); - else - g_task_return_boolean (task, TRUE); - g_object_unref (task); - return; - - default: - g_assert_not_reached (); - } -} - -static void -modem_3gpp_set_initial_eps_bearer_settings (MMIfaceModem3gpp *self, - MMBearerProperties *properties, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GTask *task; - SetInitialEpsContext *ctx; - - task = g_task_new (self, NULL, callback, user_data); - - /* The initial EPS bearer settings should have already been loaded */ - g_assert (MM_BROADBAND_MODEM_CINTERION (self)->priv->initial_eps_bearer_cid >= 0); - - /* Setup context */ - ctx = g_slice_new0 (SetInitialEpsContext); - ctx->properties = g_object_ref (properties); - ctx->step = SET_INITIAL_EPS_STEP_FIRST; - g_task_set_task_data (task, ctx, (GDestroyNotify) set_initial_eps_context_free); - - set_initial_eps_step (task); -} - -/*****************************************************************************/ -/* Common initial EPS bearer info loading for both: - * - runtime status - * - configuration settings - */ - -typedef enum { - COMMON_LOAD_INITIAL_EPS_STEP_FIRST = 0, - COMMON_LOAD_INITIAL_EPS_STEP_PROFILE, - COMMON_LOAD_INITIAL_EPS_STEP_APN, - COMMON_LOAD_INITIAL_EPS_STEP_AUTH, - COMMON_LOAD_INITIAL_EPS_STEP_LAST, -} CommonLoadInitialEpsStep; - -typedef struct { - MMBearerProperties *properties; - CommonLoadInitialEpsStep step; - gboolean runtime; -} CommonLoadInitialEpsContext; - -static void -common_load_initial_eps_context_free (CommonLoadInitialEpsContext *ctx) -{ - g_clear_object (&ctx->properties); - g_slice_free (CommonLoadInitialEpsContext, ctx); -} - -static MMBearerProperties * -common_load_initial_eps_bearer_finish (MMIfaceModem3gpp *self, - GAsyncResult *res, - GError **error) -{ - return MM_BEARER_PROPERTIES (g_task_propagate_pointer (G_TASK (res), error)); -} - -static void common_load_initial_eps_step (GTask *task); - -static void -common_load_initial_eps_auth_ready (MMBaseModem *_self, - GAsyncResult *res, - GTask *task) -{ - MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self); - const gchar *response; - CommonLoadInitialEpsContext *ctx; - g_autoptr(GError) error = NULL; - MMBearerAllowedAuth auth = MM_BEARER_ALLOWED_AUTH_UNKNOWN; - g_autofree gchar *username = NULL; - - ctx = (CommonLoadInitialEpsContext *) g_task_get_task_data (task); - - response = mm_base_modem_at_command_finish (_self, res, &error); - if (!response) - mm_obj_dbg (self, "couldn't load context %d auth settings: %s", - self->priv->initial_eps_bearer_cid, error->message); - else if (!mm_cinterion_parse_sgauth_response (response, self->priv->initial_eps_bearer_cid, &auth, &username, &error)) - mm_obj_dbg (self, "couldn't parse context %d auth settings: %s", self->priv->initial_eps_bearer_cid, error->message); - else { - mm_bearer_properties_set_allowed_auth (ctx->properties, auth); - mm_bearer_properties_set_user (ctx->properties, username); - } - - /* Go to next step */ - ctx->step++; - common_load_initial_eps_step (task); -} - -static void -common_load_initial_eps_load_cid_ready (MMBroadbandModemCinterion *self, - GAsyncResult *res, - GTask *task) -{ - CommonLoadInitialEpsContext *ctx; - - ctx = (CommonLoadInitialEpsContext *) g_task_get_task_data (task); - - load_initial_eps_bearer_cid_finish (self, res, NULL); - g_assert (self->priv->initial_eps_bearer_cid >= 0); - - /* Go to next step */ - ctx->step++; - common_load_initial_eps_step (task); -} - -static void -common_load_initial_eps_cgcontrdp_ready (MMBaseModem *_self, - GAsyncResult *res, - GTask *task) -{ - MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self); - const gchar *response; - CommonLoadInitialEpsContext *ctx; - g_autofree gchar *apn = NULL; - g_autoptr(GError) error = NULL; - - ctx = (CommonLoadInitialEpsContext *) g_task_get_task_data (task); - - /* errors aren't fatal */ - response = mm_base_modem_at_command_finish (_self, res, &error); - if (!response) - mm_obj_dbg (self, "couldn't load context %d settings: %s", - self->priv->initial_eps_bearer_cid, error->message); - else if (!mm_3gpp_parse_cgcontrdp_response (response, NULL, NULL, &apn, NULL, NULL, NULL, NULL, NULL, &error)) - mm_obj_dbg (self, "couldn't parse CGDCONTRDP response: %s", error->message); - else - mm_bearer_properties_set_apn (ctx->properties, apn); - - /* Go to next step */ - ctx->step++; - common_load_initial_eps_step (task); -} - -static void -common_load_initial_eps_cgdcont_ready (MMBaseModem *_self, - GAsyncResult *res, - GTask *task) -{ - MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self); - const gchar *response; - CommonLoadInitialEpsContext *ctx; - g_autoptr(GError) error = NULL; - - ctx = (CommonLoadInitialEpsContext *) g_task_get_task_data (task); - - /* errors aren't fatal */ - response = mm_base_modem_at_command_finish (_self, res, &error); - if (!response) - mm_obj_dbg (self, "couldn't load context %d status: %s", - self->priv->initial_eps_bearer_cid, error->message); - else { - GList *context_list; - - context_list = mm_3gpp_parse_cgdcont_read_response (response, &error); - if (!context_list) - mm_obj_dbg (self, "couldn't parse CGDCONT response: %s", error->message); - else { - GList *l; - - for (l = context_list; l; l = g_list_next (l)) { - MM3gppPdpContext *pdp = l->data; - - if (pdp->cid == (guint) self->priv->initial_eps_bearer_cid) { - mm_bearer_properties_set_ip_type (ctx->properties, pdp->pdp_type); - mm_bearer_properties_set_apn (ctx->properties, pdp->apn ? pdp->apn : ""); - break; - } - } - if (!l) - mm_obj_dbg (self, "no status reported for context %d", self->priv->initial_eps_bearer_cid); - mm_3gpp_pdp_context_list_free (context_list); - } - } - - /* Go to next step */ - ctx->step++; - common_load_initial_eps_step (task); -} - -static void -common_load_initial_eps_step (GTask *task) -{ - MMBroadbandModemCinterion *self; - CommonLoadInitialEpsContext *ctx; - - self = g_task_get_source_object (task); - ctx = g_task_get_task_data (task); - - switch (ctx->step) { - case COMMON_LOAD_INITIAL_EPS_STEP_FIRST: - ctx->step++; - /* fall through */ - - case COMMON_LOAD_INITIAL_EPS_STEP_PROFILE: - /* Initial EPS bearer CID initialization run once only */ - if (G_UNLIKELY (self->priv->initial_eps_bearer_cid < 0)) { - load_initial_eps_bearer_cid ( - self, - (GAsyncReadyCallback)common_load_initial_eps_load_cid_ready, - task); - return; - } - ctx->step++; - /* fall through */ - - case COMMON_LOAD_INITIAL_EPS_STEP_APN: - if (ctx->runtime) { - mm_base_modem_at_command ( - MM_BASE_MODEM (self), - "+CGDCONT?", - 20, - FALSE, - (GAsyncReadyCallback)common_load_initial_eps_cgdcont_ready, - task); - } else { - g_autofree gchar *cmd = NULL; - - cmd = g_strdup_printf ("+CGCONTRDP=%u", self->priv->initial_eps_bearer_cid); - mm_base_modem_at_command ( - MM_BASE_MODEM (self), - "+CGCONTRDP", - 20, - FALSE, - (GAsyncReadyCallback)common_load_initial_eps_cgcontrdp_ready, - task); - } - return; - - case COMMON_LOAD_INITIAL_EPS_STEP_AUTH: - mm_base_modem_at_command ( - MM_BASE_MODEM (self), - "^SGAUTH?", - 20, - FALSE, - (GAsyncReadyCallback)common_load_initial_eps_auth_ready, - task); - return; - - case COMMON_LOAD_INITIAL_EPS_STEP_LAST: - g_task_return_pointer (task, g_steal_pointer (&ctx->properties), g_object_unref); - g_object_unref (task); - return; - - default: - g_assert_not_reached (); - } -} - -static void -common_load_initial_eps_bearer (MMIfaceModem3gpp *self, - gboolean runtime, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GTask *task; - CommonLoadInitialEpsContext *ctx; - - task = g_task_new (self, NULL, callback, user_data); - - /* Setup context */ - ctx = g_slice_new0 (CommonLoadInitialEpsContext); - ctx->runtime = runtime; - ctx->properties = mm_bearer_properties_new (); - ctx->step = COMMON_LOAD_INITIAL_EPS_STEP_FIRST; - g_task_set_task_data (task, ctx, (GDestroyNotify) common_load_initial_eps_context_free); - - common_load_initial_eps_step (task); -} - -/*****************************************************************************/ -/* Initial EPS bearer runtime status loading */ - -static MMBearerProperties * -modem_3gpp_load_initial_eps_bearer_finish (MMIfaceModem3gpp *self, - GAsyncResult *res, - GError **error) -{ - return common_load_initial_eps_bearer_finish (self, res, error); -} - -static void -modem_3gpp_load_initial_eps_bearer (MMIfaceModem3gpp *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - common_load_initial_eps_bearer (self, TRUE, callback, user_data); -} - -/*****************************************************************************/ -/* Initial EPS bearer settings loading -> set configuration */ - -static MMBearerProperties * -modem_3gpp_load_initial_eps_bearer_settings_finish (MMIfaceModem3gpp *self, - GAsyncResult *res, - GError **error) -{ - return common_load_initial_eps_bearer_finish (self, res, error); -} - -static void -modem_3gpp_load_initial_eps_bearer_settings (MMIfaceModem3gpp *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - common_load_initial_eps_bearer (self, FALSE, callback, user_data); -} - -/*****************************************************************************/ -/* Load supported modes (Modem interface) */ - -static GArray * -load_supported_modes_finish (MMIfaceModem *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_pointer (G_TASK (res), error); -} - -static void -parent_load_supported_modes_ready (MMIfaceModem *self, - GAsyncResult *res, - GTask *task) -{ - GError *error = NULL; - GArray *all; - GArray *combinations; - GArray *filtered; - MMModemModeCombination mode; - - all = iface_modem_parent->load_supported_modes_finish (self, res, &error); - if (!all) { - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - /* Build list of combinations */ - combinations = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), 3); - - /* 2G only */ - mode.allowed = MM_MODEM_MODE_2G; - mode.preferred = MM_MODEM_MODE_NONE; - g_array_append_val (combinations, mode); - /* 3G only */ - mode.allowed = MM_MODEM_MODE_3G; - mode.preferred = MM_MODEM_MODE_NONE; - g_array_append_val (combinations, mode); - - if (mm_iface_modem_is_4g (self)) { - /* 4G only */ - mode.allowed = MM_MODEM_MODE_4G; - mode.preferred = MM_MODEM_MODE_NONE; - g_array_append_val (combinations, mode); - /* 2G, 3G and 4G */ - mode.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G); - mode.preferred = MM_MODEM_MODE_NONE; - g_array_append_val (combinations, mode); - } else { - /* 2G and 3G */ - mode.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G); - mode.preferred = MM_MODEM_MODE_NONE; - g_array_append_val (combinations, mode); - } - - /* Filter out those unsupported modes */ - filtered = mm_filter_supported_modes (all, combinations, self); - g_array_unref (all); - g_array_unref (combinations); - - g_task_return_pointer (task, filtered, (GDestroyNotify) g_array_unref); - g_object_unref (task); -} - -static void -sxrat_load_supported_modes_ready (MMBroadbandModemCinterion *self, - GTask *task) -{ - GArray *combinations; - MMModemModeCombination mode; - - g_assert (self->priv->sxrat_supported_rat); - g_assert (self->priv->sxrat_supported_pref1); - - /* Build list of combinations */ - combinations = g_array_sized_new (FALSE, FALSE, sizeof (MMModemModeCombination), 3); - - if (value_supported (self->priv->sxrat_supported_rat, 0)) { - /* 2G only */ - mode.allowed = MM_MODEM_MODE_2G; - mode.preferred = MM_MODEM_MODE_NONE; - g_array_append_val (combinations, mode); - } - if (value_supported (self->priv->sxrat_supported_rat, 1)) { - /* 2G+3G with none preferred */ - mode.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G); - mode.preferred = MM_MODEM_MODE_NONE; - g_array_append_val (combinations, mode); - - self->priv->any_allowed = mode.allowed; - - if (value_supported (self->priv->sxrat_supported_pref1, 0)) { - /* 2G preferred */ - mode.preferred = MM_MODEM_MODE_2G; - g_array_append_val (combinations, mode); - } - if (value_supported (self->priv->sxrat_supported_pref1, 2)) { - /* 3G preferred */ - mode.preferred = MM_MODEM_MODE_3G; - g_array_append_val (combinations, mode); - } - } - if (value_supported (self->priv->sxrat_supported_rat, 2)) { - /* 3G only */ - mode.allowed = MM_MODEM_MODE_3G; - mode.preferred = MM_MODEM_MODE_NONE; - g_array_append_val (combinations, mode); - } - if (value_supported (self->priv->sxrat_supported_rat, 3)) { - /* 4G only */ - mode.allowed = MM_MODEM_MODE_4G; - mode.preferred = MM_MODEM_MODE_NONE; - g_array_append_val (combinations, mode); - } - if (value_supported (self->priv->sxrat_supported_rat, 4)) { - /* 3G+4G with none preferred */ - mode.allowed = (MM_MODEM_MODE_3G | MM_MODEM_MODE_4G); - mode.preferred = MM_MODEM_MODE_NONE; - g_array_append_val (combinations, mode); - - self->priv->any_allowed = mode.allowed; - - if (value_supported (self->priv->sxrat_supported_pref1, 2)) { - /* 3G preferred */ - mode.preferred = MM_MODEM_MODE_3G; - g_array_append_val (combinations, mode); - } - if (value_supported (self->priv->sxrat_supported_pref1, 3)) { - /* 4G preferred */ - mode.preferred = MM_MODEM_MODE_4G; - g_array_append_val (combinations, mode); - } - } - if (value_supported (self->priv->sxrat_supported_rat, 5)) { - /* 2G+4G with none preferred */ - mode.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_4G); - mode.preferred = MM_MODEM_MODE_NONE; - g_array_append_val (combinations, mode); - - self->priv->any_allowed = mode.allowed; - - if (value_supported (self->priv->sxrat_supported_pref1, 0)) { - /* 2G preferred */ - mode.preferred = MM_MODEM_MODE_2G; - g_array_append_val (combinations, mode); - } - if (value_supported (self->priv->sxrat_supported_pref1, 3)) { - /* 4G preferred */ - mode.preferred = MM_MODEM_MODE_4G; - g_array_append_val (combinations, mode); - } - } - if (value_supported (self->priv->sxrat_supported_rat, 6)) { - /* 2G+3G+4G with none preferred */ - mode.allowed = (MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G); - mode.preferred = MM_MODEM_MODE_NONE; - g_array_append_val (combinations, mode); - - self->priv->any_allowed = mode.allowed; - - if (value_supported (self->priv->sxrat_supported_pref1, 0)) { - /* 2G preferred */ - mode.preferred = MM_MODEM_MODE_2G; - g_array_append_val (combinations, mode); - } - if (value_supported (self->priv->sxrat_supported_pref1, 2)) { - /* 3G preferred */ - mode.preferred = MM_MODEM_MODE_3G; - g_array_append_val (combinations, mode); - } - if (value_supported (self->priv->sxrat_supported_pref1, 3)) { - /* 4G preferred */ - mode.preferred = MM_MODEM_MODE_4G; - g_array_append_val (combinations, mode); - } - } - - g_task_return_pointer (task, combinations, (GDestroyNotify) g_array_unref); - g_object_unref (task); -} - -static void -sxrat_test_ready (MMBaseModem *_self, - GAsyncResult *res, - GTask *task) -{ - MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self); - g_autoptr(GError) error = NULL; - const gchar *response; - - response = mm_base_modem_at_command_finish (_self, res, &error); - if (!error) { - mm_cinterion_parse_sxrat_test (response, - &self->priv->sxrat_supported_rat, - &self->priv->sxrat_supported_pref1, - NULL, - &error); - if (!error) { - self->priv->sxrat_support = FEATURE_SUPPORTED; - sxrat_load_supported_modes_ready (self, task); - return; - } - mm_obj_warn (self, "error reading SXRAT response: %s", error->message); - } - - self->priv->sxrat_support = FEATURE_NOT_SUPPORTED; - - /* Run parent's loading in case SXRAT is not supported */ - iface_modem_parent->load_supported_modes ( - MM_IFACE_MODEM (self), - (GAsyncReadyCallback)parent_load_supported_modes_ready, - task); -} - -static void -load_supported_modes (MMIfaceModem *_self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self); - GTask *task; - - task = g_task_new (self, NULL, callback, user_data); - - /* First check SXRAT support, if not already done */ - if (self->priv->sxrat_support == FEATURE_SUPPORT_UNKNOWN) { - mm_base_modem_at_command (MM_BASE_MODEM (self), - "^SXRAT=?", - 3, - TRUE, - (GAsyncReadyCallback)sxrat_test_ready, - task); - return; - } - - if (self->priv->sxrat_support == FEATURE_SUPPORTED) { - sxrat_load_supported_modes_ready (self, task); - return; - } - - /* Run parent's loading */ - iface_modem_parent->load_supported_modes ( - MM_IFACE_MODEM (self), - (GAsyncReadyCallback)parent_load_supported_modes_ready, - task); -} - -/*****************************************************************************/ -/* Set current modes (Modem interface) */ - -static gboolean -set_current_modes_finish (MMIfaceModem *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -set_current_modes_reregister_in_network_ready (MMIfaceModem3gpp *self, - GAsyncResult *res, - GTask *task) -{ - GError *error = NULL; - - if (!mm_iface_modem_3gpp_reregister_in_network_finish (self, res, &error)) - g_task_return_error (task, error); - else - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -static void -allowed_access_technology_update_ready (MMBroadbandModemCinterion *self, - GAsyncResult *res, - GTask *task) -{ - GError *error = NULL; - - mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error); - if (error) - g_task_return_error (task, error); - else - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -static void -cops_set_current_modes (MMBroadbandModemCinterion *self, - MMModemMode allowed, - MMModemMode preferred, - GTask *task) -{ - gchar *command; - - g_assert (preferred == MM_MODEM_MODE_NONE); - - /* We will try to simulate the possible allowed modes here. The - * Cinterion devices do not seem to allow setting preferred access - * technology in devices, but they allow restricting to a given - * one: - * - 2G-only is forced by forcing GERAN RAT (AcT=0) - * - 3G-only is forced by forcing UTRAN RAT (AcT=2) - * - 4G-only is forced by forcing E-UTRAN RAT (AcT=7) - * - for the remaining ones, we default to automatic selection of RAT, - * which is based on the quality of the connection. - */ - - if (mm_iface_modem_is_4g (MM_IFACE_MODEM (self)) && allowed == MM_MODEM_MODE_4G) - command = g_strdup ("+COPS=,,,7"); - else if (mm_iface_modem_is_3g (MM_IFACE_MODEM (self)) && allowed == MM_MODEM_MODE_3G) - command = g_strdup ("+COPS=,,,2"); - else if (mm_iface_modem_is_2g (MM_IFACE_MODEM (self)) && allowed == MM_MODEM_MODE_2G) - command = g_strdup ("+COPS=,,,0"); - else { - /* For any other combination (e.g. ANY or no AcT given, defaults to Auto. For this case, we cannot provide - * AT+COPS=,,, (i.e. just without a last value). Instead, we need to - * re-run the last manual/automatic selection command which succeeded, - * (or auto by default if none was launched) */ - mm_iface_modem_3gpp_reregister_in_network (MM_IFACE_MODEM_3GPP (self), - (GAsyncReadyCallback) set_current_modes_reregister_in_network_ready, - task); - return; - } - - mm_base_modem_at_command ( - MM_BASE_MODEM (self), - command, - 20, - FALSE, - (GAsyncReadyCallback)allowed_access_technology_update_ready, - task); - - g_free (command); -} - -static void -sxrat_set_current_modes (MMBroadbandModemCinterion *self, - MMModemMode allowed, - MMModemMode preferred, - GTask *task) -{ - gchar *command; - GError *error = NULL; - - g_assert (self->priv->any_allowed != MM_MODEM_MODE_NONE); - - /* Handle ANY */ - if (allowed == MM_MODEM_MODE_ANY) - allowed = self->priv->any_allowed; - - command = mm_cinterion_build_sxrat_set_command (allowed, preferred, &error); - - if (!command) { - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - mm_base_modem_at_command ( - MM_BASE_MODEM (self), - command, - 30, - FALSE, - (GAsyncReadyCallback)allowed_access_technology_update_ready, - task); - - g_free (command); -} - -static void -set_current_modes (MMIfaceModem *_self, - MMModemMode allowed, - MMModemMode preferred, - GAsyncReadyCallback callback, - gpointer user_data) -{ - MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self); - GTask *task; - - task = g_task_new (self, NULL, callback, user_data); - - if (self->priv->sxrat_support == FEATURE_SUPPORTED) - sxrat_set_current_modes (self, allowed, preferred, task); - else if (self->priv->sxrat_support == FEATURE_NOT_SUPPORTED) - cops_set_current_modes (self, allowed, preferred, task); - else - g_assert_not_reached (); -} - -/*****************************************************************************/ -/* Supported bands (Modem interface) */ - -static GArray * -load_supported_bands_finish (MMIfaceModem *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_pointer (G_TASK (res), error); -} - -static void -scfg_test_ready (MMBaseModem *_self, - GAsyncResult *res, - GTask *task) -{ - MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self); - const gchar *response; - GError *error = NULL; - GArray *bands; - - response = mm_base_modem_at_command_finish (_self, res, &error); - if (!response || - !mm_cinterion_parse_scfg_test (response, - self->priv->modem_family, - mm_broadband_modem_get_current_charset (MM_BROADBAND_MODEM (self)), - &bands, - &self->priv->rb_format, - &error)) - g_task_return_error (task, error); - else { - if (!mm_cinterion_build_band (bands, - NULL, - FALSE, - self->priv->rb_format, - self->priv->modem_family, - self->priv->supported_bands, - &error)) - g_task_return_error (task, error); - else - g_task_return_pointer (task, bands, (GDestroyNotify)g_array_unref); - } - g_object_unref (task); -} - -static void -load_supported_bands (MMIfaceModem *_self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self); - GTask *task; - MMPort *primary; - MMKernelDevice *port; - const gchar *family = NULL; - - /* Lookup for the tag specifying which modem family the current device belongs */ - primary = MM_PORT (mm_base_modem_peek_port_primary (MM_BASE_MODEM (self))); - port = mm_port_peek_kernel_device (primary); - family = mm_kernel_device_get_global_property (port, "ID_MM_CINTERION_MODEM_FAMILY"); - - /* if the property is not set, default family */ - self->priv->modem_family = MM_CINTERION_MODEM_FAMILY_DEFAULT; - - /* set used family also in the string for mm_obj_dbg */ - if (!family) - family = "default"; - - if (g_ascii_strcasecmp (family, "imt") == 0) - self->priv->modem_family = MM_CINTERION_MODEM_FAMILY_IMT; - else if (g_ascii_strcasecmp (family, "default") != 0) { - mm_obj_dbg (self, "cinterion modem family '%s' unknown", family); - family = "default"; - } - - mm_obj_dbg (self, "Using cinterion %s modem family", family); - - task = g_task_new (_self, NULL, callback, user_data); - mm_base_modem_at_command (MM_BASE_MODEM (_self), - "AT^SCFG=?", - 3, - FALSE, - (GAsyncReadyCallback)scfg_test_ready, - task); -} - -/*****************************************************************************/ -/* Load current bands (Modem interface) */ - -static GArray * -load_current_bands_finish (MMIfaceModem *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_pointer (G_TASK (res), error); -} - -static void -get_band_ready (MMBaseModem *_self, - GAsyncResult *res, - GTask *task) -{ - MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self); - const gchar *response; - GError *error = NULL; - GArray *bands = NULL; - - response = mm_base_modem_at_command_finish (_self, res, &error); - if (!response || - !mm_cinterion_parse_scfg_response (response, - self->priv->modem_family, - mm_broadband_modem_get_current_charset (MM_BROADBAND_MODEM (self)), - &bands, - self->priv->rb_format, - &error)) - g_task_return_error (task, error); - else - g_task_return_pointer (task, bands, (GDestroyNotify) g_array_unref); - g_object_unref (task); -} - -static void -load_current_bands (MMIfaceModem *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GTask *task; - - task = g_task_new (self, NULL, callback, user_data); - - /* The timeout in this command is extremely large, because there are some - * modules like the EGS5 that build the response based on the current network - * registration, and that implies the module needs to be registered. If for - * any reason there is no serving network where to register, the response - * comes after a very long time, up to 100s. */ - mm_base_modem_at_command (MM_BASE_MODEM (self), - "AT^SCFG?", - 120, - FALSE, - (GAsyncReadyCallback)get_band_ready, - task); -} - -/*****************************************************************************/ -/* Set current bands (Modem interface) */ - -typedef struct { - MMBaseModemAtCommandAlloc *cmds; -} SetCurrentBandsContext; - -static void -set_current_bands_context_free (SetCurrentBandsContext *ctx) -{ - if (ctx->cmds) { - guint i; - - for (i = 0; ctx->cmds[i].command; i++) - mm_base_modem_at_command_alloc_clear (&ctx->cmds[i]); - g_free (ctx->cmds); - } - g_slice_free (SetCurrentBandsContext, ctx); -} - -static gboolean -set_current_bands_finish (MMIfaceModem *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -scfg_set_ready (MMBaseModem *self, - GAsyncResult *res, - GTask *task) -{ - GError *error = NULL; - - if (!mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error)) - g_task_return_error (task, error); - else - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -static void -scfg_set_ready_sequence (MMBaseModem *self, - GAsyncResult *res, - GTask *task) -{ - GError *error = NULL; - - mm_base_modem_at_sequence_finish (self, res, NULL, &error); - if (error) - g_task_return_error (task, error); - else - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -static void -set_bands_3g (GTask *task, - GArray *bands_array) -{ - MMBroadbandModemCinterion *self; - GError *error = NULL; - guint band[MM_CINTERION_RB_BLOCK_N] = { 0 }; - - self = g_task_get_source_object (task); - - if (!mm_cinterion_build_band (bands_array, - self->priv->supported_bands, - FALSE, /* 2G and 3G */ - self->priv->rb_format, - self->priv->modem_family, - band, - &error)) { - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - if (self->priv->rb_format == MM_CINTERION_RADIO_BAND_FORMAT_SINGLE) { - g_autofree gchar *cmd = NULL; - - /* Following the setup: - * AT^SCFG="Radion/Band",<rba> - * We will set the preferred band equal to the allowed band, so that we force - * the modem to connect at that specific frequency only. Note that we will be - * passing a number here! - * - * The optional <rbe> field is set to 1, so that changes take effect - * immediately. - */ - cmd = g_strdup_printf ("^SCFG=\"Radio/Band\",%u,1", band[MM_CINTERION_RB_BLOCK_LEGACY]); - mm_base_modem_at_command (MM_BASE_MODEM (self), - cmd, - 15, - FALSE, - (GAsyncReadyCallback)scfg_set_ready, - task); - return; - } - - if (self->priv->rb_format == MM_CINTERION_RADIO_BAND_FORMAT_MULTIPLE) { - SetCurrentBandsContext *ctx; - - ctx = g_slice_new0 (SetCurrentBandsContext); - g_task_set_task_data (task, ctx, (GDestroyNotify)set_current_bands_context_free); - - if (self->priv->modem_family == MM_CINTERION_MODEM_FAMILY_IMT) { - g_autofree gchar *bandstr2G = NULL; - g_autofree gchar *bandstr3G = NULL; - g_autofree gchar *bandstr4G = NULL; - g_autofree gchar *bandstr2G_enc = NULL; - g_autofree gchar *bandstr3G_enc = NULL; - g_autofree gchar *bandstr4G_enc = NULL; - - bandstr2G = g_strdup_printf ("0x%08X", band[MM_CINTERION_RB_BLOCK_GSM]); - bandstr3G = g_strdup_printf ("0x%08X", band[MM_CINTERION_RB_BLOCK_UMTS]); - bandstr4G = g_strdup_printf ("0x%08X", band[MM_CINTERION_RB_BLOCK_LTE_LOW]); - - bandstr2G_enc = mm_modem_charset_str_from_utf8 (bandstr2G, - mm_broadband_modem_get_current_charset (MM_BROADBAND_MODEM (self)), - FALSE, - &error); - if (!bandstr2G_enc) { - g_prefix_error (&error, "Couldn't convert 2G band string to current charset: "); - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - bandstr3G_enc = mm_modem_charset_str_from_utf8 (bandstr3G, - mm_broadband_modem_get_current_charset (MM_BROADBAND_MODEM (self)), - FALSE, - &error); - if (!bandstr3G_enc) { - g_prefix_error (&error, "Couldn't convert 3G band string to current charset: "); - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - bandstr4G_enc = mm_modem_charset_str_from_utf8 (bandstr4G, - mm_broadband_modem_get_current_charset (MM_BROADBAND_MODEM (self)), - FALSE, - &error); - if (!bandstr4G_enc) { - g_prefix_error (&error, "Couldn't convert 4G band string to current charset: "); - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - ctx->cmds = g_new0 (MMBaseModemAtCommandAlloc, 3 + 1); - ctx->cmds[0].command = g_strdup_printf ("^SCFG=\"Radio/Band/2G\",\"%s\"", bandstr2G_enc); - ctx->cmds[1].command = g_strdup_printf ("^SCFG=\"Radio/Band/3G\",\"%s\"", bandstr3G_enc); - ctx->cmds[2].command = g_strdup_printf ("^SCFG=\"Radio/Band/4G\",\"%s\"", bandstr4G_enc); - ctx->cmds[0].timeout = ctx->cmds[1].timeout = ctx->cmds[2].timeout = 60; - } else { - ctx->cmds = g_new0 (MMBaseModemAtCommandAlloc, 3 + 1); - ctx->cmds[0].command = g_strdup_printf ("^SCFG=\"Radio/Band/2G\",\"%08x\",,1", band[MM_CINTERION_RB_BLOCK_GSM]); - ctx->cmds[1].command = g_strdup_printf ("^SCFG=\"Radio/Band/3G\",\"%08x\",,1", band[MM_CINTERION_RB_BLOCK_UMTS]); - ctx->cmds[2].command = g_strdup_printf ("^SCFG=\"Radio/Band/4G\",\"%08x\",\"%08x\",1", band[MM_CINTERION_RB_BLOCK_LTE_LOW], band[MM_CINTERION_RB_BLOCK_LTE_HIGH]); - ctx->cmds[0].timeout = ctx->cmds[1].timeout = ctx->cmds[2].timeout = 15; - } - - mm_base_modem_at_sequence (MM_BASE_MODEM (self), - (const MMBaseModemAtCommand *)ctx->cmds, - NULL, - NULL, - (GAsyncReadyCallback)scfg_set_ready_sequence, - task); - return; - } - - g_assert_not_reached (); -} - -static void -set_bands_2g (GTask *task, - GArray *bands_array) -{ - MMBroadbandModemCinterion *self; - GError *error = NULL; - guint band[MM_CINTERION_RB_BLOCK_N] = { 0 }; - g_autofree gchar *cmd = NULL; - g_autofree gchar *bandstr = NULL; - g_autofree gchar *bandstr_enc = NULL; - - self = g_task_get_source_object (task); - - if (!mm_cinterion_build_band (bands_array, - self->priv->supported_bands, - TRUE, /* 2G only */ - MM_CINTERION_RADIO_BAND_FORMAT_SINGLE, - 0, - band, - &error)) { - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - /* Build string with the value, in the proper charset */ - bandstr = g_strdup_printf ("%u", band[MM_CINTERION_RB_BLOCK_LEGACY]); - bandstr_enc = mm_modem_charset_str_from_utf8 (bandstr, - mm_broadband_modem_get_current_charset (MM_BROADBAND_MODEM (self)), - FALSE, - &error); - if (!bandstr_enc) { - g_prefix_error (&error, "Couldn't convert band string to current charset: "); - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - /* Following the setup: - * AT^SCFG="Radion/Band",<rbp>,<rba> - * We will set the preferred band equal to the allowed band, so that we force - * the modem to connect at that specific frequency only. Note that we will be - * passing double-quote enclosed strings here! - */ - cmd = g_strdup_printf ("^SCFG=\"Radio/Band\",\"%s\",\"%s\"", bandstr_enc, bandstr_enc); - mm_base_modem_at_command (MM_BASE_MODEM (self), - cmd, - 15, - FALSE, - (GAsyncReadyCallback)scfg_set_ready, - task); -} - -static void -set_current_bands (MMIfaceModem *self, - GArray *bands_array, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GTask *task; - - /* The bands that we get here are previously validated by the interface, and - * that means that ALL the bands given here were also given in the list of - * supported bands. BUT BUT, that doesn't mean that the exact list of bands - * will end up being valid, as not all combinations are possible. E.g, - * Cinterion modems supporting only 2G have specific combinations allowed. - */ - task = g_task_new (self, NULL, callback, user_data); - if (mm_iface_modem_is_3g (self)) - set_bands_3g (task, bands_array); - else - set_bands_2g (task, bands_array); -} - -/*****************************************************************************/ -/* Flow control */ - -static gboolean -setup_flow_control_finish (MMIfaceModem *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -setup_flow_control_ready (MMBaseModem *self, - GAsyncResult *res, - GTask *task) -{ - GError *error = NULL; - - if (!mm_base_modem_at_command_finish (self, res, &error)) - /* Let the error be critical. We DO need RTS/CTS in order to have - * proper modem disabling. */ - g_task_return_error (task, error); - else - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -static void -setup_flow_control (MMIfaceModem *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GTask *task; - - task = g_task_new (self, NULL, callback, user_data); - - /* We need to enable RTS/CTS so that CYCLIC SLEEP mode works */ - g_object_set (self, MM_BROADBAND_MODEM_FLOW_CONTROL, MM_FLOW_CONTROL_RTS_CTS, NULL); - mm_base_modem_at_command (MM_BASE_MODEM (self), - "\\Q3", - 3, - FALSE, - (GAsyncReadyCallback)setup_flow_control_ready, - task); -} - -/*****************************************************************************/ -/* Load unlock retries (Modem interface) */ - -typedef struct { - MMUnlockRetries *retries; - guint i; -} LoadUnlockRetriesContext; - -typedef struct { - MMModemLock lock; - const gchar *command; -} UnlockRetriesMap; - -static const UnlockRetriesMap unlock_retries_map [] = { - { MM_MODEM_LOCK_SIM_PIN, "^SPIC=\"SC\"" }, - { MM_MODEM_LOCK_SIM_PUK, "^SPIC=\"SC\",1" }, - { MM_MODEM_LOCK_SIM_PIN2, "^SPIC=\"P2\"" }, - { MM_MODEM_LOCK_SIM_PUK2, "^SPIC=\"P2\",1" }, - { MM_MODEM_LOCK_PH_FSIM_PIN, "^SPIC=\"PS\"" }, - { MM_MODEM_LOCK_PH_FSIM_PUK, "^SPIC=\"PS\",1" }, - { MM_MODEM_LOCK_PH_NET_PIN, "^SPIC=\"PN\"" }, - { MM_MODEM_LOCK_PH_NET_PUK, "^SPIC=\"PN\",1" }, -}; - -static void -load_unlock_retries_context_free (LoadUnlockRetriesContext *ctx) -{ - g_object_unref (ctx->retries); - g_slice_free (LoadUnlockRetriesContext, ctx); -} - -static MMUnlockRetries * -load_unlock_retries_finish (MMIfaceModem *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_pointer (G_TASK (res), error); -} - -static void load_unlock_retries_context_step (GTask *task); - -static void -spic_ready (MMBaseModem *self, - GAsyncResult *res, - GTask *task) -{ - LoadUnlockRetriesContext *ctx; - const gchar *response; - g_autoptr(GError) error = NULL; - - ctx = g_task_get_task_data (task); - - response = mm_base_modem_at_command_finish (self, res, &error); - if (!response) { - mm_obj_dbg (self, "Couldn't load retry count for lock '%s': %s", - mm_modem_lock_get_string (unlock_retries_map[ctx->i].lock), - error->message); - } else { - guint val; - - response = mm_strip_tag (response, "^SPIC:"); - if (!mm_get_uint_from_str (response, &val)) - mm_obj_dbg (self, "couldn't parse retry count value for lock '%s'", - mm_modem_lock_get_string (unlock_retries_map[ctx->i].lock)); - else - mm_unlock_retries_set (ctx->retries, unlock_retries_map[ctx->i].lock, val); - } - - /* Go to next lock value */ - ctx->i++; - load_unlock_retries_context_step (task); -} - -static void -load_unlock_retries_context_step (GTask *task) -{ - MMBroadbandModemCinterion *self; - LoadUnlockRetriesContext *ctx; - - self = g_task_get_source_object (task); - ctx = g_task_get_task_data (task); - - if (ctx->i == G_N_ELEMENTS (unlock_retries_map)) { - g_task_return_pointer (task, g_object_ref (ctx->retries), g_object_unref); - g_object_unref (task); - return; - } - - mm_base_modem_at_command ( - MM_BASE_MODEM (self), - unlock_retries_map[ctx->i].command, - 3, - FALSE, - (GAsyncReadyCallback)spic_ready, - task); -} - -static void -load_unlock_retries (MMIfaceModem *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GTask *task; - LoadUnlockRetriesContext *ctx; - - task = g_task_new (self, NULL, callback, user_data); - - ctx = g_slice_new0 (LoadUnlockRetriesContext); - ctx->retries = mm_unlock_retries_new (); - ctx->i = 0; - g_task_set_task_data (task, ctx, (GDestroyNotify)load_unlock_retries_context_free); - - load_unlock_retries_context_step (task); -} - -/*****************************************************************************/ -/* After SIM unlock (Modem interface) */ - -#define MAX_AFTER_SIM_UNLOCK_RETRIES 15 - -typedef enum { - CINTERION_SIM_STATUS_REMOVED = 0, - CINTERION_SIM_STATUS_INSERTED = 1, - CINTERION_SIM_STATUS_INIT_COMPLETED = 5, -} CinterionSimStatus; - -typedef struct { - guint retries; - guint timeout_id; -} AfterSimUnlockContext; - -static gboolean -after_sim_unlock_finish (MMIfaceModem *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void after_sim_unlock_context_step (GTask *task); - -static gboolean -simstatus_timeout_cb (GTask *task) -{ - AfterSimUnlockContext *ctx; - - ctx = g_task_get_task_data (task); - ctx->timeout_id = 0; - after_sim_unlock_context_step (task); - return G_SOURCE_REMOVE; -} - -static void -simstatus_check_ready (MMBaseModem *self, - GAsyncResult *res, - GTask *task) -{ - AfterSimUnlockContext *ctx; - const gchar *response; - - response = mm_base_modem_at_command_finish (self, res, NULL); - if (response) { - gchar *descr = NULL; - guint val = 0; - - if (mm_cinterion_parse_sind_response (response, &descr, NULL, &val, NULL) && - g_str_equal (descr, "simstatus") && - val == CINTERION_SIM_STATUS_INIT_COMPLETED) { - /* SIM ready! */ - g_free (descr); - g_task_return_boolean (task, TRUE); - g_object_unref (task); - return; - } - - g_free (descr); - } - - /* Need to retry after 1 sec */ - ctx = g_task_get_task_data (task); - g_assert (ctx->timeout_id == 0); - ctx->timeout_id = g_timeout_add_seconds (1, (GSourceFunc)simstatus_timeout_cb, task); -} - -static void -after_sim_unlock_context_step (GTask *task) -{ - MMBroadbandModemCinterion *self; - AfterSimUnlockContext *ctx; - - self = g_task_get_source_object (task); - ctx = g_task_get_task_data (task); - - /* if not supported or too much wait, skip */ - if (self->priv->sind_simstatus_support != FEATURE_SUPPORTED || ctx->retries == 0) { - g_task_return_boolean (task, TRUE); - g_object_unref (task); - return; - } - - /* Recheck */ - ctx->retries--; - mm_base_modem_at_command (MM_BASE_MODEM (self), - "^SIND=\"simstatus\",2", - 3, - FALSE, - (GAsyncReadyCallback)simstatus_check_ready, - task); -} - -static void -sind_indicators_ready (MMBaseModem *_self, - GAsyncResult *res, - GTask *task) -{ - MMBroadbandModemCinterion *self; - g_autoptr(GError) error = NULL; - const gchar *response; - - self = MM_BROADBAND_MODEM_CINTERION (_self); - if (!(response = mm_base_modem_at_command_finish (_self, res, &error))) { - self->priv->sind_psinfo_support = FEATURE_NOT_SUPPORTED; - mm_obj_dbg (self, "psinfo support? no"); - - self->priv->sind_simstatus_support = FEATURE_NOT_SUPPORTED; - mm_obj_dbg (self, "simstatus support? no"); - - g_task_return_boolean (task, TRUE); - g_object_unref (task); - - return; - } - - if (g_regex_match_simple ("\\(\\s*psinfo\\s*,", response, 0, 0)) - self->priv->sind_psinfo_support = FEATURE_SUPPORTED; - mm_obj_dbg (self, "psinfo support? %s", self->priv->sind_psinfo_support == FEATURE_SUPPORTED ? "yes":"no"); - - if (g_regex_match_simple ("\\(\\s*simstatus\\s*,", response, 0, 0)) - self->priv->sind_simstatus_support = FEATURE_SUPPORTED; - mm_obj_dbg (self, "simstatus support? %s", self->priv->sind_simstatus_support == FEATURE_SUPPORTED ? "yes":"no"); - - after_sim_unlock_context_step (task); -} - -static void -after_sim_unlock (MMIfaceModem *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GTask *task; - AfterSimUnlockContext *ctx; - - task = g_task_new (self, NULL, callback, user_data); - ctx = g_new0 (AfterSimUnlockContext, 1); - ctx->retries = MAX_AFTER_SIM_UNLOCK_RETRIES; - g_task_set_task_data (task, ctx, g_free); - - /* check which indicators are available */ - mm_base_modem_at_command (MM_BASE_MODEM (self), - "AT^SIND=?", - 3, - FALSE, - (GAsyncReadyCallback)sind_indicators_ready, - task); -} - -/*****************************************************************************/ -/* Setup SIM hot swap (Modem interface) */ - -static void -cinterion_scks_unsolicited_handler (MMPortSerialAt *port, - GMatchInfo *match_info, - MMBroadbandModemCinterion *self) -{ - guint scks; - - if (!mm_get_uint_from_match_info (match_info, 1, &scks)) - return; - - switch (scks) { - case 0: - mm_obj_msg (self, "SIM removal detected"); - break; - case 1: - mm_obj_msg (self, "SIM insertion detected"); - break; - case 2: - mm_obj_msg (self, "SIM interface hardware deactivated (potentially non-electrically compatible SIM inserted)"); - break; - case 3: - mm_obj_msg (self, "SIM interface hardware deactivated (technical problem, no precise diagnosis)"); - break; - default: - g_assert_not_reached (); - break; - } - - mm_iface_modem_process_sim_event (MM_IFACE_MODEM (self)); -} - -static gboolean -modem_setup_sim_hot_swap_finish (MMIfaceModem *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -cinterion_hot_swap_init_ready (MMBaseModem *_self, - GAsyncResult *res, - GTask *task) -{ - MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self); - g_autoptr(GError) error = NULL; - MMPortSerialAt *primary; - MMPortSerialAt *secondary; - - if (!mm_base_modem_at_command_finish (_self, res, &error)) { - g_prefix_error (&error, "Could not enable SCKS: "); - g_task_return_error (task, g_steal_pointer (&error)); - g_object_unref (task); - return; - } - - mm_obj_dbg (self, "SIM hot swap detect successfully enabled"); - - primary = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)); - mm_port_serial_at_add_unsolicited_msg_handler ( - primary, - self->priv->scks_regex, - (MMPortSerialAtUnsolicitedMsgFn) cinterion_scks_unsolicited_handler, - self, - NULL); - - secondary = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self)); - if (secondary) - mm_port_serial_at_add_unsolicited_msg_handler ( - secondary, - self->priv->scks_regex, - (MMPortSerialAtUnsolicitedMsgFn) cinterion_scks_unsolicited_handler, - self, - NULL); - - if (!mm_broadband_modem_sim_hot_swap_ports_context_init (MM_BROADBAND_MODEM (self), &error)) - mm_obj_warn (self, "failed to initialize SIM hot swap ports context: %s", error->message); - - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -static void -modem_setup_sim_hot_swap (MMIfaceModem *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GTask *task; - - mm_obj_dbg (self, "Enabling SCKS URCs for SIM hot swap detection"); - - task = g_task_new (self, NULL, callback, user_data); - - mm_base_modem_at_command (MM_BASE_MODEM (self), - "^SCKS=1", - 3, - FALSE, - (GAsyncReadyCallback) cinterion_hot_swap_init_ready, - task); -} - -/*****************************************************************************/ -/* SIM hot swap cleanup (Modem interface) */ - -static void -modem_cleanup_sim_hot_swap (MMIfaceModem *self) -{ - mm_broadband_modem_sim_hot_swap_ports_context_reset (MM_BROADBAND_MODEM (self)); -} - -/*****************************************************************************/ -/* Create Bearer (Modem interface) */ - -static MMBaseBearer * -cinterion_modem_create_bearer_finish (MMIfaceModem *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_pointer (G_TASK (res), error); -} - -static void -broadband_bearer_cinterion_new_ready (GObject *unused, - GAsyncResult *res, - GTask *task) -{ - MMBaseBearer *bearer; - GError *error = NULL; - - bearer = mm_broadband_bearer_cinterion_new_finish (res, &error); - if (!bearer) - g_task_return_error (task, error); - else - g_task_return_pointer (task, bearer, g_object_unref); - g_object_unref (task); -} - -static void -broadband_bearer_new_ready (GObject *unused, - GAsyncResult *res, - GTask *task) -{ - MMBaseBearer *bearer; - GError *error = NULL; - - bearer = mm_broadband_bearer_new_finish (res, &error); - if (!bearer) - g_task_return_error (task, error); - else - g_task_return_pointer (task, bearer, g_object_unref); - g_object_unref (task); -} - -static void -common_create_bearer (GTask *task) -{ - MMBroadbandModemCinterion *self; - - self = g_task_get_source_object (task); - - switch (self->priv->swwan_support) { - case FEATURE_NOT_SUPPORTED: - mm_obj_dbg (self, "^SWWAN not supported, creating default bearer..."); - mm_broadband_bearer_new (MM_BROADBAND_MODEM (self), - g_task_get_task_data (task), - NULL, /* cancellable */ - (GAsyncReadyCallback)broadband_bearer_new_ready, - task); - return; - case FEATURE_SUPPORTED: - mm_obj_dbg (self, "^SWWAN supported, creating cinterion bearer..."); - mm_broadband_bearer_cinterion_new (MM_BROADBAND_MODEM_CINTERION (self), - g_task_get_task_data (task), - NULL, /* cancellable */ - (GAsyncReadyCallback)broadband_bearer_cinterion_new_ready, - task); - return; - case FEATURE_SUPPORT_UNKNOWN: - default: - g_assert_not_reached (); - } -} - -static void -swwan_test_ready (MMBaseModem *_self, - GAsyncResult *res, - GTask *task) -{ - MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self); - - /* Fetch the result to the SWWAN test. If no response given (error triggered), - * assume unsupported */ - if (!mm_base_modem_at_command_finish (_self, res, NULL)) { - mm_obj_dbg (self, "SWWAN unsupported"); - self->priv->swwan_support = FEATURE_NOT_SUPPORTED; - } else { - mm_obj_dbg (self, "SWWAN supported"); - self->priv->swwan_support = FEATURE_SUPPORTED; - } - - /* Go on and create the bearer */ - common_create_bearer (task); -} - -static void -cinterion_modem_create_bearer (MMIfaceModem *_self, - MMBearerProperties *properties, - GAsyncReadyCallback callback, - gpointer user_data) -{ - MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self); - GTask *task; - - task = g_task_new (self, NULL, callback, user_data); - g_task_set_task_data (task, g_object_ref (properties), g_object_unref); - - /* Newer Cinterion modems may support SWWAN, which is the same as WWAN. - * Check to see if current modem supports it.*/ - if (self->priv->swwan_support != FEATURE_SUPPORT_UNKNOWN) { - common_create_bearer (task); - return; - } - - /* If we don't have a data port, don't even bother checking for ^SWWAN - * support. */ - if (!mm_base_modem_peek_best_data_port (MM_BASE_MODEM (self), MM_PORT_TYPE_NET)) { - mm_obj_dbg (self, "skipping ^SWWAN check as no data port is available"); - self->priv->swwan_support = FEATURE_NOT_SUPPORTED; - common_create_bearer (task); - return; - } - - mm_obj_dbg (self, "checking ^SWWAN support..."); - mm_base_modem_at_command (MM_BASE_MODEM (self), - "^SWWAN=?", - 6, - TRUE, /* may be cached */ - (GAsyncReadyCallback) swwan_test_ready, - task); -} - -/*****************************************************************************/ - -static void -setup_ports (MMBroadbandModem *_self) -{ - MMBroadbandModemCinterion *self = (MM_BROADBAND_MODEM_CINTERION (_self)); - MMPortSerialAt *ports[2]; - guint i; - - /* Call parent's setup ports first always */ - MM_BROADBAND_MODEM_CLASS (mm_broadband_modem_cinterion_parent_class)->setup_ports (_self); - - ports[0] = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)); - ports[1] = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self)); - - for (i = 0; i < G_N_ELEMENTS (ports); i++) { - if (!ports[i]) - continue; - mm_port_serial_at_add_unsolicited_msg_handler ( - ports[i], - self->priv->sysstart_regex, - NULL, NULL, NULL); - mm_port_serial_at_add_unsolicited_msg_handler ( - ports[i], - self->priv->scks_regex, - NULL, NULL, NULL); - } -} - -/*****************************************************************************/ - -MMBroadbandModemCinterion * -mm_broadband_modem_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_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, - /* Generic bearer (TTY) or Cinterion bearer (NET) supported */ - MM_BASE_MODEM_DATA_NET_SUPPORTED, TRUE, - MM_BASE_MODEM_DATA_TTY_SUPPORTED, TRUE, - MM_IFACE_MODEM_SIM_HOT_SWAP_SUPPORTED, TRUE, - NULL); -} - -static void -mm_broadband_modem_cinterion_init (MMBroadbandModemCinterion *self) -{ - /* Initialize private data */ - self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self), - MM_TYPE_BROADBAND_MODEM_CINTERION, - MMBroadbandModemCinterionPrivate); - - /* Initialize private variables */ - self->priv->initial_eps_bearer_cid = -1; - self->priv->sind_psinfo_support = FEATURE_SUPPORT_UNKNOWN; - self->priv->swwan_support = FEATURE_SUPPORT_UNKNOWN; - self->priv->smoni_support = FEATURE_SUPPORT_UNKNOWN; - self->priv->sind_simstatus_support = FEATURE_SUPPORT_UNKNOWN; - self->priv->sxrat_support = FEATURE_SUPPORT_UNKNOWN; - - self->priv->ciev_regex = g_regex_new ("\\r\\n\\+CIEV:\\s*([a-z]+),(\\d+)\\r\\n", - G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - self->priv->sysstart_regex = g_regex_new ("\\r\\n\\^SYSSTART.*\\r\\n", - G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - self->priv->scks_regex = g_regex_new ("\\^SCKS:\\s*([0-3])\\r\\n", - G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); - - self->priv->any_allowed = MM_MODEM_MODE_NONE; -} - -static void -finalize (GObject *object) -{ - MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (object); - - g_free (self->priv->sleep_mode_cmd); - - if (self->priv->cnmi_supported_mode) - g_array_unref (self->priv->cnmi_supported_mode); - if (self->priv->cnmi_supported_mt) - g_array_unref (self->priv->cnmi_supported_mt); - if (self->priv->cnmi_supported_bm) - g_array_unref (self->priv->cnmi_supported_bm); - if (self->priv->cnmi_supported_ds) - g_array_unref (self->priv->cnmi_supported_ds); - if (self->priv->cnmi_supported_bfr) - g_array_unref (self->priv->cnmi_supported_bfr); - if (self->priv->sxrat_supported_rat) - g_array_unref (self->priv->sxrat_supported_rat); - if (self->priv->sxrat_supported_pref1) - g_array_unref (self->priv->sxrat_supported_pref1); - - g_regex_unref (self->priv->ciev_regex); - g_regex_unref (self->priv->sysstart_regex); - g_regex_unref (self->priv->scks_regex); - - G_OBJECT_CLASS (mm_broadband_modem_cinterion_parent_class)->finalize (object); -} - -static void -iface_modem_init (MMIfaceModem *iface) -{ - iface_modem_parent = g_type_interface_peek_parent (iface); - - iface->create_bearer = cinterion_modem_create_bearer; - iface->create_bearer_finish = cinterion_modem_create_bearer_finish; - iface->load_supported_modes = load_supported_modes; - iface->load_supported_modes_finish = load_supported_modes_finish; - iface->set_current_modes = set_current_modes; - iface->set_current_modes_finish = set_current_modes_finish; - iface->load_supported_bands = load_supported_bands; - iface->load_supported_bands_finish = load_supported_bands_finish; - iface->load_current_bands = load_current_bands; - iface->load_current_bands_finish = load_current_bands_finish; - iface->set_current_bands = set_current_bands; - iface->set_current_bands_finish = set_current_bands_finish; - iface->load_access_technologies = load_access_technologies; - iface->load_access_technologies_finish = load_access_technologies_finish; - iface->setup_flow_control = setup_flow_control; - iface->setup_flow_control_finish = setup_flow_control_finish; - iface->modem_after_sim_unlock = after_sim_unlock; - iface->modem_after_sim_unlock_finish = after_sim_unlock_finish; - iface->load_unlock_retries = load_unlock_retries; - iface->load_unlock_retries_finish = load_unlock_retries_finish; - iface->reset = mm_shared_cinterion_modem_reset; - iface->reset_finish = mm_shared_cinterion_modem_reset_finish; - iface->modem_power_down = modem_power_down; - iface->modem_power_down_finish = modem_power_down_finish; - iface->modem_power_off = modem_power_off; - iface->modem_power_off_finish = modem_power_off_finish; - iface->setup_sim_hot_swap = modem_setup_sim_hot_swap; - iface->setup_sim_hot_swap_finish = modem_setup_sim_hot_swap_finish; - iface->cleanup_sim_hot_swap = modem_cleanup_sim_hot_swap; -} - -static MMIfaceModem * -peek_parent_interface (MMSharedCinterion *self) -{ - return iface_modem_parent; -} - -static void -iface_modem_3gpp_init (MMIfaceModem3gpp *iface) -{ - iface_modem_3gpp_parent = g_type_interface_peek_parent (iface); - - iface->enable_unsolicited_events = modem_3gpp_enable_unsolicited_events; - iface->enable_unsolicited_events_finish = modem_3gpp_enable_unsolicited_events_finish; - iface->disable_unsolicited_events = modem_3gpp_disable_unsolicited_events; - iface->disable_unsolicited_events_finish = modem_3gpp_disable_unsolicited_events_finish; - - iface->setup_unsolicited_events = modem_3gpp_setup_unsolicited_events; - iface->setup_unsolicited_events_finish = modem_3gpp_setup_cleanup_unsolicited_events_finish; - iface->cleanup_unsolicited_events = modem_3gpp_cleanup_unsolicited_events; - iface->cleanup_unsolicited_events_finish = modem_3gpp_setup_cleanup_unsolicited_events_finish; - - iface->load_initial_eps_bearer = modem_3gpp_load_initial_eps_bearer; - iface->load_initial_eps_bearer_finish = modem_3gpp_load_initial_eps_bearer_finish; - iface->load_initial_eps_bearer_settings = modem_3gpp_load_initial_eps_bearer_settings; - iface->load_initial_eps_bearer_settings_finish = modem_3gpp_load_initial_eps_bearer_settings_finish; - iface->set_initial_eps_bearer_settings = modem_3gpp_set_initial_eps_bearer_settings; - iface->set_initial_eps_bearer_settings_finish = modem_3gpp_set_initial_eps_bearer_settings_finish; - -} - -static void -iface_modem_messaging_init (MMIfaceModemMessaging *iface) -{ - iface->check_support = messaging_check_support; - iface->check_support_finish = messaging_check_support_finish; - iface->enable_unsolicited_events = messaging_enable_unsolicited_events; - iface->enable_unsolicited_events_finish = messaging_enable_unsolicited_events_finish; -} - -static void -iface_modem_location_init (MMIfaceModemLocation *iface) -{ - iface_modem_location_parent = g_type_interface_peek_parent (iface); - - iface->load_capabilities = mm_shared_cinterion_location_load_capabilities; - iface->load_capabilities_finish = mm_shared_cinterion_location_load_capabilities_finish; - iface->enable_location_gathering = mm_shared_cinterion_enable_location_gathering; - iface->enable_location_gathering_finish = mm_shared_cinterion_enable_location_gathering_finish; - iface->disable_location_gathering = mm_shared_cinterion_disable_location_gathering; - iface->disable_location_gathering_finish = mm_shared_cinterion_disable_location_gathering_finish; -} - -static MMIfaceModemLocation * -peek_parent_location_interface (MMSharedCinterion *self) -{ - return iface_modem_location_parent; -} - -static void -iface_modem_voice_init (MMIfaceModemVoice *iface) -{ - iface_modem_voice_parent = g_type_interface_peek_parent (iface); - - iface->create_call = mm_shared_cinterion_create_call; - - iface->check_support = mm_shared_cinterion_voice_check_support; - iface->check_support_finish = mm_shared_cinterion_voice_check_support_finish; - iface->enable_unsolicited_events = mm_shared_cinterion_voice_enable_unsolicited_events; - iface->enable_unsolicited_events_finish = mm_shared_cinterion_voice_enable_unsolicited_events_finish; - iface->disable_unsolicited_events = mm_shared_cinterion_voice_disable_unsolicited_events; - iface->disable_unsolicited_events_finish = mm_shared_cinterion_voice_disable_unsolicited_events_finish; - iface->setup_unsolicited_events = mm_shared_cinterion_voice_setup_unsolicited_events; - iface->setup_unsolicited_events_finish = mm_shared_cinterion_voice_setup_unsolicited_events_finish; - iface->cleanup_unsolicited_events = mm_shared_cinterion_voice_cleanup_unsolicited_events; - iface->cleanup_unsolicited_events_finish = mm_shared_cinterion_voice_cleanup_unsolicited_events_finish; -} - -static MMIfaceModemVoice * -peek_parent_voice_interface (MMSharedCinterion *self) -{ - return iface_modem_voice_parent; -} - -static void -iface_modem_time_init (MMIfaceModemTime *iface) -{ - iface_modem_time_parent = g_type_interface_peek_parent (iface); - - iface->setup_unsolicited_events = mm_shared_cinterion_time_setup_unsolicited_events; - iface->setup_unsolicited_events_finish = mm_shared_cinterion_time_setup_unsolicited_events_finish; - iface->cleanup_unsolicited_events = mm_shared_cinterion_time_cleanup_unsolicited_events; - iface->cleanup_unsolicited_events_finish = mm_shared_cinterion_time_cleanup_unsolicited_events_finish; -} - -static MMIfaceModemTime * -peek_parent_time_interface (MMSharedCinterion *self) -{ - return iface_modem_time_parent; -} - -static void -shared_cinterion_init (MMSharedCinterion *iface) -{ - iface->peek_parent_interface = peek_parent_interface; - iface->peek_parent_location_interface = peek_parent_location_interface; - iface->peek_parent_voice_interface = peek_parent_voice_interface; - iface->peek_parent_time_interface = peek_parent_time_interface; -} - -static void -iface_modem_signal_init (MMIfaceModemSignal *iface) -{ - iface_modem_signal_parent = g_type_interface_peek_parent (iface); - - iface->check_support = signal_check_support; - iface->check_support_finish = signal_check_support_finish; - iface->load_values = signal_load_values; - iface->load_values_finish = signal_load_values_finish; -} - -static void -mm_broadband_modem_cinterion_class_init (MMBroadbandModemCinterionClass *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 (MMBroadbandModemCinterionPrivate)); - - /* Virtual methods */ - object_class->finalize = finalize; - broadband_modem_class->setup_ports = setup_ports; -} diff --git a/plugins/cinterion/mm-broadband-modem-cinterion.h b/plugins/cinterion/mm-broadband-modem-cinterion.h deleted file mode 100644 index 555ee084..00000000 --- a/plugins/cinterion/mm-broadband-modem-cinterion.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -*- 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) 2011 Ammonit Measurement GmbH - * Copyright (C) 2011 Google Inc. - * Author: Aleksander Morgado <aleksander@lanedo.com> - */ - -#ifndef MM_BROADBAND_MODEM_CINTERION_H -#define MM_BROADBAND_MODEM_CINTERION_H - -#include "mm-broadband-modem.h" -#include "mm-modem-helpers-cinterion.h" - -#define MM_TYPE_BROADBAND_MODEM_CINTERION (mm_broadband_modem_cinterion_get_type ()) -#define MM_BROADBAND_MODEM_CINTERION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_MODEM_CINTERION, MMBroadbandModemCinterion)) -#define MM_BROADBAND_MODEM_CINTERION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_MODEM_CINTERION, MMBroadbandModemCinterionClass)) -#define MM_IS_BROADBAND_MODEM_CINTERION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_MODEM_CINTERION)) -#define MM_IS_BROADBAND_MODEM_CINTERION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_MODEM_CINTERION)) -#define MM_BROADBAND_MODEM_CINTERION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_MODEM_CINTERION, MMBroadbandModemCinterionClass)) - -typedef struct _MMBroadbandModemCinterion MMBroadbandModemCinterion; -typedef struct _MMBroadbandModemCinterionClass MMBroadbandModemCinterionClass; -typedef struct _MMBroadbandModemCinterionPrivate MMBroadbandModemCinterionPrivate; - -struct _MMBroadbandModemCinterion { - MMBroadbandModem parent; - MMBroadbandModemCinterionPrivate *priv; -}; - -struct _MMBroadbandModemCinterionClass{ - MMBroadbandModemClass parent; -}; - -GType mm_broadband_modem_cinterion_get_type (void); - -MMBroadbandModemCinterion *mm_broadband_modem_cinterion_new (const gchar *device, - const gchar **drivers, - const gchar *plugin, - guint16 vendor_id, - guint16 product_id); - -MMCinterionModemFamily mm_broadband_modem_cinterion_get_family (MMBroadbandModemCinterion * modem); - -#endif /* MM_BROADBAND_MODEM_CINTERION_H */ diff --git a/plugins/cinterion/mm-broadband-modem-mbim-cinterion.c b/plugins/cinterion/mm-broadband-modem-mbim-cinterion.c deleted file mode 100644 index 740909b1..00000000 --- a/plugins/cinterion/mm-broadband-modem-mbim-cinterion.c +++ /dev/null @@ -1,167 +0,0 @@ -/* -*- 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) 2021 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.h" -#include "mm-iface-modem-location.h" -#include "mm-iface-modem-voice.h" -#include "mm-broadband-modem-mbim-cinterion.h" -#include "mm-shared-cinterion.h" - -static void iface_modem_init (MMIfaceModem *iface); -static void iface_modem_location_init (MMIfaceModemLocation *iface); -static void iface_modem_voice_init (MMIfaceModemVoice *iface); -static void iface_modem_time_init (MMIfaceModemTime *iface); -static void shared_cinterion_init (MMSharedCinterion *iface); - -static MMIfaceModem *iface_modem_parent; -static MMIfaceModemLocation *iface_modem_location_parent; -static MMIfaceModemVoice *iface_modem_voice_parent; -static MMIfaceModemTime *iface_modem_time_parent; - -G_DEFINE_TYPE_EXTENDED (MMBroadbandModemMbimCinterion, mm_broadband_modem_mbim_cinterion, MM_TYPE_BROADBAND_MODEM_MBIM, 0, - G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init) - G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init) - G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_VOICE, iface_modem_voice_init) - G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_TIME, iface_modem_time_init) - G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_CINTERION, shared_cinterion_init)) - -/*****************************************************************************/ - -MMBroadbandModemMbimCinterion * -mm_broadband_modem_mbim_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_MBIM_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, - /* MBIM bearer supports NET only */ - MM_BASE_MODEM_DATA_NET_SUPPORTED, TRUE, - MM_BASE_MODEM_DATA_TTY_SUPPORTED, FALSE, - MM_IFACE_MODEM_SIM_HOT_SWAP_SUPPORTED, TRUE, - MM_BROADBAND_MODEM_MBIM_INTEL_FIRMWARE_UPDATE_UNSUPPORTED, TRUE, - NULL); -} - -static void -mm_broadband_modem_mbim_cinterion_init (MMBroadbandModemMbimCinterion *self) -{ -} - -static void -iface_modem_init (MMIfaceModem *iface) -{ - iface_modem_parent = g_type_interface_peek_parent (iface); - - iface->reset = mm_shared_cinterion_modem_reset; - iface->reset_finish = mm_shared_cinterion_modem_reset_finish; -} - -static MMIfaceModem * -peek_parent_interface (MMSharedCinterion *self) -{ - return iface_modem_parent; -} - -static void -iface_modem_location_init (MMIfaceModemLocation *iface) -{ - iface_modem_location_parent = g_type_interface_peek_parent (iface); - - iface->load_capabilities = mm_shared_cinterion_location_load_capabilities; - iface->load_capabilities_finish = mm_shared_cinterion_location_load_capabilities_finish; - iface->enable_location_gathering = mm_shared_cinterion_enable_location_gathering; - iface->enable_location_gathering_finish = mm_shared_cinterion_enable_location_gathering_finish; - iface->disable_location_gathering = mm_shared_cinterion_disable_location_gathering; - iface->disable_location_gathering_finish = mm_shared_cinterion_disable_location_gathering_finish; -} - -static MMIfaceModemLocation * -peek_parent_location_interface (MMSharedCinterion *self) -{ - return iface_modem_location_parent; -} - -static void -iface_modem_voice_init (MMIfaceModemVoice *iface) -{ - iface_modem_voice_parent = g_type_interface_peek_parent (iface); - - iface->create_call = mm_shared_cinterion_create_call; - - iface->check_support = mm_shared_cinterion_voice_check_support; - iface->check_support_finish = mm_shared_cinterion_voice_check_support_finish; - iface->enable_unsolicited_events = mm_shared_cinterion_voice_enable_unsolicited_events; - iface->enable_unsolicited_events_finish = mm_shared_cinterion_voice_enable_unsolicited_events_finish; - iface->disable_unsolicited_events = mm_shared_cinterion_voice_disable_unsolicited_events; - iface->disable_unsolicited_events_finish = mm_shared_cinterion_voice_disable_unsolicited_events_finish; - iface->setup_unsolicited_events = mm_shared_cinterion_voice_setup_unsolicited_events; - iface->setup_unsolicited_events_finish = mm_shared_cinterion_voice_setup_unsolicited_events_finish; - iface->cleanup_unsolicited_events = mm_shared_cinterion_voice_cleanup_unsolicited_events; - iface->cleanup_unsolicited_events_finish = mm_shared_cinterion_voice_cleanup_unsolicited_events_finish; -} - -static MMIfaceModemVoice * -peek_parent_voice_interface (MMSharedCinterion *self) -{ - return iface_modem_voice_parent; -} - -static void -iface_modem_time_init (MMIfaceModemTime *iface) -{ - iface_modem_time_parent = g_type_interface_peek_parent (iface); - - iface->setup_unsolicited_events = mm_shared_cinterion_time_setup_unsolicited_events; - iface->setup_unsolicited_events_finish = mm_shared_cinterion_time_setup_unsolicited_events_finish; - iface->cleanup_unsolicited_events = mm_shared_cinterion_time_cleanup_unsolicited_events; - iface->cleanup_unsolicited_events_finish = mm_shared_cinterion_time_cleanup_unsolicited_events_finish; -} - -static MMIfaceModemTime * -peek_parent_time_interface (MMSharedCinterion *self) -{ - return iface_modem_time_parent; -} - -static void -shared_cinterion_init (MMSharedCinterion *iface) -{ - iface->peek_parent_interface = peek_parent_interface; - iface->peek_parent_location_interface = peek_parent_location_interface; - iface->peek_parent_voice_interface = peek_parent_voice_interface; - iface->peek_parent_time_interface = peek_parent_time_interface; -} - -static void -mm_broadband_modem_mbim_cinterion_class_init (MMBroadbandModemMbimCinterionClass *klass) -{ -} diff --git a/plugins/cinterion/mm-broadband-modem-mbim-cinterion.h b/plugins/cinterion/mm-broadband-modem-mbim-cinterion.h deleted file mode 100644 index a2f2ef68..00000000 --- a/plugins/cinterion/mm-broadband-modem-mbim-cinterion.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -*- 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) 2021 Aleksander Morgado <aleksander@aleksander.es> - */ - -#ifndef MM_BROADBAND_MODEM_MBIM_CINTERION_MBIM_H -#define MM_BROADBAND_MODEM_MBIM_CINTERION_MBIM_H - -#include "mm-broadband-modem-mbim.h" - -#define MM_TYPE_BROADBAND_MODEM_MBIM_CINTERION (mm_broadband_modem_mbim_cinterion_get_type ()) -#define MM_BROADBAND_MODEM_MBIM_CINTERION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_BROADBAND_MODEM_MBIM_CINTERION, MMBroadbandModemMbimCinterion)) -#define MM_BROADBAND_MODEM_MBIM_CINTERION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_BROADBAND_MODEM_MBIM_CINTERION, MMBroadbandModemMbimCinterionClass)) -#define MM_IS_BROADBAND_MODEM_MBIM_CINTERION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_BROADBAND_MODEM_MBIM_CINTERION)) -#define MM_IS_BROADBAND_MODEM_MBIM_CINTERION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_BROADBAND_MODEM_MBIM_CINTERION)) -#define MM_BROADBAND_MODEM_MBIM_CINTERION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_BROADBAND_MODEM_MBIM_CINTERION, MMBroadbandModemMbimCinterionClass)) - -typedef struct _MMBroadbandModemMbimCinterion MMBroadbandModemMbimCinterion; -typedef struct _MMBroadbandModemMbimCinterionClass MMBroadbandModemMbimCinterionClass; - -struct _MMBroadbandModemMbimCinterion { - MMBroadbandModemMbim parent; -}; - -struct _MMBroadbandModemMbimCinterionClass{ - MMBroadbandModemMbimClass parent; -}; - -GType mm_broadband_modem_mbim_cinterion_get_type (void); - -MMBroadbandModemMbimCinterion *mm_broadband_modem_mbim_cinterion_new (const gchar *device, - const gchar **drivers, - const gchar *plugin, - guint16 vendor_id, - guint16 product_id); - -#endif /* MM_BROADBAND_MODEM_MBIM_CINTERION_H */ diff --git a/plugins/cinterion/mm-broadband-modem-qmi-cinterion.c b/plugins/cinterion/mm-broadband-modem-qmi-cinterion.c deleted file mode 100644 index b94e63d3..00000000 --- a/plugins/cinterion/mm-broadband-modem-qmi-cinterion.c +++ /dev/null @@ -1,167 +0,0 @@ -/* -*- 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.h" -#include "mm-iface-modem-location.h" -#include "mm-iface-modem-voice.h" -#include "mm-broadband-modem-qmi-cinterion.h" -#include "mm-shared-cinterion.h" - -static void iface_modem_init (MMIfaceModem *iface); -static void iface_modem_location_init (MMIfaceModemLocation *iface); -static void iface_modem_voice_init (MMIfaceModemVoice *iface); -static void iface_modem_time_init (MMIfaceModemTime *iface); -static void shared_cinterion_init (MMSharedCinterion *iface); - -static MMIfaceModem *iface_modem_parent; -static MMIfaceModemLocation *iface_modem_location_parent; -static MMIfaceModemVoice *iface_modem_voice_parent; -static MMIfaceModemTime *iface_modem_time_parent; - -G_DEFINE_TYPE_EXTENDED (MMBroadbandModemQmiCinterion, mm_broadband_modem_qmi_cinterion, MM_TYPE_BROADBAND_MODEM_QMI, 0, - G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init) - G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init) - G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_VOICE, iface_modem_voice_init) - G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_TIME, iface_modem_time_init) - G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_CINTERION, shared_cinterion_init)) - -/*****************************************************************************/ - -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, - /* QMI bearer supports NET only */ - MM_BASE_MODEM_DATA_NET_SUPPORTED, TRUE, - MM_BASE_MODEM_DATA_TTY_SUPPORTED, FALSE, - MM_IFACE_MODEM_SIM_HOT_SWAP_SUPPORTED, TRUE, - NULL); -} - -static void -mm_broadband_modem_qmi_cinterion_init (MMBroadbandModemQmiCinterion *self) -{ -} - -static void -iface_modem_init (MMIfaceModem *iface) -{ - iface_modem_parent = g_type_interface_peek_parent (iface); - - iface->reset = mm_shared_cinterion_modem_reset; - iface->reset_finish = mm_shared_cinterion_modem_reset_finish; -} - -static MMIfaceModem * -peek_parent_interface (MMSharedCinterion *self) -{ - return iface_modem_parent; -} - -static void -iface_modem_location_init (MMIfaceModemLocation *iface) -{ - iface_modem_location_parent = g_type_interface_peek_parent (iface); - - iface->load_capabilities = mm_shared_cinterion_location_load_capabilities; - iface->load_capabilities_finish = mm_shared_cinterion_location_load_capabilities_finish; - iface->enable_location_gathering = mm_shared_cinterion_enable_location_gathering; - iface->enable_location_gathering_finish = mm_shared_cinterion_enable_location_gathering_finish; - iface->disable_location_gathering = mm_shared_cinterion_disable_location_gathering; - iface->disable_location_gathering_finish = mm_shared_cinterion_disable_location_gathering_finish; -} - -static MMIfaceModemLocation * -peek_parent_location_interface (MMSharedCinterion *self) -{ - return iface_modem_location_parent; -} - -static void -iface_modem_voice_init (MMIfaceModemVoice *iface) -{ - iface_modem_voice_parent = g_type_interface_peek_parent (iface); - - iface->create_call = mm_shared_cinterion_create_call; - - iface->check_support = mm_shared_cinterion_voice_check_support; - iface->check_support_finish = mm_shared_cinterion_voice_check_support_finish; - iface->enable_unsolicited_events = mm_shared_cinterion_voice_enable_unsolicited_events; - iface->enable_unsolicited_events_finish = mm_shared_cinterion_voice_enable_unsolicited_events_finish; - iface->disable_unsolicited_events = mm_shared_cinterion_voice_disable_unsolicited_events; - iface->disable_unsolicited_events_finish = mm_shared_cinterion_voice_disable_unsolicited_events_finish; - iface->setup_unsolicited_events = mm_shared_cinterion_voice_setup_unsolicited_events; - iface->setup_unsolicited_events_finish = mm_shared_cinterion_voice_setup_unsolicited_events_finish; - iface->cleanup_unsolicited_events = mm_shared_cinterion_voice_cleanup_unsolicited_events; - iface->cleanup_unsolicited_events_finish = mm_shared_cinterion_voice_cleanup_unsolicited_events_finish; -} - -static MMIfaceModemVoice * -peek_parent_voice_interface (MMSharedCinterion *self) -{ - return iface_modem_voice_parent; -} - -static void -iface_modem_time_init (MMIfaceModemTime *iface) -{ - iface_modem_time_parent = g_type_interface_peek_parent (iface); - - iface->setup_unsolicited_events = mm_shared_cinterion_time_setup_unsolicited_events; - iface->setup_unsolicited_events_finish = mm_shared_cinterion_time_setup_unsolicited_events_finish; - iface->cleanup_unsolicited_events = mm_shared_cinterion_time_cleanup_unsolicited_events; - iface->cleanup_unsolicited_events_finish = mm_shared_cinterion_time_cleanup_unsolicited_events_finish; -} - -static MMIfaceModemTime * -peek_parent_time_interface (MMSharedCinterion *self) -{ - return iface_modem_time_parent; -} - -static void -shared_cinterion_init (MMSharedCinterion *iface) -{ - iface->peek_parent_interface = peek_parent_interface; - iface->peek_parent_location_interface = peek_parent_location_interface; - iface->peek_parent_voice_interface = peek_parent_voice_interface; - iface->peek_parent_time_interface = peek_parent_time_interface; -} - -static void -mm_broadband_modem_qmi_cinterion_class_init (MMBroadbandModemQmiCinterionClass *klass) -{ -} diff --git a/plugins/cinterion/mm-broadband-modem-qmi-cinterion.h b/plugins/cinterion/mm-broadband-modem-qmi-cinterion.h deleted file mode 100644 index ac8f68be..00000000 --- a/plugins/cinterion/mm-broadband-modem-qmi-cinterion.h +++ /dev/null @@ -1,48 +0,0 @@ -/* -*- 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-modem-helpers-cinterion.c b/plugins/cinterion/mm-modem-helpers-cinterion.c deleted file mode 100644 index f22a998c..00000000 --- a/plugins/cinterion/mm-modem-helpers-cinterion.c +++ /dev/null @@ -1,1804 +0,0 @@ -/* -*- 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 Aleksander Morgado <aleksander@aleksander.es> - * Copyright (C) 2016 Trimble Navigation Limited - * Copyright (C) 2016 Matthew Stanger <matthew_stanger@trimble.com> - * Copyright (C) 2019 Purism SPC - */ - -#include <config.h> -#include <string.h> -#include <stdlib.h> -#include <stdio.h> - -#include "ModemManager.h" -#define _LIBMM_INSIDE_MM -#include <libmm-glib.h> -#include "mm-log-object.h" -#include "mm-charsets.h" -#include "mm-errors-types.h" -#include "mm-modem-helpers-cinterion.h" -#include "mm-modem-helpers.h" -#include "mm-common-helpers.h" -#include "mm-port-serial-at.h" - -/* Setup relationship between the 3G band bitmask in the modem and the bitmask - * in ModemManager. */ -typedef struct { - guint32 cinterion_band_flag; - MMModemBand mm_band; -} CinterionBand; - -typedef struct { - MMCinterionRbBlock cinterion_band_block; - guint32 cinterion_band_flag; - MMModemBand mm_band; -} CinterionBandEx; - -/* Table checked in PLS8-X/E/J/V/US, HC25 & PHS8 references. The table includes 2/3/4G - * frequencies. Depending on which one is configured, one access technology or - * the other will be used. This may conflict with the allowed mode configuration - * set, so you shouldn't for example set 3G frequency bands, and then use a - * 2G-only allowed mode. */ -static const CinterionBand cinterion_bands[] = { - { (1 << 0), MM_MODEM_BAND_EGSM }, - { (1 << 1), MM_MODEM_BAND_DCS }, - { (1 << 2), MM_MODEM_BAND_G850 }, - { (1 << 3), MM_MODEM_BAND_PCS }, - { (1 << 4), MM_MODEM_BAND_UTRAN_1 }, - { (1 << 5), MM_MODEM_BAND_UTRAN_2 }, - { (1 << 6), MM_MODEM_BAND_UTRAN_5 }, - { (1 << 7), MM_MODEM_BAND_UTRAN_8 }, - { (1 << 8), MM_MODEM_BAND_UTRAN_6 }, - { (1 << 9), MM_MODEM_BAND_UTRAN_4 }, - { (1 << 10), MM_MODEM_BAND_UTRAN_19 }, - { (1 << 12), MM_MODEM_BAND_UTRAN_3 }, - { (1 << 13), MM_MODEM_BAND_EUTRAN_1 }, - { (1 << 14), MM_MODEM_BAND_EUTRAN_2 }, - { (1 << 15), MM_MODEM_BAND_EUTRAN_3 }, - { (1 << 16), MM_MODEM_BAND_EUTRAN_4 }, - { (1 << 17), MM_MODEM_BAND_EUTRAN_5 }, - { (1 << 18), MM_MODEM_BAND_EUTRAN_7 }, - { (1 << 19), MM_MODEM_BAND_EUTRAN_8 }, - { (1 << 20), MM_MODEM_BAND_EUTRAN_17 }, - { (1 << 21), MM_MODEM_BAND_EUTRAN_20 }, - { (1 << 22), MM_MODEM_BAND_EUTRAN_13 }, - { (1 << 24), MM_MODEM_BAND_EUTRAN_19 } -}; - -static const CinterionBandEx cinterion_bands_ex[] = { - { MM_CINTERION_RB_BLOCK_GSM, 0x00000001, MM_MODEM_BAND_EGSM }, - { MM_CINTERION_RB_BLOCK_GSM, 0x00000002, MM_MODEM_BAND_DCS }, - { MM_CINTERION_RB_BLOCK_GSM, 0x00000004, MM_MODEM_BAND_G850 }, - { MM_CINTERION_RB_BLOCK_GSM, 0x00000008, MM_MODEM_BAND_PCS }, - { MM_CINTERION_RB_BLOCK_UMTS, 0x00000001, MM_MODEM_BAND_UTRAN_1 }, - { MM_CINTERION_RB_BLOCK_UMTS, 0x00000002, MM_MODEM_BAND_UTRAN_2 }, - { MM_CINTERION_RB_BLOCK_UMTS, 0x00000004, MM_MODEM_BAND_UTRAN_3 }, - { MM_CINTERION_RB_BLOCK_UMTS, 0x00000008, MM_MODEM_BAND_UTRAN_4 }, - { MM_CINTERION_RB_BLOCK_UMTS, 0x00000010, MM_MODEM_BAND_UTRAN_5 }, - { MM_CINTERION_RB_BLOCK_UMTS, 0x00000020, MM_MODEM_BAND_UTRAN_6 }, - { MM_CINTERION_RB_BLOCK_UMTS, 0x00000080, MM_MODEM_BAND_UTRAN_8 }, - { MM_CINTERION_RB_BLOCK_UMTS, 0x00000100, MM_MODEM_BAND_UTRAN_9 }, - { MM_CINTERION_RB_BLOCK_UMTS, 0x00040000, MM_MODEM_BAND_UTRAN_19 }, - { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000001, MM_MODEM_BAND_EUTRAN_1 }, - { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000002, MM_MODEM_BAND_EUTRAN_2 }, - { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000004, MM_MODEM_BAND_EUTRAN_3 }, - { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000008, MM_MODEM_BAND_EUTRAN_4 }, - { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000010, MM_MODEM_BAND_EUTRAN_5 }, - { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000040, MM_MODEM_BAND_EUTRAN_7 }, - { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000080, MM_MODEM_BAND_EUTRAN_8 }, - { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000800, MM_MODEM_BAND_EUTRAN_12 }, - { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00001000, MM_MODEM_BAND_EUTRAN_13 }, - { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00010000, MM_MODEM_BAND_EUTRAN_17 }, - { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00020000, MM_MODEM_BAND_EUTRAN_18 }, - { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00040000, MM_MODEM_BAND_EUTRAN_19 }, - { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00080000, MM_MODEM_BAND_EUTRAN_20 }, - { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x02000000, MM_MODEM_BAND_EUTRAN_26 }, - { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x08000000, MM_MODEM_BAND_EUTRAN_28 }, - { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x10000000, MM_MODEM_BAND_EUTRAN_29 }, - { MM_CINTERION_RB_BLOCK_LTE_HIGH, 0x00000020, MM_MODEM_BAND_EUTRAN_38 }, - { MM_CINTERION_RB_BLOCK_LTE_HIGH, 0x00000040, MM_MODEM_BAND_EUTRAN_39 }, - { MM_CINTERION_RB_BLOCK_LTE_HIGH, 0x00000080, MM_MODEM_BAND_EUTRAN_40 }, - { MM_CINTERION_RB_BLOCK_LTE_HIGH, 0x00000100, MM_MODEM_BAND_EUTRAN_41 } -}; - -static const CinterionBandEx cinterion_bands_imt[] = { - { MM_CINTERION_RB_BLOCK_GSM, 0x00000004, MM_MODEM_BAND_EGSM }, - { MM_CINTERION_RB_BLOCK_GSM, 0x00000010, MM_MODEM_BAND_DCS }, - { MM_CINTERION_RB_BLOCK_GSM, 0x00000020, MM_MODEM_BAND_PCS }, - { MM_CINTERION_RB_BLOCK_GSM, 0x00000040, MM_MODEM_BAND_G850 }, - { MM_CINTERION_RB_BLOCK_UMTS, 0x00000001, MM_MODEM_BAND_UTRAN_1 }, - { MM_CINTERION_RB_BLOCK_UMTS, 0x00000002, MM_MODEM_BAND_UTRAN_2 }, - { MM_CINTERION_RB_BLOCK_UMTS, 0x00000008, MM_MODEM_BAND_UTRAN_4 }, - { MM_CINTERION_RB_BLOCK_UMTS, 0x00000010, MM_MODEM_BAND_UTRAN_5 }, - { MM_CINTERION_RB_BLOCK_UMTS, 0x00000080, MM_MODEM_BAND_UTRAN_8 }, - { MM_CINTERION_RB_BLOCK_UMTS, 0x00000100, MM_MODEM_BAND_UTRAN_9 }, - { MM_CINTERION_RB_BLOCK_UMTS, 0x00040000, MM_MODEM_BAND_UTRAN_19 }, - { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000001, MM_MODEM_BAND_EUTRAN_1 }, - { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000002, MM_MODEM_BAND_EUTRAN_2 }, - { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000004, MM_MODEM_BAND_EUTRAN_3 }, - { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000008, MM_MODEM_BAND_EUTRAN_4 }, - { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000010, MM_MODEM_BAND_EUTRAN_5 }, - { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000040, MM_MODEM_BAND_EUTRAN_7 }, - { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000080, MM_MODEM_BAND_EUTRAN_8 }, - { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00000800, MM_MODEM_BAND_EUTRAN_12 }, - { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00020000, MM_MODEM_BAND_EUTRAN_18 }, - { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00040000, MM_MODEM_BAND_EUTRAN_19 }, - { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x00080000, MM_MODEM_BAND_EUTRAN_20 }, - { MM_CINTERION_RB_BLOCK_LTE_LOW, 0x08000000, MM_MODEM_BAND_EUTRAN_28 } -}; - -/* Check valid combinations in 2G-only devices */ -#define VALIDATE_2G_BAND(cinterion_mask) \ - (cinterion_mask == 1 || \ - cinterion_mask == 2 || \ - cinterion_mask == 4 || \ - cinterion_mask == 8 || \ - cinterion_mask == 3 || \ - cinterion_mask == 5 || \ - cinterion_mask == 10 || \ - cinterion_mask == 12 || \ - cinterion_mask == 15) - -/*****************************************************************************/ -/* ^SCFG (3G+LTE) test parser - * - * Example 3G: - * AT^SCFG=? - * ... - * ^SCFG: "MEShutdown/OnIgnition",("on","off") - * ^SCFG: "Radio/Band",("1-511","0-1") - * ^SCFG: "Radio/NWSM",("0","1","2") - * ... - * ^SCFG: "Radio/Band\",("1"-"147") - * - * Example LTE1 (GSM charset): - * AT^SCFG=? - * ... - * ^SCFG: "Radio/Band/2G",("0x00000004"-"0x00000074") - * ^SCFG: "Radio/Band/3G",("0x00000001"-"0x0004019B") - * ^SCFG: "Radio/Band/4G",("0x00000001"-"0x080E08DF") - * ... - * - * Example LTE1 (UCS2 charset): - * AT^SCFG=? - * ... - * ^SCFG: "Radio/Band/2G",("0030007800300030003000300030003000300034"-"0030007800300030003000300030003000370034") - * ^SCFG: "Radio/Band/3G",("0030007800300030003000300030003000300031"-"0030007800300030003000340030003100390042") - * ^SCFG: "Radio/Band/4G",("0030007800300030003000300030003000300031"-"0030007800300038003000450030003800440046") - * ... - * - * Example LTE2 (all charsets): - * AT^SCFG=? - * ... - * ^SCFG: "Radio/Band/2G",("00000001-0000000f"),,("0","1") - * ^SCFG: "Radio/Band/3G",("00000001-000400b5"),,("0","1") - * ^SCFG: "Radio/Band/4G",("00000001-8a0e00d5"),("00000002-000001e2"),("0","1") - * ... - */ - -static void -parse_bands (guint bandlist, - GArray **bands, - MMCinterionRbBlock block, - MMCinterionModemFamily modem_family) -{ - guint i; - const CinterionBandEx *ref_bands; - guint nb_ref_bands; - - if (!bandlist) - return; - - if (modem_family == MM_CINTERION_MODEM_FAMILY_IMT) { - ref_bands = cinterion_bands_imt; - nb_ref_bands = G_N_ELEMENTS (cinterion_bands_imt); - } else { - ref_bands = cinterion_bands_ex; - nb_ref_bands = G_N_ELEMENTS (cinterion_bands_ex); - } - - for (i = 0; i < nb_ref_bands; i++) { - if (block == ref_bands[i].cinterion_band_block && (bandlist & ref_bands[i].cinterion_band_flag)) { - if (G_UNLIKELY (!*bands)) - *bands = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), 23); - g_array_append_val (*bands, ref_bands[i].mm_band); - } - } -} - -static guint -take_and_convert_from_matched_string (gchar *str, - MMModemCharset charset, - MMCinterionModemFamily modem_family, - GError **error) -{ - guint val = 0; - g_autofree gchar *utf8 = NULL; - g_autofree gchar *taken_str = str; - - if (!taken_str) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, - "Couldn't convert to integer number: no input string"); - return 0; - } - - if (modem_family == MM_CINTERION_MODEM_FAMILY_IMT) { - utf8 = mm_modem_charset_str_to_utf8 (taken_str, -1, charset, FALSE, error); - if (!utf8) { - g_prefix_error (error, "Couldn't convert to integer number: "); - return 0; - } - } - - if (!mm_get_uint_from_hex_str (utf8 ? utf8 : taken_str, &val)) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Couldn't convert to integer number: wrong hex encoding: %s", utf8 ? utf8 : taken_str); - return 0; - } - - return val; -} - -gboolean -mm_cinterion_parse_scfg_test (const gchar *response, - MMCinterionModemFamily modem_family, - MMModemCharset charset, - GArray **supported_bands, - MMCinterionRadioBandFormat *format, - GError **error) -{ - g_autoptr(GRegex) r1 = NULL; - g_autoptr(GMatchInfo) match_info1 = NULL; - g_autoptr(GRegex) r2 = NULL; - g_autoptr(GMatchInfo) match_info2 = NULL; - GError *inner_error = NULL; - GArray *bands = NULL; - - g_assert (format); - - if (!response) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Missing response"); - return FALSE; - } - - r1 = g_regex_new ("\\^SCFG:\\s*\"Radio/Band\",\\((?:\")?([0-9]*)(?:\")?-(?:\")?([0-9]*)(?:\")?.*\\)", - G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW, 0, NULL); - g_assert (r1 != NULL); - - g_regex_match_full (r1, response, strlen (response), 0, 0, &match_info1, &inner_error); - if (inner_error) - goto finish; - if (g_match_info_matches (match_info1)) { - g_autofree gchar *maxbandstr = NULL; - guint maxband = 0; - - *format = MM_CINTERION_RADIO_BAND_FORMAT_SINGLE; - - maxbandstr = mm_get_string_unquoted_from_match_info (match_info1, 2); - if (maxbandstr) - mm_get_uint_from_str (maxbandstr, &maxband); - - if (maxband == 0) { - inner_error = g_error_new (MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Couldn't parse ^SCFG=? response"); - } else { - guint i; - - for (i = 0; i < G_N_ELEMENTS (cinterion_bands); i++) { - if (maxband & cinterion_bands[i].cinterion_band_flag) { - if (G_UNLIKELY (!bands)) - bands = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), 9); - g_array_append_val (bands, cinterion_bands[i].mm_band); - } - } - } - goto finish; - } - - r2 = g_regex_new ("\\^SCFG:\\s*\"Radio/Band/([234]G)\"," - "\\(\"?([0-9A-Fa-fx]*)\"?-\"?([0-9A-Fa-fx]*)\"?\\)" - "(,*\\(\"?([0-9A-Fa-fx]*)\"?-\"?([0-9A-Fa-fx]*)\"?\\))?", - 0, 0, NULL); - g_assert (r2 != NULL); - - g_regex_match_full (r2, response, strlen (response), 0, 0, &match_info2, &inner_error); - if (inner_error) - goto finish; - - while (g_match_info_matches (match_info2)) { - g_autofree gchar *techstr = NULL; - guint maxband; - - *format = MM_CINTERION_RADIO_BAND_FORMAT_MULTIPLE; - - techstr = mm_get_string_unquoted_from_match_info (match_info2, 1); - if (g_strcmp0 (techstr, "2G") == 0) { - maxband = take_and_convert_from_matched_string (mm_get_string_unquoted_from_match_info (match_info2, 3), - charset, modem_family, &inner_error); - if (inner_error) - break; - parse_bands (maxband, &bands, MM_CINTERION_RB_BLOCK_GSM, modem_family); - } else if (g_strcmp0 (techstr, "3G") == 0) { - maxband = take_and_convert_from_matched_string (mm_get_string_unquoted_from_match_info (match_info2, 3), - charset, modem_family, &inner_error); - if (inner_error) - break; - parse_bands (maxband, &bands, MM_CINTERION_RB_BLOCK_UMTS, modem_family); - } else if (g_strcmp0 (techstr, "4G") == 0) { - maxband = take_and_convert_from_matched_string (mm_get_string_unquoted_from_match_info (match_info2, 3), - charset, modem_family, &inner_error); - if (inner_error) - break; - parse_bands (maxband, &bands, MM_CINTERION_RB_BLOCK_LTE_LOW, modem_family); - if (modem_family == MM_CINTERION_MODEM_FAMILY_DEFAULT) { - maxband = take_and_convert_from_matched_string (mm_get_string_unquoted_from_match_info (match_info2, 6), - charset, modem_family, &inner_error); - if (inner_error) - break; - parse_bands (maxband, &bands, MM_CINTERION_RB_BLOCK_LTE_HIGH, modem_family); - } - } else { - inner_error = g_error_new (MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Couldn't parse ^SCFG=? response"); - break; - } - - g_match_info_next (match_info2, NULL); - } - -finish: - /* set error only if not already given */ - if (!bands && !inner_error) - inner_error = g_error_new (MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "No valid bands found in ^SCFG=? response"); - - if (inner_error) { - g_propagate_error (error, inner_error); - return FALSE; - } - - g_assert (bands != NULL && bands->len > 0); - *supported_bands = bands; - - return TRUE; -} - -/*****************************************************************************/ -/* ^SCFG response parser (2 types: 2G/3G and LTE) - * - * Example (3G): - * AT^SCFG="Radio/Band" - * ^SCFG: "Radio/Band",127 - * - * Example (2G, UCS-2): - * AT+SCFG="Radio/Band" - * ^SCFG: "Radio/Band","0031","0031" - * - * Example (2G): - * AT+SCFG="Radio/Band" - * ^SCFG: "Radio/Band","3","3" - * - * Example LTE1 (GSM charset): - * AT^SCFG=? - * ... - * ^SCFG: "Radio/Band/2G","0x00000074" - * ^SCFG: "Radio/Band/3G","0x0004019B" - * ^SCFG: "Radio/Band/4G","0x080E08DF" - * ... - * AT^SCFG=? - * ... - * Example LTE1 (UCS2 charset): - * AT^SCFG=? - * ... - * ^SCFG: "Radio/Band/2G","0030007800300030003000300030003000370034" - * ^SCFG: "Radio/Band/3G","0030007800300030003000340030003100390042" - * ^SCFG: "Radio/Band/4G","0030007800300038003000450030003800440046" - * ... - * Example LTE2 (all charsets): - * AT^SCFG=? - * ... - * ^SCFG: "Radio/Band/2G","0000000f" - * ^SCFG: "Radio/Band/3G","000400b5" - * ^SCFG: "Radio/Band/4G","8a0e00d5","000000e2" - * ... - */ - -gboolean -mm_cinterion_parse_scfg_response (const gchar *response, - MMCinterionModemFamily modem_family, - MMModemCharset charset, - GArray **current_bands, - MMCinterionRadioBandFormat format, - GError **error) -{ - g_autoptr(GRegex) r = NULL; - g_autoptr(GMatchInfo) match_info = NULL; - GError *inner_error = NULL; - GArray *bands = NULL; - - if (!response) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Missing response"); - return FALSE; - } - - if (format == MM_CINTERION_RADIO_BAND_FORMAT_SINGLE) { - r = g_regex_new ("\\^SCFG:\\s*\"Radio/Band\",\\s*\"?([0-9a-fA-F]*)\"?", 0, 0, NULL); - g_assert (r != NULL); - - g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error); - if (inner_error) - goto finish; - - if (g_match_info_matches (match_info)) { - g_autofree gchar *currentstr = NULL; - guint current = 0; - - currentstr = mm_get_string_unquoted_from_match_info (match_info, 1); - if (currentstr) - mm_get_uint_from_str (currentstr, ¤t); - - if (current == 0) { - inner_error = g_error_new (MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Couldn't parse ^SCFG? response"); - } else { - guint i; - - for (i = 0; i < G_N_ELEMENTS (cinterion_bands); i++) { - if (current & cinterion_bands[i].cinterion_band_flag) { - if (G_UNLIKELY (!bands)) - bands = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), 9); - g_array_append_val (bands, cinterion_bands[i].mm_band); - } - } - } - } - } else if (format == MM_CINTERION_RADIO_BAND_FORMAT_MULTIPLE) { - r = g_regex_new ("\\^SCFG:\\s*\"Radio/Band/([234]G)\",\"?([0-9A-Fa-fx]*)\"?,?\"?([0-9A-Fa-fx]*)?\"?", - 0, 0, NULL); - g_assert (r != NULL); - - g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error); - if (inner_error) - goto finish; - - while (g_match_info_matches (match_info)) { - g_autofree gchar *techstr = NULL; - guint current; - - techstr = mm_get_string_unquoted_from_match_info (match_info, 1); - if (g_strcmp0 (techstr, "2G") == 0) { - current = take_and_convert_from_matched_string (mm_get_string_unquoted_from_match_info (match_info, 2), - charset, modem_family, &inner_error); - if (inner_error) - break; - parse_bands (current, &bands, MM_CINTERION_RB_BLOCK_GSM, modem_family); - - } else if (g_strcmp0 (techstr, "3G") == 0) { - current = take_and_convert_from_matched_string (mm_get_string_unquoted_from_match_info (match_info, 2), - charset, modem_family, &inner_error); - if (inner_error) - break; - parse_bands (current, &bands, MM_CINTERION_RB_BLOCK_UMTS, modem_family); - } else if (g_strcmp0 (techstr, "4G") == 0) { - current = take_and_convert_from_matched_string (mm_get_string_unquoted_from_match_info (match_info, 2), - charset, modem_family, &inner_error); - if (inner_error) - break; - parse_bands (current, &bands, MM_CINTERION_RB_BLOCK_LTE_LOW, modem_family); - if (modem_family == MM_CINTERION_MODEM_FAMILY_DEFAULT) { - current = take_and_convert_from_matched_string (mm_get_string_unquoted_from_match_info (match_info, 3), - charset, modem_family, &inner_error); - if (inner_error) - break; - parse_bands (current, &bands, MM_CINTERION_RB_BLOCK_LTE_HIGH, modem_family); - } - } else { - inner_error = g_error_new (MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Couldn't parse ^SCFG? response"); - break; - } - - g_match_info_next (match_info, NULL); - } - } else - g_assert_not_reached (); - -finish: - /* set error only if not already given */ - if (!bands && !inner_error) - inner_error = g_error_new (MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "No valid bands found in ^SCFG response"); - - if (inner_error) { - g_propagate_error (error, inner_error); - return FALSE; - } - - g_assert (bands != NULL && bands->len > 0); - *current_bands = bands; - - return TRUE; -} - -/*****************************************************************************/ -/* +CNMI test parser - * - * Example (PHS8): - * AT+CNMI=? - * +CNMI: (0,1,2),(0,1),(0,2),(0),(1) - */ - -gboolean -mm_cinterion_parse_cnmi_test (const gchar *response, - GArray **supported_mode, - GArray **supported_mt, - GArray **supported_bm, - GArray **supported_ds, - GArray **supported_bfr, - GError **error) -{ - g_autoptr(GRegex) r = NULL; - g_autoptr(GMatchInfo) match_info = NULL; - g_autoptr(GArray) tmp_supported_mode = NULL; - g_autoptr(GArray) tmp_supported_mt = NULL; - g_autoptr(GArray) tmp_supported_bm = NULL; - g_autoptr(GArray) tmp_supported_ds = NULL; - g_autoptr(GArray) tmp_supported_bfr = NULL; - GError *inner_error = NULL; - - if (!response) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Missing response"); - return FALSE; - } - - r = g_regex_new ("\\+CNMI:\\s*\\((.*)\\),\\((.*)\\),\\((.*)\\),\\((.*)\\),\\((.*)\\)", - G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW, - 0, NULL); - g_assert (r != NULL); - - g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error); - if (!inner_error && g_match_info_matches (match_info)) { - if (supported_mode) { - g_autofree gchar *str = NULL; - - str = mm_get_string_unquoted_from_match_info (match_info, 1); - tmp_supported_mode = mm_parse_uint_list (str, &inner_error); - if (inner_error) - goto out; - } - if (supported_mt) { - g_autofree gchar *str = NULL; - - str = mm_get_string_unquoted_from_match_info (match_info, 2); - tmp_supported_mt = mm_parse_uint_list (str, &inner_error); - if (inner_error) - goto out; - } - if (supported_bm) { - g_autofree gchar *str = NULL; - - str = mm_get_string_unquoted_from_match_info (match_info, 3); - tmp_supported_bm = mm_parse_uint_list (str, &inner_error); - if (inner_error) - goto out; - } - if (supported_ds) { - g_autofree gchar *str = NULL; - - str = mm_get_string_unquoted_from_match_info (match_info, 4); - tmp_supported_ds = mm_parse_uint_list (str, &inner_error); - if (inner_error) - goto out; - } - if (supported_bfr) { - g_autofree gchar *str = NULL; - - str = mm_get_string_unquoted_from_match_info (match_info, 5); - tmp_supported_bfr = mm_parse_uint_list (str, &inner_error); - if (inner_error) - goto out; - } - } - -out: - if (inner_error) { - g_propagate_error (error, inner_error); - return FALSE; - } - - if (supported_mode) - *supported_mode = g_steal_pointer (&tmp_supported_mode); - if (supported_mt) - *supported_mt = g_steal_pointer (&tmp_supported_mt); - if (supported_bm) - *supported_bm = g_steal_pointer (&tmp_supported_bm); - if (supported_ds) - *supported_ds = g_steal_pointer (&tmp_supported_ds); - if (supported_bfr) - *supported_bfr = g_steal_pointer (&tmp_supported_bfr); - - return TRUE; -} - -/*****************************************************************************/ -/* ^SXRAT test parser - * - * Example (ELS61-E2): - * AT^SXRAT=? - * ^SXRAT: (0-6),(0,2,3),(0,2,3) - */ - -gboolean -mm_cinterion_parse_sxrat_test (const gchar *response, - GArray **supported_rat, - GArray **supported_pref1, - GArray **supported_pref2, - GError **error) -{ - g_autoptr(GRegex) r = NULL; - g_autoptr(GMatchInfo) match_info = NULL; - GError *inner_error = NULL; - GArray *tmp_supported_rat = NULL; - GArray *tmp_supported_pref1 = NULL; - GArray *tmp_supported_pref2 = NULL; - - if (!response) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Missing response"); - return FALSE; - } - - r = g_regex_new ("\\^SXRAT:\\s*\\(([^\\)]*)\\),\\(([^\\)]*)\\)(,\\(([^\\)]*)\\))?(?:\\r\\n)?", - G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW, - 0, NULL); - - g_assert (r != NULL); - - g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error); - - if (!inner_error && g_match_info_matches (match_info)) { - if (supported_rat) { - g_autofree gchar *str = NULL; - - str = mm_get_string_unquoted_from_match_info (match_info, 1); - tmp_supported_rat = mm_parse_uint_list (str, &inner_error); - - if (inner_error) - goto out; - } - if (supported_pref1) { - g_autofree gchar *str = NULL; - - str = mm_get_string_unquoted_from_match_info (match_info, 2); - tmp_supported_pref1 = mm_parse_uint_list (str, &inner_error); - - if (inner_error) - goto out; - } - if (supported_pref2) { - g_autofree gchar *str = NULL; - - /* this match is optional */ - str = mm_get_string_unquoted_from_match_info (match_info, 4); - if (str) { - tmp_supported_pref2 = mm_parse_uint_list (str, &inner_error); - - if (inner_error) - goto out; - } - } - } - -out: - - if (inner_error) { - g_clear_pointer (&tmp_supported_rat, g_array_unref); - g_clear_pointer (&tmp_supported_pref1, g_array_unref); - g_clear_pointer (&tmp_supported_pref2, g_array_unref); - g_propagate_error (error, inner_error); - return FALSE; - } - - if (supported_rat) - *supported_rat = tmp_supported_rat; - if (supported_pref1) - *supported_pref1 = tmp_supported_pref1; - if (supported_pref2) - *supported_pref2 = tmp_supported_pref2; - - return TRUE; -} - -/*****************************************************************************/ -/* Build Cinterion-specific band value */ - -gboolean -mm_cinterion_build_band (GArray *bands, - guint *supported, - gboolean only_2g, - MMCinterionRadioBandFormat format, - MMCinterionModemFamily modem_family, - guint *out_band, - GError **error) -{ - guint band[MM_CINTERION_RB_BLOCK_N] = { 0 }; - - if (format == MM_CINTERION_RADIO_BAND_FORMAT_SINGLE) { - /* The special case of ANY should be treated separately. */ - if (bands->len == 1 && g_array_index (bands, MMModemBand, 0) == MM_MODEM_BAND_ANY) { - if (supported) - band[MM_CINTERION_RB_BLOCK_LEGACY] = supported[MM_CINTERION_RB_BLOCK_LEGACY]; - } else { - guint i; - - for (i = 0; i < G_N_ELEMENTS (cinterion_bands); i++) { - guint j; - - for (j = 0; j < bands->len; j++) { - if (g_array_index (bands, MMModemBand, j) == cinterion_bands[i].mm_band) { - band[MM_CINTERION_RB_BLOCK_LEGACY] |= cinterion_bands[i].cinterion_band_flag; - break; - } - } - } - - /* 2G-only modems only support a subset of the possible band - * combinations. Detect it early and error out. - */ - if (only_2g && !VALIDATE_2G_BAND (band[MM_CINTERION_RB_BLOCK_LEGACY])) - band[MM_CINTERION_RB_BLOCK_LEGACY] = 0; - } - - if (band[MM_CINTERION_RB_BLOCK_LEGACY] == 0) { - g_autofree gchar *bands_string = NULL; - - bands_string = mm_common_build_bands_string ((MMModemBand *)(gpointer)bands->data, bands->len); - g_set_error (error, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "The given band combination is not supported: '%s'", - bands_string); - return FALSE; - } - - } else { /* format == MM_CINTERION_RADIO_BAND_FORMAT_MULTIPLE */ - if (bands->len == 1 && g_array_index (bands, MMModemBand, 0) == MM_MODEM_BAND_ANY) { - if (supported) - memcpy (band, supported, sizeof (guint) * MM_CINTERION_RB_BLOCK_N); - } else { - guint i; - const CinterionBandEx *ref_bands; - guint nb_ref_bands; - - if (modem_family == MM_CINTERION_MODEM_FAMILY_IMT) { - ref_bands = cinterion_bands_imt; - nb_ref_bands = G_N_ELEMENTS (cinterion_bands_imt); - } else { - ref_bands = cinterion_bands_ex; - nb_ref_bands = G_N_ELEMENTS (cinterion_bands_ex); - } - - for (i = 0; i < nb_ref_bands; i++) { - guint j; - - for (j = 0; j < bands->len; j++) { - if (g_array_index (bands, MMModemBand, j) == ref_bands[i].mm_band) { - band[ref_bands[i].cinterion_band_block] |= ref_bands[i].cinterion_band_flag; - break; - } - } - } - } - - /* this modem family does not allow disabling all bands in a given technology through this command */ - if (modem_family == MM_CINTERION_MODEM_FAMILY_IMT && - (!band[MM_CINTERION_RB_BLOCK_GSM] || - !band[MM_CINTERION_RB_BLOCK_UMTS] || - !band[MM_CINTERION_RB_BLOCK_LTE_LOW])) { - g_autofree gchar *bands_string = NULL; - - bands_string = mm_common_build_bands_string ((MMModemBand *)(gpointer)bands->data, bands->len); - g_set_error (error, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "The given band combination is not supported: '%s'", - bands_string); - return FALSE; - } - } - - memcpy (out_band, band, sizeof (guint) * MM_CINTERION_RB_BLOCK_N); - return TRUE; -} - -/*****************************************************************************/ -/* Single ^SIND response parser */ - -gboolean -mm_cinterion_parse_sind_response (const gchar *response, - gchar **description, - guint *mode, - guint *value, - GError **error) -{ - g_autoptr(GRegex) r = NULL; - g_autoptr(GMatchInfo) match_info = NULL; - guint errors = 0; - - if (!response) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Missing response"); - return FALSE; - } - - r = g_regex_new ("\\^SIND:\\s*(.*),(\\d+),(\\d+)(\\r\\n)?", 0, 0, NULL); - g_assert (r != NULL); - - if (g_regex_match (r, response, 0, &match_info)) { - if (description) { - *description = mm_get_string_unquoted_from_match_info (match_info, 1); - if (*description == NULL) - errors++; - } - if (mode && !mm_get_uint_from_match_info (match_info, 2, mode)) - errors++; - if (value && !mm_get_uint_from_match_info (match_info, 3, value)) - errors++; - } else - errors++; - - if (errors > 0) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Failed parsing ^SIND response"); - return FALSE; - } - - return TRUE; -} - -/*****************************************************************************/ -/* ^SWWAN read parser - * - * Description: Parses <cid>, <state>[, <WWAN adapter>] or CME ERROR from SWWAN. - * - * The method returns a MMSwwanState with the connection status of a single - * PDP context, the one being queried via the cid given as input. - * - * Note that we use CID for matching because the WWAN adapter field is optional - * it seems. - * - * Read Command - * AT^SWWAN? - * Response(s) - * [^SWWAN: <cid>, <state>[, <WWAN adapter>]] - * [^SWWAN: ...] - * OK - * ERROR - * +CME ERROR: <err> - * - * Examples: - * OK - If no WWAN connection is active, then read command just returns OK - * ^SWWAN: 3,1,1 - 3rd PDP Context, Activated, First WWAN Adaptor - * +CME ERROR: ? - - */ - -enum { - MM_SWWAN_STATE_DISCONNECTED = 0, - MM_SWWAN_STATE_CONNECTED = 1, -}; - -MMBearerConnectionStatus -mm_cinterion_parse_swwan_response (const gchar *response, - guint cid, - gpointer log_object, - GError **error) -{ - g_autoptr(GRegex) r = NULL; - g_autoptr(GMatchInfo) match_info = NULL; - GError *inner_error = NULL; - MMBearerConnectionStatus status; - - g_assert (response); - - /* If no WWAN connection is active, then ^SWWAN read command just returns OK - * (which we receive as an empty string) */ - if (!response[0]) - return MM_BEARER_CONNECTION_STATUS_DISCONNECTED; - - if (!g_str_has_prefix (response, "^SWWAN:")) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Couldn't parse ^SWWAN response: '%s'", response); - return MM_BEARER_CONNECTION_STATUS_UNKNOWN; - } - - r = g_regex_new ("\\^SWWAN:\\s*(\\d+),\\s*(\\d+)(?:,\\s*(\\d+))?(?:\\r\\n)?", - G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW, 0, NULL); - g_assert (r != NULL); - - status = MM_BEARER_CONNECTION_STATUS_UNKNOWN; - g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error); - while (!inner_error && g_match_info_matches (match_info)) { - guint read_state; - guint read_cid; - - if (!mm_get_uint_from_match_info (match_info, 1, &read_cid)) - mm_obj_warn (log_object, "couldn't read cid in ^SWWAN response: %s", response); - else if (!mm_get_uint_from_match_info (match_info, 2, &read_state)) - mm_obj_warn (log_object, "couldn't read state in ^SWWAN response: %s", response); - else if (read_cid == cid) { - if (read_state == MM_SWWAN_STATE_CONNECTED) { - status = MM_BEARER_CONNECTION_STATUS_CONNECTED; - break; - } - if (read_state == MM_SWWAN_STATE_DISCONNECTED) { - status = MM_BEARER_CONNECTION_STATUS_DISCONNECTED; - break; - } - mm_obj_warn (log_object, "invalid state read in ^SWWAN response: %u", read_state); - break; - } - g_match_info_next (match_info, &inner_error); - } - - if (status == MM_BEARER_CONNECTION_STATUS_UNKNOWN) - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "No state returned for CID %u", cid); - - return status; -} - -/*****************************************************************************/ -/* ^SGAUTH response parser */ - -/* at^sgauth? - * ^SGAUTH: 1,2,"vf" - * ^SGAUTH: 3,0,"" - * ^SGAUTH: 4,0 - * - * OK - */ - -gboolean -mm_cinterion_parse_sgauth_response (const gchar *response, - guint cid, - MMBearerAllowedAuth *out_auth, - gchar **out_username, - GError **error) -{ - g_autoptr(GRegex) r = NULL; - g_autoptr(GMatchInfo) match_info = NULL; - - r = g_regex_new ("\\^SGAUTH:\\s*(\\d+),(\\d+),?\"?([a-zA-Z0-9_-]+)?\"?", 0, 0, NULL); - g_assert (r != NULL); - - g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, NULL); - while (g_match_info_matches (match_info)) { - guint sgauth_cid = 0; - - if (mm_get_uint_from_match_info (match_info, 1, &sgauth_cid) && - (sgauth_cid == cid)) { - guint cinterion_auth_type = 0; - - mm_get_uint_from_match_info (match_info, 2, &cinterion_auth_type); - *out_auth = mm_auth_type_from_cinterion_auth_type (cinterion_auth_type); - *out_username = mm_get_string_unquoted_from_match_info (match_info, 3); - return TRUE; - } - g_match_info_next (match_info, NULL); - } - - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_NOT_FOUND, - "Auth settings for context %u not found", cid); - return FALSE; -} - -/*****************************************************************************/ -/* ^SMONG response parser */ - -static gboolean -get_access_technology_from_smong_gprs_status (guint gprs_status, - MMModemAccessTechnology *out, - GError **error) -{ - switch (gprs_status) { - case 0: - *out = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; - return TRUE; - case 1: - case 2: - *out = MM_MODEM_ACCESS_TECHNOLOGY_GPRS; - return TRUE; - case 3: - case 4: - *out = MM_MODEM_ACCESS_TECHNOLOGY_EDGE; - return TRUE; - default: - break; - } - - g_set_error (error, - MM_CORE_ERROR, - MM_CORE_ERROR_INVALID_ARGS, - "Couldn't get network capabilities, " - "unsupported GPRS status value: '%u'", - gprs_status); - return FALSE; -} - -gboolean -mm_cinterion_parse_smong_response (const gchar *response, - MMModemAccessTechnology *access_tech, - GError **error) -{ - guint value = 0; - GError *inner_error = NULL; - g_autoptr(GMatchInfo) match_info = NULL; - g_autoptr(GRegex) regex = NULL; - - /* The AT^SMONG command returns a cell info table, where the second - * column identifies the "GPRS status", which is exactly what we want. - * So we'll try to read that second number in the values row. - * - * AT^SMONG - * GPRS Monitor - * BCCH G PBCCH PAT MCC MNC NOM TA RAC # Cell # - * 0776 1 - - 214 03 2 00 01 - * OK - */ - regex = g_regex_new (".*GPRS Monitor(?:\r\n)*" - "BCCH\\s*G.*\\r\\n" - "\\s*(\\d+)\\s*(\\d+)\\s*", - G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW, - 0, NULL); - g_assert (regex); - - g_regex_match_full (regex, response, strlen (response), 0, 0, &match_info, &inner_error); - - if (inner_error) { - g_prefix_error (&inner_error, "Failed to match AT^SMONG response: "); - g_propagate_error (error, inner_error); - return FALSE; - } - - if (!g_match_info_matches (match_info) || !mm_get_uint_from_match_info (match_info, 2, &value)) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Couldn't read 'GPRS status' field from AT^SMONG response"); - return FALSE; - } - - return get_access_technology_from_smong_gprs_status (value, access_tech, error); -} - -/*****************************************************************************/ -/* ^SIND psinfo helper */ - -MMModemAccessTechnology -mm_cinterion_get_access_technology_from_sind_psinfo (guint val, - gpointer log_object) -{ - switch (val) { - case 0: - return MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; - case 1: - case 2: - return MM_MODEM_ACCESS_TECHNOLOGY_GPRS; - case 3: - case 4: - return MM_MODEM_ACCESS_TECHNOLOGY_EDGE; - case 5: - case 6: - return MM_MODEM_ACCESS_TECHNOLOGY_UMTS; - case 7: - case 8: - return MM_MODEM_ACCESS_TECHNOLOGY_HSDPA; - case 9: - case 10: - return (MM_MODEM_ACCESS_TECHNOLOGY_HSDPA | MM_MODEM_ACCESS_TECHNOLOGY_HSUPA); - case 16: - case 17: - return MM_MODEM_ACCESS_TECHNOLOGY_LTE; - default: - mm_obj_dbg (log_object, "unable to identify access technology from psinfo reported value: %u", val); - return MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN; - } -} - -/*****************************************************************************/ -/* ^SLCC psinfo helper */ - -GRegex * -mm_cinterion_get_slcc_regex (void) -{ - /* The list of active calls displayed with this URC will always be terminated - * with an empty line preceded by prefix "^SLCC: ", in order to indicate the end - * of the list. - */ - return g_regex_new ("\\r\\n(\\^SLCC: .*\\r\\n)*\\^SLCC: \\r\\n", - G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); -} - -static void -cinterion_call_info_free (MMCallInfo *info) -{ - if (!info) - return; - g_free (info->number); - g_slice_free (MMCallInfo, info); -} - -gboolean -mm_cinterion_parse_slcc_list (const gchar *str, - gpointer log_object, - GList **out_list, - GError **error) -{ - g_autoptr(GRegex) r = NULL; - g_autoptr(GMatchInfo) match_info = NULL; - GList *list = NULL; - GError *inner_error = NULL; - - static const MMCallDirection cinterion_call_direction[] = { - [0] = MM_CALL_DIRECTION_OUTGOING, - [1] = MM_CALL_DIRECTION_INCOMING, - }; - - static const MMCallState cinterion_call_state[] = { - [0] = MM_CALL_STATE_ACTIVE, - [1] = MM_CALL_STATE_HELD, - [2] = MM_CALL_STATE_DIALING, /* Dialing (MOC) */ - [3] = MM_CALL_STATE_RINGING_OUT, /* Alerting (MOC) */ - [4] = MM_CALL_STATE_RINGING_IN, /* Incoming (MTC) */ - [5] = MM_CALL_STATE_WAITING, /* Waiting (MTC) */ - }; - - g_assert (out_list); - - /* - * 1 2 3 4 5 6 7 8 9 - * ^SLCC: <idx>, <dir>, <stat>, <mode>, <mpty>, <Reserved>[, <number>, <type>[,<alpha>]] - * [^SLCC: <idx>, <dir>, <stat>, <mode>, <mpty>, <Reserved>[, <number>, <type>[,<alpha>]]] - * [... ] - * ^SLCC : - */ - - r = g_regex_new ("\\^SLCC:\\s*(\\d+),\\s*(\\d+),\\s*(\\d+),\\s*(\\d+),\\s*(\\d+),\\s*(\\d+)" /* mandatory fields */ - "(?:,\\s*([^,]*),\\s*(\\d+)" /* number and type */ - "(?:,\\s*([^,]*)" /* alpha */ - ")?)?$", - G_REGEX_RAW | G_REGEX_MULTILINE | G_REGEX_NEWLINE_CRLF, - G_REGEX_MATCH_NEWLINE_CRLF, - NULL); - g_assert (r != NULL); - - g_regex_match_full (r, str, strlen (str), 0, 0, &match_info, &inner_error); - if (inner_error) - goto out; - - /* Parse the results */ - while (g_match_info_matches (match_info)) { - MMCallInfo *call_info; - guint aux; - - call_info = g_slice_new0 (MMCallInfo); - - if (!mm_get_uint_from_match_info (match_info, 1, &call_info->index)) { - mm_obj_warn (log_object, "couldn't parse call index from ^SLCC line"); - goto next; - } - - if (!mm_get_uint_from_match_info (match_info, 2, &aux) || - (aux >= G_N_ELEMENTS (cinterion_call_direction))) { - mm_obj_warn (log_object, "couldn't parse call direction from ^SLCC line"); - goto next; - } - call_info->direction = cinterion_call_direction[aux]; - - if (!mm_get_uint_from_match_info (match_info, 3, &aux) || - (aux >= G_N_ELEMENTS (cinterion_call_state))) { - mm_obj_warn (log_object, "couldn't parse call state from ^SLCC line"); - goto next; - } - call_info->state = cinterion_call_state[aux]; - - if (g_match_info_get_match_count (match_info) >= 8) - call_info->number = mm_get_string_unquoted_from_match_info (match_info, 7); - - list = g_list_append (list, call_info); - call_info = NULL; - - next: - cinterion_call_info_free (call_info); - g_match_info_next (match_info, NULL); - } - -out: - if (inner_error) { - mm_cinterion_call_info_list_free (list); - g_propagate_error (error, inner_error); - return FALSE; - } - - *out_list = list; - - return TRUE; -} - -void -mm_cinterion_call_info_list_free (GList *call_info_list) -{ - g_list_free_full (call_info_list, (GDestroyNotify) cinterion_call_info_free); -} - -/*****************************************************************************/ -/* +CTZU URC helpers */ - -GRegex * -mm_cinterion_get_ctzu_regex (void) -{ - /* - * From PLS-8 AT command spec: - * +CTZU:<nitzUT>, <nitzTZ>[, <nitzDST>] - * E.g.: - * +CTZU: "19/07/09,10:19:15",+08,1 - */ - - return g_regex_new ("\\r\\n\\+CTZU:\\s*\"(\\d+)\\/(\\d+)\\/(\\d+),(\\d+):(\\d+):(\\d+)\",([\\-\\+\\d]+)(?:,(\\d+))?(?:\\r\\n)?", - G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); -} - -gboolean -mm_cinterion_parse_ctzu_urc (GMatchInfo *match_info, - gchar **iso8601p, - MMNetworkTimezone **tzp, - GError **error) -{ - gboolean ret = TRUE; - guint year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0, dst = 0; - gint tz = 0; - - if (!mm_get_uint_from_match_info (match_info, 1, &year) || - !mm_get_uint_from_match_info (match_info, 2, &month) || - !mm_get_uint_from_match_info (match_info, 3, &day) || - !mm_get_uint_from_match_info (match_info, 4, &hour) || - !mm_get_uint_from_match_info (match_info, 5, &minute) || - !mm_get_uint_from_match_info (match_info, 6, &second) || - !mm_get_int_from_match_info (match_info, 7, &tz)) { - g_set_error_literal (error, - MM_CORE_ERROR, - MM_CORE_ERROR_FAILED, - "Failed to parse +CTZU URC"); - return FALSE; - } - - /* adjust year */ - if (year < 100) - year += 2000; - - /* - * tz = timezone offset in 15 minute intervals - */ - if (iso8601p) { - /* Return ISO-8601 format date/time string */ - *iso8601p = mm_new_iso8601_time (year, month, day, hour, - minute, second, - TRUE, tz * 15, - error); - ret = (*iso8601p != NULL); - } - - if (tzp) { - *tzp = mm_network_timezone_new (); - mm_network_timezone_set_offset (*tzp, tz * 15); - } - - /* dst flag is optional in the URC - * - * tz = timezone offset in 15 minute intervals - * dst = daylight adjustment, 0 = none, 1 = 1 hour, 2 = 2 hours - */ - if (tzp && mm_get_uint_from_match_info (match_info, 8, &dst)) - mm_network_timezone_set_dst_offset (*tzp, dst * 60); - - return ret; -} - -/*****************************************************************************/ -/* ^SMONI response parser */ - -gboolean -mm_cinterion_parse_smoni_query_response (const gchar *response, - MMCinterionRadioGen *out_tech, - gdouble *out_rssi, - gdouble *out_ecn0, - gdouble *out_rscp, - gdouble *out_rsrp, - gdouble *out_rsrq, - GError **error) -{ - g_autoptr(GRegex) r = NULL; - g_autoptr(GRegex) pre = NULL; - g_autoptr(GMatchInfo) match_info = NULL; - g_autoptr(GMatchInfo) match_info_pre = NULL; - GError *inner_error = NULL; - MMCinterionRadioGen tech = MM_CINTERION_RADIO_GEN_NONE; - gdouble rssi = -G_MAXDOUBLE; - gdouble ecn0 = -G_MAXDOUBLE; - gdouble rscp = -G_MAXDOUBLE; - gdouble rsrq = -G_MAXDOUBLE; - gdouble rsrp = -G_MAXDOUBLE; - gboolean success = FALSE; - - g_assert (out_tech); - g_assert (out_rssi); - g_assert (out_ecn0); - g_assert (out_rscp); - g_assert (out_rsrp); - g_assert (out_rsrq); - g_assert (out_rssi); - - /* Possible Responses: - * 2G - * ^SMONI: 2G,ARFCN,BCCH,MCC,MNC,LAC,cell,C1,C2,NCC,BCC,GPRS,Conn_state // registered - * ^SMONI: 2G,ARFCN,BCCH,MCC,MNC,LAC,cell,C1,C2,NCC,BCC,GPRS,ARFCN,TS,timAdv,dBm,Q,ChMod // searching - * ^SMONI: 2G,ARFCN,BCCH,MCC,MNC,LAC,cell,C1,C2,NCC,BCC,GPRS,PWR,RXLev,ARFCN,TS,timAdv,dBm,Q,ChMod // limsrv - * ^SMONI: 2G,ARFCN,BCCH,MCC,MNC,LAC,cell,C1,C2,NCC,BCC,GPRS,ARFCN,TS,timAdv,dBm,Q,ChMod // dedicated channel - * - * ^SMONI: 2G,71,-61,262,02,0143,83BA,33,33,3,6,G,NOCONN - * ^^^ - * ^SMONI: 2G,SEARCH,SEARCH - * ^SMONI: 2G,673,-89,262,07,4EED,A500,16,16,7,4,G,5,-107,LIMSRV - * ^^^ ^^^^ RXLev dBm - * ^SMONI: 2G,673,-80,262,07,4EED,A500,35,35,7,4,G,643,4,0,-80,0,S_FR - * ^^^ ^^^ dBm: Receiving level of the traffic channel carrier in dBm - * BCCH: Receiving level of the BCCH carrier in dBm (level is limited from -110dBm to -47dBm) - * -> rssi for 2G, directly without mm_3gpp_rxlev_to_rssi - * - * - * 3G - * ^SMONI: 3G,UARFCN,PSC,EC/n0,RSCP,MCC,MNC,LAC,cell,SQual,SRxLev,,Conn_state", - * ^SMONI: 3G,UARFCN,PSC,EC/n0,RSCP,MCC,MNC,LAC,cell,SQual,SRxLev,PhysCh, SF,Slot,EC/n0,RSCP,ComMod,HSUPA,HSDPA", - * ^SMONI: 3G,UARFCN,PSC,EC/n0,RSCP,MCC,MNC,LAC,cell,SQual,SRxLev,PhysCh, SF,Slot,EC/n0,RSCP,ComMod,HSUPA,HSDPA", - * ^SMONI: 3G,UARFCN,PSC,EC/n0,RSCP,MCC,MNC,LAC,cell,SQual,SRxLev,PhysCh, SF,Slot,EC/n0,RSCP,ComMod,HSUPA,HSDPA", - * - * ^SMONI: 3G,10564,296,-7.5,-79,262,02,0143,00228FF,-92,-78,NOCONN - * ^^^^ ^^^ - * ^SMONI: 3G,SEARCH,SEARCH - * ^SMONI: 3G,10564,96,-7.5,-79,262,02,0143,00228FF,-92,-78,LIMSRV - * ^^^^ ^^^ - * ^SMONI: 3G,10737,131,-5,-93,260,01,7D3D,C80BC9A,--,--,----,---,-,-5,-93,0,01,06 - * ^^ ^^^ - * RSCP: Received Signal Code Power in dBm -> no need for mm_3gpp_rscp_level_to_rscp - * EC/n0: EC/n0 Carrier to noise ratio in dB = measured Ec/Io value in dB. Please refer to 3GPP 25.133, section 9.1.2.3, Table 9.9 for details on the mapping from EC/n0 to EC/Io. - * -> direct value, without need for mm_3gpp_ecn0_level_to_ecio - * - * - * 4G - * ^SMONI: 4G,EARFCN,Band,DL bandwidth,UL bandwidth,Mode,MCC,MNC,TAC,Global Cell ID,Physical Cell ID,Srxlev,RSRP,RSRQ,Conn_state - * ^SMONI: 4G,EARFCN,Band,DL bandwidth,UL bandwidth,Mode,MCC,MNC,TAC,Global Cell ID,Physical Cell ID,Srxlev,RSRP,RSRQ,Conn_state - * ^SMONI: 4G,EARFCN,Band,DL bandwidth,UL bandwidth,Mode,MCC,MNC,TAC,Global Cell ID,Physical Cell ID,Srxlev,RSRP,RSRQ,Conn_state - * ^SMONI: 4G,EARFCN,Band,DL bandwidth,UL bandwidth,Mode,MCC,MNC,TAC,Global Cell ID,Physical Cell ID,TX_power,RSRP,RSRQ,Conn_state - * - * ^SMONI: 4G,6300,20,10,10,FDD,262,02,BF75,0345103,350,33,-94,-7,NOCONN - * ^^^ ^^ - * ^SMONI: 4G,SEARCH - * ^SMONI: 4G,6300,20,10,10,FDD,262,02,BF75,0345103,350,33,-94,-7,LIMSRV - * ^^^ ^^ - * ^SMONI: 4G,6300,20,10,10,FDD,262,02,BF75,0345103,350,90,-94,-7,CONN - * ^^^ ^^ - * RSRP Reference Signal Received Power (see 3GPP 36.214 Section 5.1.1.) -> directly the value without mm_3gpp_rsrq_level_to_rsrp - * RSRQ Reference Signal Received Quality (see 3GPP 36.214 Section 5.1.2.) -> directly the value without mm_3gpp_rsrq_level_to_rsrq - */ - if (g_regex_match_simple ("\\^SMONI:\\s*[234]G,SEARCH", response, 0, 0)) { - success = TRUE; - goto out; - } - pre = g_regex_new ("\\^SMONI:\\s*([234])", 0, 0, NULL); - g_assert (pre != NULL); - g_regex_match_full (pre, response, strlen (response), 0, 0, &match_info_pre, &inner_error); - if (!inner_error && g_match_info_matches (match_info_pre)) { - if (!mm_get_uint_from_match_info (match_info_pre, 1, &tech)) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't read tech"); - goto out; - } - #define FLOAT "([-+]?[0-9]+\\.?[0-9]*)" - switch (tech) { - case MM_CINTERION_RADIO_GEN_2G: - r = g_regex_new ("\\^SMONI:\\s*2G,(\\d+),"FLOAT, 0, 0, NULL); - g_assert (r != NULL); - g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error); - if (!inner_error && g_match_info_matches (match_info)) { - /* skip ARFCN */ - if (!mm_get_double_from_match_info (match_info, 2, &rssi)) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't read BCCH=rssi"); - goto out; - } - } - break; - case MM_CINTERION_RADIO_GEN_3G: - r = g_regex_new ("\\^SMONI:\\s*3G,(\\d+),(\\d+),"FLOAT","FLOAT, 0, 0, NULL); - g_assert (r != NULL); - g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error); - if (!inner_error && g_match_info_matches (match_info)) { - /* skip UARFCN */ - /* skip PSC (Primary scrambling code) */ - if (!mm_get_double_from_match_info (match_info, 3, &ecn0)) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't read EcN0"); - goto out; - } - if (!mm_get_double_from_match_info (match_info, 4, &rscp)) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't read RSCP"); - goto out; - } - } - break; - case MM_CINTERION_RADIO_GEN_4G: - r = g_regex_new ("\\^SMONI:\\s*4G,(\\d+),(\\d+),(\\d+),(\\d+),(\\w+),(\\d+),(\\d+),(\\w+),(\\w+),(\\d+),([^,]*),"FLOAT","FLOAT, 0, 0, NULL); - g_assert (r != NULL); - g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error); - if (!inner_error && g_match_info_matches (match_info)) { - /* skip EARFCN */ - /* skip Band */ - /* skip DL bandwidth */ - /* skip UL bandwidth */ - /* skip Mode */ - /* skip MCC */ - /* skip MNC */ - /* skip TAC */ - /* skip Global Cell ID */ - /* skip Physical Cell ID */ - /* skip Srxlev/TX_power */ - if (!mm_get_double_from_match_info (match_info, 12, &rsrp)) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't read RSRQ"); - goto out; - } - if (!mm_get_double_from_match_info (match_info, 13, &rsrq)) { - inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't read RSRP"); - goto out; - } - } - break; - case MM_CINTERION_RADIO_GEN_NONE: - default: - goto out; - } - #undef FLOAT - success = TRUE; - } - -out: - if (inner_error) { - g_propagate_error (error, inner_error); - return FALSE; - } - - if (!success) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Couldn't parse ^SMONI response: %s", response); - return FALSE; - } - - *out_tech = tech; - *out_rssi = rssi; - *out_rscp = rscp; - *out_ecn0 = ecn0; - *out_rsrq = rsrq; - *out_rsrp = rsrp; - return TRUE; -} - -/*****************************************************************************/ -/* Get extended signal information */ - -gboolean -mm_cinterion_smoni_response_to_signal_info (const gchar *response, - MMSignal **out_gsm, - MMSignal **out_umts, - MMSignal **out_lte, - GError **error) -{ - MMCinterionRadioGen tech = MM_CINTERION_RADIO_GEN_NONE; - gdouble rssi = MM_SIGNAL_UNKNOWN; - gdouble ecn0 = MM_SIGNAL_UNKNOWN; - gdouble rscp = MM_SIGNAL_UNKNOWN; - gdouble rsrq = MM_SIGNAL_UNKNOWN; - gdouble rsrp = MM_SIGNAL_UNKNOWN; - MMSignal *gsm = NULL; - MMSignal *umts = NULL; - MMSignal *lte = NULL; - - if (!mm_cinterion_parse_smoni_query_response (response, - &tech, &rssi, - &ecn0, &rscp, - &rsrp, &rsrq, - error)) - return FALSE; - - switch (tech) { - case MM_CINTERION_RADIO_GEN_2G: - gsm = mm_signal_new (); - mm_signal_set_rssi (gsm, rssi); - break; - case MM_CINTERION_RADIO_GEN_3G: - umts = mm_signal_new (); - mm_signal_set_rscp (umts, rscp); - mm_signal_set_ecio (umts, ecn0); /* UMTS EcIo (assumed EcN0) */ - break; - case MM_CINTERION_RADIO_GEN_4G: - lte = mm_signal_new (); - mm_signal_set_rsrp (lte, rsrp); - mm_signal_set_rsrq (lte, rsrq); - break; - case MM_CINTERION_RADIO_GEN_NONE: /* not registered, searching */ - break; /* no error case */ - default: /* should not happen, so if it does, error */ - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Couldn't build detailed signal info"); - return FALSE; - } - - if (out_gsm) - *out_gsm = gsm; - if (out_umts) - *out_umts = umts; - if (out_lte) - *out_lte = lte; - - return TRUE; -} - -/*****************************************************************************/ -/* provider cfg information to CID number for EPS initial settings */ - -/* - * at^scfg="MEopMode/Prov/Cfg" - * ^SCFG: "MEopMode/Prov/Cfg","vdfde" - * ^SCFG: "MEopMode/Prov/Cfg","attus" - * ^SCFG: "MEopMode/Prov/Cfg","2" -> PLS8-X vzw - * ^SCFG: "MEopMode/Prov/Cfg","vzwdcus" -> PLAS9-x vzw - * ^SCFG: "MEopMode/Prov/Cfg","tmode" -> t-mob germany - * OK - */ -gboolean -mm_cinterion_provcfg_response_to_cid (const gchar *response, - MMCinterionModemFamily modem_family, - MMModemCharset charset, - gpointer log_object, - gint *cid, - GError **error) -{ - g_autoptr(GRegex) r = NULL; - g_autoptr(GMatchInfo) match_info = NULL; - g_autofree gchar *mno = NULL; - GError *inner_error = NULL; - - r = g_regex_new ("\\^SCFG:\\s*\"MEopMode/Prov/Cfg\",\\s*\"([0-9a-zA-Z*]*)\"", 0, 0, NULL); - g_assert (r != NULL); - - g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error); - - if (inner_error) { - g_prefix_error (&inner_error, "Failed to match Prov/Cfg response: "); - g_propagate_error (error, inner_error); - return FALSE; - } - - if (!g_match_info_matches (match_info)) { - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "Couldn't match Prov/Cfg response"); - return FALSE; - } - - mno = mm_get_string_unquoted_from_match_info (match_info, 1); - if (mno && modem_family == MM_CINTERION_MODEM_FAMILY_IMT) { - gchar *mno_utf8; - - mno_utf8 = mm_modem_charset_str_to_utf8 (mno, -1, charset, FALSE, error); - if (!mno_utf8) - return FALSE; - g_free (mno); - mno = mno_utf8; - } - mm_obj_dbg (log_object, "current mno: %s", mno ? mno : "none"); - - /* for Cinterion LTE modules, some CID numbers have special meaning. - * This is dictated by the chipset and by the MNO: - * - the chipset uses a special one, CID 1, as a LTE combined attach chipset - * - the MNOs can define the sequence and number of APN to be used for their network. - * This takes priority over the chipset preferences, and therefore for some of them - * the CID for the initial EPS context must be changed. - */ - if (g_strcmp0 (mno, "2") == 0 || g_strcmp0 (mno, "vzwdcus") == 0) - *cid = 3; - else if (g_strcmp0 (mno, "tmode") == 0) - *cid = 2; - else - *cid = 1; - return TRUE; -} - -/*****************************************************************************/ -/* Auth related helpers */ - -typedef enum { - BEARER_CINTERION_AUTH_UNKNOWN = -1, - BEARER_CINTERION_AUTH_NONE = 0, - BEARER_CINTERION_AUTH_PAP = 1, - BEARER_CINTERION_AUTH_CHAP = 2, - BEARER_CINTERION_AUTH_MSCHAPV2 = 3, -} BearerCinterionAuthType; - -static BearerCinterionAuthType -parse_auth_type (MMBearerAllowedAuth mm_auth) -{ - switch (mm_auth) { - case MM_BEARER_ALLOWED_AUTH_NONE: - return BEARER_CINTERION_AUTH_NONE; - case MM_BEARER_ALLOWED_AUTH_PAP: - return BEARER_CINTERION_AUTH_PAP; - case MM_BEARER_ALLOWED_AUTH_CHAP: - return BEARER_CINTERION_AUTH_CHAP; - case MM_BEARER_ALLOWED_AUTH_MSCHAPV2: - return BEARER_CINTERION_AUTH_MSCHAPV2; - case MM_BEARER_ALLOWED_AUTH_UNKNOWN: - case MM_BEARER_ALLOWED_AUTH_MSCHAP: - case MM_BEARER_ALLOWED_AUTH_EAP: - default: - return BEARER_CINTERION_AUTH_UNKNOWN; - } -} - -MMBearerAllowedAuth -mm_auth_type_from_cinterion_auth_type (guint cinterion_auth) -{ - switch (cinterion_auth) { - case BEARER_CINTERION_AUTH_NONE: - return MM_BEARER_ALLOWED_AUTH_NONE; - case BEARER_CINTERION_AUTH_PAP: - return MM_BEARER_ALLOWED_AUTH_PAP; - case BEARER_CINTERION_AUTH_CHAP: - return MM_BEARER_ALLOWED_AUTH_CHAP; - default: - return MM_BEARER_ALLOWED_AUTH_UNKNOWN; - } -} - -/* Cinterion authentication is done with the command AT^SGAUTH, - whose syntax depends on the modem family, as follow: - - AT^SGAUTH=<cid>[, <auth_type>[, <user>, <passwd>]] for the IMT family - - AT^SGAUTH=<cid>[, <auth_type>[, <passwd>, <user>]] for the rest */ -gchar * -mm_cinterion_build_auth_string (gpointer log_object, - MMCinterionModemFamily modem_family, - MMBearerProperties *config, - guint cid) -{ - MMBearerAllowedAuth auth; - BearerCinterionAuthType encoded_auth = BEARER_CINTERION_AUTH_UNKNOWN; - gboolean has_user; - gboolean has_passwd; - const gchar *user; - const gchar *passwd; - g_autofree gchar *quoted_user = NULL; - g_autofree gchar *quoted_passwd = NULL; - - user = mm_bearer_properties_get_user (config); - passwd = mm_bearer_properties_get_password (config); - auth = mm_bearer_properties_get_allowed_auth (config); - - has_user = (user && user[0]); - has_passwd = (passwd && passwd[0]); - encoded_auth = parse_auth_type (auth); - - /* When 'none' requested, we won't require user/password */ - if (encoded_auth == BEARER_CINTERION_AUTH_NONE) { - if (has_user || has_passwd) - mm_obj_warn (log_object, "APN user/password given but 'none' authentication requested"); - if (modem_family == MM_CINTERION_MODEM_FAMILY_IMT) - return g_strdup_printf ("^SGAUTH=%u,%d,\"\",\"\"", cid, encoded_auth); - return g_strdup_printf ("^SGAUTH=%u,%d", cid, encoded_auth); - } - - /* No explicit auth type requested? */ - if (encoded_auth == BEARER_CINTERION_AUTH_UNKNOWN) { - /* If no user/passwd given, do nothing */ - if (!has_user && !has_passwd) - return NULL; - - /* If user/passwd given, default to CHAP (more common than PAP) */ - mm_obj_dbg (log_object, "APN user/password given but no authentication type explicitly requested: defaulting to 'CHAP'"); - encoded_auth = BEARER_CINTERION_AUTH_CHAP; - } - - quoted_user = mm_port_serial_at_quote_string (user ? user : ""); - quoted_passwd = mm_port_serial_at_quote_string (passwd ? passwd : ""); - - if (modem_family == MM_CINTERION_MODEM_FAMILY_IMT) - return g_strdup_printf ("^SGAUTH=%u,%d,%s,%s", - cid, - encoded_auth, - quoted_user, - quoted_passwd); - - return g_strdup_printf ("^SGAUTH=%u,%d,%s,%s", - cid, - encoded_auth, - quoted_passwd, - quoted_user); -} - -/*****************************************************************************/ -/* ^SXRAT set command builder */ - -/* Index of the array is the centerion-specific sxrat value */ -static const MMModemMode sxrat_combinations[] = { - [0] = ( MM_MODEM_MODE_2G ), - [1] = ( MM_MODEM_MODE_2G | MM_MODEM_MODE_3G ), - [2] = ( MM_MODEM_MODE_3G ), - [3] = ( MM_MODEM_MODE_4G ), - [4] = ( MM_MODEM_MODE_3G | MM_MODEM_MODE_4G ), - [5] = ( MM_MODEM_MODE_2G | MM_MODEM_MODE_4G ), - [6] = ( MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G ), -}; - -static gboolean -append_sxrat_rat_value (GString *str, - MMModemMode mode, - GError **error) -{ - guint i; - - for (i = 0; i < G_N_ELEMENTS (sxrat_combinations); i++) { - if (sxrat_combinations[i] == mode) { - g_string_append_printf (str, "%u", i); - return TRUE; - } - } - - g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "No AcT value matches requested mode"); - return FALSE; -} - -gchar * -mm_cinterion_build_sxrat_set_command (MMModemMode allowed, - MMModemMode preferred, - GError **error) -{ - GString *command; - - command = g_string_new ("^SXRAT="); - if (!append_sxrat_rat_value (command, allowed, error)) { - g_string_free (command, TRUE); - return NULL; - } - - if (preferred != MM_MODEM_MODE_NONE) { - if (mm_count_bits_set (preferred) != 1) { - *error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, - "AcT preferred value should be a single AcT"); - g_string_free (command, TRUE); - return NULL; - } - g_string_append (command, ","); - if (!append_sxrat_rat_value (command, preferred, error)) { - g_string_free (command, TRUE); - return NULL; - } - } - - return g_string_free (command, FALSE); -} diff --git a/plugins/cinterion/mm-modem-helpers-cinterion.h b/plugins/cinterion/mm-modem-helpers-cinterion.h deleted file mode 100644 index 3155d0c1..00000000 --- a/plugins/cinterion/mm-modem-helpers-cinterion.h +++ /dev/null @@ -1,211 +0,0 @@ -/* -*- 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 Aleksander Morgado <aleksander@aleksander.es> - * Copyright (C) 2016 Trimble Navigation Limited - * Copyright (C) 2016 Matthew Stanger <matthew_stanger@trimble.com> - * Copyright (C) 2019 Purism SPC - */ - -#ifndef MM_MODEM_HELPERS_CINTERION_H -#define MM_MODEM_HELPERS_CINTERION_H - -#include <glib.h> - -#include <ModemManager.h> -#include <mm-base-bearer.h> -#define _LIBMM_INSIDE_MM -#include <libmm-glib.h> - -typedef enum { - MM_CINTERION_MODEM_FAMILY_DEFAULT = 0, - MM_CINTERION_MODEM_FAMILY_IMT = 1, -} MMCinterionModemFamily; - -typedef enum { - MM_CINTERION_RADIO_BAND_FORMAT_SINGLE = 0, - MM_CINTERION_RADIO_BAND_FORMAT_MULTIPLE = 1, -} MMCinterionRadioBandFormat; - -typedef enum { - MM_CINTERION_RB_BLOCK_LEGACY = 0, - MM_CINTERION_RB_BLOCK_GSM = 0, - MM_CINTERION_RB_BLOCK_UMTS = 1, - MM_CINTERION_RB_BLOCK_LTE_LOW = 2, - MM_CINTERION_RB_BLOCK_LTE_HIGH = 3, - MM_CINTERION_RB_BLOCK_N = 4 -} MMCinterionRbBlock; - -typedef enum { - MM_CINTERION_RADIO_GEN_NONE = 0, - MM_CINTERION_RADIO_GEN_2G = 2, - MM_CINTERION_RADIO_GEN_3G = 3, - MM_CINTERION_RADIO_GEN_4G = 4, -} MMCinterionRadioGen; - -/*****************************************************************************/ -/* ^SCFG test parser */ - -gboolean mm_cinterion_parse_scfg_test (const gchar *response, - MMCinterionModemFamily modem_family, - MMModemCharset charset, - GArray **supported_bands, - MMCinterionRadioBandFormat *format, - GError **error); - -/*****************************************************************************/ -/* ^SCFG response parser */ - -gboolean mm_cinterion_parse_scfg_response (const gchar *response, - MMCinterionModemFamily modem_family, - MMModemCharset charset, - GArray **bands, - MMCinterionRadioBandFormat format, - GError **error); - -/*****************************************************************************/ -/* +CNMI test parser */ - -gboolean mm_cinterion_parse_cnmi_test (const gchar *response, - GArray **supported_mode, - GArray **supported_mt, - GArray **supported_bm, - GArray **supported_ds, - GArray **supported_bfr, - GError **error); - -/*****************************************************************************/ -/* ^SXRAT test parser */ - -gboolean mm_cinterion_parse_sxrat_test (const gchar *response, - GArray **supported_rat, - GArray **supported_pref1, - GArray **supported_pref2, - GError **error); - -/*****************************************************************************/ -/* Build Cinterion-specific band value */ - -gboolean mm_cinterion_build_band (GArray *bands, - guint *supported, - gboolean only_2g, - MMCinterionRadioBandFormat format, - MMCinterionModemFamily modem_family, - guint *out_band, - GError **error); - -/*****************************************************************************/ -/* Single ^SIND response parser */ - -gboolean mm_cinterion_parse_sind_response (const gchar *response, - gchar **description, - guint *mode, - guint *value, - GError **error); - -/*****************************************************************************/ -/* ^SWWAN response parser */ - -MMBearerConnectionStatus mm_cinterion_parse_swwan_response (const gchar *response, - guint swwan_index, - gpointer log_object, - GError **error); - -/*****************************************************************************/ -/* ^SGAUTH response parser */ - -gboolean mm_cinterion_parse_sgauth_response (const gchar *response, - guint cid, - MMBearerAllowedAuth *out_auth, - gchar **out_username, - GError **error); - -/*****************************************************************************/ -/* ^SMONG response parser */ - -gboolean mm_cinterion_parse_smong_response (const gchar *response, - MMModemAccessTechnology *access_tech, - GError **error); - -/*****************************************************************************/ -/* ^SIND psinfo helper */ - -MMModemAccessTechnology mm_cinterion_get_access_technology_from_sind_psinfo (guint val, - gpointer log_object); - -/*****************************************************************************/ -/* ^SLCC URC helpers */ - -GRegex *mm_cinterion_get_slcc_regex (void); - -/* MMCallInfo list management */ -gboolean mm_cinterion_parse_slcc_list (const gchar *str, - gpointer log_object, - GList **out_list, - GError **error); -void mm_cinterion_call_info_list_free (GList *call_info_list); - -/*****************************************************************************/ -/* +CTZU URC helpers */ - -GRegex *mm_cinterion_get_ctzu_regex (void); -gboolean mm_cinterion_parse_ctzu_urc (GMatchInfo *match_info, - gchar **iso8601p, - MMNetworkTimezone **tzp, - GError **error); - -/*****************************************************************************/ -/* ^SMONI helper */ - -gboolean mm_cinterion_parse_smoni_query_response (const gchar *response, - MMCinterionRadioGen *out_tech, - gdouble *out_rssi, - gdouble *out_ecn0, - gdouble *out_rscp, - gdouble *out_rsrp, - gdouble *out_rsrq, - GError **error); - -gboolean mm_cinterion_smoni_response_to_signal_info (const gchar *response, - MMSignal **out_gsm, - MMSignal **out_umts, - MMSignal **out_lte, - GError **error); - -/*****************************************************************************/ -/* ^SCFG="MEopMode/Prov/Cfg" helper */ - -gboolean mm_cinterion_provcfg_response_to_cid (const gchar *response, - MMCinterionModemFamily modem_family, - MMModemCharset charset, - gpointer log_object, - gint *cid, - GError **error); - -/*****************************************************************************/ -/* Auth related helpers */ - -MMBearerAllowedAuth mm_auth_type_from_cinterion_auth_type (guint cinterion_auth); - -gchar *mm_cinterion_build_auth_string (gpointer log_object, - MMCinterionModemFamily modem_family, - MMBearerProperties *config, - guint cid); - -/*****************************************************************************/ -/* ^SXRAT set command helper */ - -gchar *mm_cinterion_build_sxrat_set_command (MMModemMode allowed, - MMModemMode preferred, - GError **error); - -#endif /* MM_MODEM_HELPERS_CINTERION_H */ diff --git a/plugins/cinterion/mm-plugin-cinterion.c b/plugins/cinterion/mm-plugin-cinterion.c deleted file mode 100644 index b0f3f992..00000000 --- a/plugins/cinterion/mm-plugin-cinterion.c +++ /dev/null @@ -1,218 +0,0 @@ -/* -*- 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. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Copyright (C) 2011 Ammonit Measurement GmbH - * Copyright (C) 2011 - 2012 Google Inc. - * Author: Aleksander Morgado <aleksander@lanedo.com> - */ - -#include <string.h> -#include <gmodule.h> - -#define _LIBMM_INSIDE_MM -#include <libmm-glib.h> - -#include "mm-plugin-cinterion.h" -#include "mm-broadband-modem-cinterion.h" -#include "mm-log-object.h" - -#if defined WITH_QMI -#include "mm-broadband-modem-qmi-cinterion.h" -#endif - -#if defined WITH_MBIM -#include "mm-broadband-modem-mbim-cinterion.h" -#endif - -G_DEFINE_TYPE (MMPluginCinterion, mm_plugin_cinterion, MM_TYPE_PLUGIN) - -MM_PLUGIN_DEFINE_MAJOR_VERSION -MM_PLUGIN_DEFINE_MINOR_VERSION - -/*****************************************************************************/ -/* Custom init */ - -#define TAG_CINTERION_APP_PORT "cinterion-app-port" -#define TAG_CINTERION_MODEM_PORT "cinterion-modem-port" - -static gboolean -cinterion_custom_init_finish (MMPortProbe *probe, - GAsyncResult *result, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (result), error); -} - -static void -sqport_ready (MMPortSerialAt *port, - GAsyncResult *res, - GTask *task) -{ - MMPortProbe *probe; - const gchar *response; - - probe = g_task_get_source_object (task); - - /* Ignore errors, just avoid tagging */ - response = mm_port_serial_at_command_finish (port, res, NULL); - if (response) { - /* A valid reply to AT^SQPORT tells us this is an AT port already */ - mm_port_probe_set_result_at (probe, TRUE); - - if (strstr (response, "Application")) - g_object_set_data (G_OBJECT (probe), TAG_CINTERION_APP_PORT, GUINT_TO_POINTER (TRUE)); - else if (strstr (response, "Modem")) - g_object_set_data (G_OBJECT (probe), TAG_CINTERION_MODEM_PORT, GUINT_TO_POINTER (TRUE)); - } - - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -static void -cinterion_custom_init (MMPortProbe *probe, - MMPortSerialAt *port, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GTask *task; - - task = g_task_new (probe, cancellable, callback, user_data); - - mm_port_serial_at_command ( - port, - "AT^SQPORT?", - 3, - FALSE, /* raw */ - FALSE, /* allow cached */ - cancellable, - (GAsyncReadyCallback) sqport_ready, - task); -} - -/*****************************************************************************/ - -static MMBaseModem * -create_modem (MMPlugin *self, - const gchar *uid, - const gchar **drivers, - guint16 vendor, - guint16 product, - guint16 subsystem_vendor, - GList *probes, - GError **error) -{ -#if defined WITH_QMI - if (mm_port_probe_list_has_qmi_port (probes)) { - mm_obj_dbg (self, "QMI-powered Cinterion modem found..."); - return MM_BASE_MODEM (mm_broadband_modem_qmi_cinterion_new (uid, - drivers, - mm_plugin_get_name (self), - vendor, - product)); - } -#endif - -#if defined WITH_MBIM - if (mm_port_probe_list_has_mbim_port (probes)) { - mm_obj_dbg (self, "MBIM-powered Cinterion modem found..."); - return MM_BASE_MODEM (mm_broadband_modem_mbim_cinterion_new (uid, - drivers, - mm_plugin_get_name (self), - vendor, - product)); - } -#endif - - return MM_BASE_MODEM (mm_broadband_modem_cinterion_new (uid, - drivers, - mm_plugin_get_name (self), - vendor, - product)); -} - -static gboolean -grab_port (MMPlugin *self, - MMBaseModem *modem, - MMPortProbe *probe, - GError **error) -{ - MMPortSerialAtFlag pflags = MM_PORT_SERIAL_AT_FLAG_NONE; - MMPortType ptype; - - ptype = mm_port_probe_get_port_type (probe); - - if (g_object_get_data (G_OBJECT (probe), TAG_CINTERION_APP_PORT)) { - mm_obj_dbg (self, "port '%s/%s' flagged as primary", - mm_port_probe_get_port_subsys (probe), - mm_port_probe_get_port_name (probe)); - pflags = MM_PORT_SERIAL_AT_FLAG_PRIMARY; - } else if (g_object_get_data (G_OBJECT (probe), TAG_CINTERION_MODEM_PORT)) { - mm_obj_dbg (self, "port '%s/%s' flagged as PPP", - mm_port_probe_get_port_subsys (probe), - mm_port_probe_get_port_name (probe)); - pflags = MM_PORT_SERIAL_AT_FLAG_PPP; - } - - return mm_base_modem_grab_port (modem, - mm_port_probe_peek_port (probe), - ptype, - pflags, - error); -} - -/*****************************************************************************/ - -G_MODULE_EXPORT MMPlugin * -mm_plugin_create (void) -{ - static const gchar *subsystems[] = { "tty", "net", "usbmisc", "wwan", NULL }; - static const gchar *vendor_strings[] = { "cinterion", "siemens", NULL }; - static const guint16 vendor_ids[] = { 0x1e2d, 0x0681, 0x1269, 0 }; - static const MMAsyncMethod custom_init = { - .async = G_CALLBACK (cinterion_custom_init), - .finish = G_CALLBACK (cinterion_custom_init_finish), - }; - - return MM_PLUGIN ( - g_object_new (MM_TYPE_PLUGIN_CINTERION, - MM_PLUGIN_NAME, MM_MODULE_NAME, - MM_PLUGIN_ALLOWED_SUBSYSTEMS, subsystems, - MM_PLUGIN_ALLOWED_VENDOR_STRINGS, vendor_strings, - MM_PLUGIN_ALLOWED_VENDOR_IDS, vendor_ids, - MM_PLUGIN_ALLOWED_AT, TRUE, - MM_PLUGIN_ALLOWED_QMI, TRUE, - MM_PLUGIN_ALLOWED_MBIM, TRUE, - MM_PLUGIN_CUSTOM_INIT, &custom_init, - NULL)); -} - -static void -mm_plugin_cinterion_init (MMPluginCinterion *self) -{ -} - -static void -mm_plugin_cinterion_class_init (MMPluginCinterionClass *klass) -{ - MMPluginClass *plugin_class = MM_PLUGIN_CLASS (klass); - - plugin_class->create_modem = create_modem; - plugin_class->grab_port = grab_port; -} diff --git a/plugins/cinterion/mm-plugin-cinterion.h b/plugins/cinterion/mm-plugin-cinterion.h deleted file mode 100644 index a8a3b6bb..00000000 --- a/plugins/cinterion/mm-plugin-cinterion.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -*- 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. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - * Copyright (C) 2011 Ammonit Measurement GmbH - * Author: Aleksander Morgado <aleksander@lanedo.com> - */ - -#ifndef MM_PLUGIN_CINTERION_H -#define MM_PLUGIN_CINTERION_H - -#include "mm-plugin.h" - -#define MM_TYPE_PLUGIN_CINTERION (mm_plugin_cinterion_get_type ()) -#define MM_PLUGIN_CINTERION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_CINTERION, MMPluginCinterion)) -#define MM_PLUGIN_CINTERION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_CINTERION, MMPluginCinterionClass)) -#define MM_IS_PLUGIN_CINTERION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_PLUGIN_CINTERION)) -#define MM_IS_PLUGIN_CINTERION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_PLUGIN_CINTERION)) -#define MM_PLUGIN_CINTERION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_PLUGIN_CINTERION, MMPluginCinterionClass)) - -typedef struct { - MMPlugin parent; -} MMPluginCinterion; - -typedef struct { - MMPluginClass parent; -} MMPluginCinterionClass; - -GType mm_plugin_cinterion_get_type (void); - -G_MODULE_EXPORT MMPlugin *mm_plugin_create (void); - -#endif /* MM_PLUGIN_CINTERION_H */ diff --git a/plugins/cinterion/mm-shared-cinterion.c b/plugins/cinterion/mm-shared-cinterion.c deleted file mode 100644 index 36cf60c9..00000000 --- a/plugins/cinterion/mm-shared-cinterion.c +++ /dev/null @@ -1,1601 +0,0 @@ -/* -*- 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 - * Copyright (C) 2014 - 2018 Aleksander Morgado <aleksander@aleksander.es> - * Copyright (C) 2019 Purism SPC - */ - -#include <config.h> - -#include <glib-object.h> -#include <gio/gio.h> - -#define _LIBMM_INSIDE_MM -#include <libmm-glib.h> - -#include "mm-log-object.h" -#include "mm-iface-modem.h" -#include "mm-iface-modem-location.h" -#include "mm-base-modem.h" -#include "mm-base-modem-at.h" -#include "mm-shared-cinterion.h" -#include "mm-modem-helpers-cinterion.h" - -/*****************************************************************************/ -/* Private data context */ - -#define PRIVATE_TAG "shared-cinterion-private-tag" -static GQuark private_quark; - -typedef enum { - FEATURE_SUPPORT_UNKNOWN, - FEATURE_NOT_SUPPORTED, - FEATURE_SUPPORTED, -} FeatureSupport; - -typedef struct { - /* modem */ - MMIfaceModem *iface_modem_parent; - /* location */ - MMIfaceModemLocation *iface_modem_location_parent; - MMModemLocationSource supported_sources; - MMModemLocationSource enabled_sources; - FeatureSupport sgpss_support; - FeatureSupport sgpsc_support; - /* voice */ - MMIfaceModemVoice *iface_modem_voice_parent; - FeatureSupport slcc_support; - GRegex *slcc_regex; - /* time */ - MMIfaceModemTime *iface_modem_time_parent; - GRegex *ctzu_regex; -} Private; - -static void -private_free (Private *ctx) -{ - g_regex_unref (ctx->ctzu_regex); - g_regex_unref (ctx->slcc_regex); - g_slice_free (Private, ctx); -} - -static Private * -get_private (MMSharedCinterion *self) -{ - Private *priv; - - if (G_UNLIKELY (!private_quark)) - private_quark = (g_quark_from_static_string (PRIVATE_TAG)); - - priv = g_object_get_qdata (G_OBJECT (self), private_quark); - if (!priv) { - priv = g_slice_new (Private); - - priv->supported_sources = MM_MODEM_LOCATION_SOURCE_NONE; - priv->enabled_sources = MM_MODEM_LOCATION_SOURCE_NONE; - priv->sgpss_support = FEATURE_SUPPORT_UNKNOWN; - priv->sgpsc_support = FEATURE_SUPPORT_UNKNOWN; - priv->slcc_support = FEATURE_SUPPORT_UNKNOWN; - priv->slcc_regex = mm_cinterion_get_slcc_regex (); - priv->ctzu_regex = mm_cinterion_get_ctzu_regex (); - - /* Setup parent class' MMIfaceModem, MMIfaceModemLocation, MMIfaceModemVoice - * and MMIfaceModemTime */ - - g_assert (MM_SHARED_CINTERION_GET_INTERFACE (self)->peek_parent_interface); - priv->iface_modem_parent = MM_SHARED_CINTERION_GET_INTERFACE (self)->peek_parent_interface (self); - - g_assert (MM_SHARED_CINTERION_GET_INTERFACE (self)->peek_parent_location_interface); - priv->iface_modem_location_parent = MM_SHARED_CINTERION_GET_INTERFACE (self)->peek_parent_location_interface (self); - - g_assert (MM_SHARED_CINTERION_GET_INTERFACE (self)->peek_parent_voice_interface); - priv->iface_modem_voice_parent = MM_SHARED_CINTERION_GET_INTERFACE (self)->peek_parent_voice_interface (self); - - g_assert (MM_SHARED_CINTERION_GET_INTERFACE (self)->peek_parent_time_interface); - priv->iface_modem_time_parent = MM_SHARED_CINTERION_GET_INTERFACE (self)->peek_parent_time_interface (self); - - g_object_set_qdata_full (G_OBJECT (self), private_quark, priv, (GDestroyNotify)private_free); - } - - return priv; -} - -/*****************************************************************************/ -/* Modem interface */ - -gboolean -mm_shared_cinterion_modem_reset_finish (MMIfaceModem *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -modem_reset_at_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); - else - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -static void -modem_reset_at (GTask *task) -{ - MMSharedCinterion *self; - - self = g_task_get_source_object (task); - - mm_base_modem_at_command (MM_BASE_MODEM (self), - "+CFUN=1,1", - 3, - FALSE, - (GAsyncReadyCallback) modem_reset_at_ready, - task); -} - -static void -parent_modem_reset_ready (MMIfaceModem *self, - GAsyncResult *res, - GTask *task) -{ - Private *priv; - - priv = get_private (MM_SHARED_CINTERION (self)); - if (!priv->iface_modem_parent->reset_finish (self, res, NULL)) { - modem_reset_at (task); - return; - } - - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -void -mm_shared_cinterion_modem_reset (MMIfaceModem *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GTask *task; - Private *priv; - - priv = get_private (MM_SHARED_CINTERION (self)); - task = g_task_new (self, NULL, callback, user_data); - - if (priv->iface_modem_parent->reset && - priv->iface_modem_parent->reset_finish) { - priv->iface_modem_parent->reset (self, - (GAsyncReadyCallback) parent_modem_reset_ready, - task); - return; - } - - modem_reset_at (task); -} - -/*****************************************************************************/ -/* GPS trace received */ - -static void -trace_received (MMPortSerialGps *port, - const gchar *trace, - MMIfaceModemLocation *self) -{ - mm_iface_modem_location_gps_update (self, trace); -} - -/*****************************************************************************/ -/* Location capabilities loading (Location interface) */ - -MMModemLocationSource -mm_shared_cinterion_location_load_capabilities_finish (MMIfaceModemLocation *self, - GAsyncResult *res, - GError **error) -{ - GError *inner_error = NULL; - gssize aux; - - aux = 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) aux; -} - -static void probe_gps_features (GTask *task); - -static void -sgpsc_test_ready (MMBaseModem *self, - GAsyncResult *res, - GTask *task) -{ - Private *priv; - - priv = get_private (MM_SHARED_CINTERION (self)); - - if (!mm_base_modem_at_command_finish (self, res, NULL)) - priv->sgpsc_support = FEATURE_NOT_SUPPORTED; - else { - /* ^SGPSC supported! */ - priv->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) -{ - Private *priv; - - priv = get_private (MM_SHARED_CINTERION (self)); - - if (!mm_base_modem_at_command_finish (self, res, NULL)) - priv->sgpss_support = FEATURE_NOT_SUPPORTED; - else { - /* ^SGPSS supported! */ - priv->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. */ - priv->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. */ - mm_base_modem_at_command (MM_BASE_MODEM (self), "AT^SGPSS=0", 3, FALSE, NULL, NULL); - } - - probe_gps_features (task); -} - -static void -probe_gps_features (GTask *task) -{ - MMSharedCinterion *self; - MMModemLocationSource sources; - Private *priv; - - self = MM_SHARED_CINTERION (g_task_get_source_object (task)); - priv = get_private (self); - - /* Need to check if SGPSS supported... */ - if (priv->sgpss_support == FEATURE_SUPPORT_UNKNOWN) { - mm_base_modem_at_command (MM_BASE_MODEM (self), "AT^SGPSS=?", 3, TRUE, (GAsyncReadyCallback) sgpss_test_ready, task); - return; - } - - /* Need to check if SGPSC supported... */ - if (priv->sgpsc_support == FEATURE_SUPPORT_UNKNOWN) { - mm_base_modem_at_command (MM_BASE_MODEM (self), "AT^SGPSC=?", 3, TRUE, (GAsyncReadyCallback) sgpsc_test_ready, task); - return; - } - - /* All GPS features probed */ - - /* Recover parent sources */ - sources = GPOINTER_TO_UINT (g_task_get_task_data (task)); - - if (priv->sgpss_support == FEATURE_SUPPORTED || priv->sgpsc_support == FEATURE_SUPPORTED) { - mm_obj_dbg (self, "GPS commands supported: GPS capabilities enabled"); - - /* We only flag as supported by this implementation those sources not already - * supported by the parent implementation */ - if (!(sources & MM_MODEM_LOCATION_SOURCE_GPS_NMEA)) - priv->supported_sources |= MM_MODEM_LOCATION_SOURCE_GPS_NMEA; - if (!(sources & MM_MODEM_LOCATION_SOURCE_GPS_RAW)) - priv->supported_sources |= MM_MODEM_LOCATION_SOURCE_GPS_RAW; - if (!(sources & MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED)) - priv->supported_sources |= MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED; - - sources |= priv->supported_sources; - - /* Add handler for the NMEA traces in the GPS data port */ - mm_port_serial_gps_add_trace_handler (mm_base_modem_peek_port_gps (MM_BASE_MODEM (self)), - (MMPortSerialGpsTraceFn)trace_received, - self, - NULL); - } else - mm_obj_dbg (self, "no GPS command supported: no GPS capabilities"); - - g_task_return_int (task, (gssize) sources); - g_object_unref (task); -} - -static void -parent_load_capabilities_ready (MMIfaceModemLocation *self, - GAsyncResult *res, - GTask *task) -{ - MMModemLocationSource sources; - GError *error = NULL; - Private *priv; - - priv = get_private (MM_SHARED_CINTERION (self)); - - sources = priv->iface_modem_location_parent->load_capabilities_finish (self, res, &error); - if (error) { - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - /* Now our own check. If we don't have any GPS port, we're done */ - if (!mm_base_modem_peek_port_gps (MM_BASE_MODEM (self))) { - mm_obj_dbg (self, "no GPS data port found: no GPS capabilities"); - g_task_return_int (task, sources); - g_object_unref (task); - return; - } - - /* Cache sources supported by the parent */ - g_task_set_task_data (task, GUINT_TO_POINTER (sources), NULL); - - /* Probe all GPS features */ - probe_gps_features (task); -} - -void -mm_shared_cinterion_location_load_capabilities (MMIfaceModemLocation *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - Private *priv; - GTask *task; - - priv = get_private (MM_SHARED_CINTERION (self)); - task = g_task_new (self, NULL, callback, user_data); - - g_assert (priv->iface_modem_location_parent); - g_assert (priv->iface_modem_location_parent->load_capabilities); - g_assert (priv->iface_modem_location_parent->load_capabilities_finish); - - priv->iface_modem_location_parent->load_capabilities (self, - (GAsyncReadyCallback)parent_load_capabilities_ready, - task); -} - -/*****************************************************************************/ -/* Disable location gathering (Location interface) */ - -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; - -typedef struct { - MMModemLocationSource source; - DisableLocationGatheringGpsStep gps_step; - GError *sgpss_error; - GError *sgpsc_error; -} DisableLocationGatheringContext; - -static void -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); -} - -gboolean -mm_shared_cinterion_disable_location_gathering_finish (MMIfaceModemLocation *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -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) -{ - DisableLocationGatheringContext *ctx; - - ctx = (DisableLocationGatheringContext *) g_task_get_task_data (task); - - /* Store error, if any, and continue */ - g_assert (!ctx->sgpss_error); - mm_base_modem_at_command_finish (self, res, &ctx->sgpss_error); - - ctx->gps_step++; - disable_location_gathering_context_gps_step (task); -} - -static void -disable_location_gathering_context_gps_step (GTask *task) -{ - DisableLocationGatheringContext *ctx; - MMSharedCinterion *self; - Private *priv; - - self = MM_SHARED_CINTERION (g_task_get_source_object (task)); - priv = get_private (self); - ctx = (DisableLocationGatheringContext *) g_task_get_task_data (task); - - /* Only one of both supported */ - g_assert ((priv->sgpss_support == FEATURE_SUPPORTED) || (priv->sgpsc_support == FEATURE_SUPPORTED)); - g_assert (!((priv->sgpss_support == FEATURE_SUPPORTED) && (priv->sgpsc_support == FEATURE_SUPPORTED))); - - switch (ctx->gps_step) { - case DISABLE_LOCATION_GATHERING_GPS_STEP_FIRST: - ctx->gps_step++; - /* fall through */ - - case DISABLE_LOCATION_GATHERING_GPS_STEP_SGPSS: - if (priv->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 through */ - - case DISABLE_LOCATION_GATHERING_GPS_STEP_SGPSC_ENGINE: - if (priv->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 through */ - - case DISABLE_LOCATION_GATHERING_GPS_STEP_SGPSC_ANTENNA: - if (priv->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 through */ - - case DISABLE_LOCATION_GATHERING_GPS_STEP_SGPSC_OUTPUT: - if (priv->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 through */ - - 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)) { - MMPortSerialGps *gps_port; - - /* Even if we get an error here, we try to close the GPS port */ - gps_port = mm_base_modem_peek_port_gps (MM_BASE_MODEM (self)); - if (gps_port) - mm_port_serial_close (MM_PORT_SERIAL (gps_port)); - } - - 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 { - priv->enabled_sources &= ~ctx->source; - g_task_return_boolean (task, TRUE); - } - g_object_unref (task); - return; - - default: - g_assert_not_reached (); - } -} - -static void -parent_disable_location_gathering_ready (MMIfaceModemLocation *self, - GAsyncResult *res, - GTask *task) -{ - GError *error = NULL; - Private *priv; - - priv = get_private (MM_SHARED_CINTERION (self)); - - g_assert (priv->iface_modem_location_parent); - if (!priv->iface_modem_location_parent->disable_location_gathering_finish (self, res, &error)) - g_task_return_error (task, error); - else - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -void -mm_shared_cinterion_disable_location_gathering (MMIfaceModemLocation *self, - MMModemLocationSource source, - GAsyncReadyCallback callback, - gpointer user_data) -{ - DisableLocationGatheringContext *ctx; - MMModemLocationSource enabled_sources; - Private *priv; - GTask *task; - - task = g_task_new (self, NULL, callback, user_data); - - priv = get_private (MM_SHARED_CINTERION (self)); - g_assert (priv->iface_modem_location_parent); - - /* Only consider request if it applies to one of the sources we are - * supporting, otherwise run parent disable */ - if (!(priv->supported_sources & source)) { - /* If disabling implemented by the parent, run it. */ - if (priv->iface_modem_location_parent->disable_location_gathering && - priv->iface_modem_location_parent->disable_location_gathering_finish) { - priv->iface_modem_location_parent->disable_location_gathering (self, - source, - (GAsyncReadyCallback)parent_disable_location_gathering_ready, - task); - return; - } - /* Otherwise, we're done */ - g_task_return_boolean (task, TRUE); - g_object_unref (task); - return; - } - - /* We only expect GPS sources here */ - g_assert (source & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA | - MM_MODEM_LOCATION_SOURCE_GPS_RAW | - MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED)); - - /* Flag as disabled to see how many others we would have left enabled */ - enabled_sources = priv->enabled_sources; - enabled_sources &= ~source; - - /* If there are still GPS-related sources enabled, do nothing else */ - if (enabled_sources & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA | - MM_MODEM_LOCATION_SOURCE_GPS_RAW | - MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED)) { - priv->enabled_sources &= ~source; - g_task_return_boolean (task, TRUE); - g_object_unref (task); - return; - } - - /* Stop GPS engine if all GPS-related sources are disabled */ - ctx = g_slice_new0 (DisableLocationGatheringContext); - ctx->source = source; - ctx->gps_step = DISABLE_LOCATION_GATHERING_GPS_STEP_FIRST; - g_task_set_task_data (task, ctx, (GDestroyNotify) disable_location_gathering_context_free); - disable_location_gathering_context_gps_step (task); -} - -/*****************************************************************************/ -/* Enable location gathering (Location interface) */ - -/* We will retry the SGPSC command that enables the Engine */ -#define MAX_SGPSC_ENGINE_RETRIES 3 - -/* Cinterion asks for 100ms some time between GPS commands, but we'll give up - * to 2000ms before setting the Engine configuration as 100ms didn't seem always - * enough (we would get +CME ERROR: 767 errors reported). */ -#define GPS_COMMAND_TIMEOUT_DEFAULT_MS 100 -#define GPS_COMMAND_TIMEOUT_ENGINE_MS 2000 - -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; - guint sgpsc_engine_retries; -} EnableLocationGatheringContext; - -static void -enable_location_gathering_context_free (EnableLocationGatheringContext *ctx) -{ - g_slice_free (EnableLocationGatheringContext, ctx); -} - -gboolean -mm_shared_cinterion_enable_location_gathering_finish (MMIfaceModemLocation *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void enable_location_gathering_context_gps_step (GTask *task); - -static gboolean -enable_location_gathering_context_gps_step_schedule_cb (GTask *task) -{ - /* Run the scheduled 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) -{ - EnableLocationGatheringContext *ctx; - GError *error = NULL; - - ctx = (EnableLocationGatheringContext *) g_task_get_task_data (task); - - if (!mm_base_modem_at_command_finish (self, res, &error)) { - /* The GPS setup may sometimes report "+CME ERROR 767" when enabling the - * Engine; so we'll run some retries of the same command ourselves. */ - if (ctx->gps_step == ENABLE_LOCATION_GATHERING_GPS_STEP_SGPSC_ENGINE) { - ctx->sgpsc_engine_retries++; - mm_obj_dbg (self, "GPS engine setup failed (%u/%u)", ctx->sgpsc_engine_retries, MAX_SGPSC_ENGINE_RETRIES); - if (ctx->sgpsc_engine_retries < MAX_SGPSC_ENGINE_RETRIES) { - g_clear_error (&error); - goto schedule; - } - } - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - /* Go on to next step */ - ctx->gps_step++; - -schedule: - g_timeout_add (ctx->gps_step == ENABLE_LOCATION_GATHERING_GPS_STEP_SGPSC_ENGINE ? GPS_COMMAND_TIMEOUT_ENGINE_MS : GPS_COMMAND_TIMEOUT_DEFAULT_MS, - (GSourceFunc) enable_location_gathering_context_gps_step_schedule_cb, task); -} - -static void -enable_location_gathering_context_gps_step (GTask *task) -{ - EnableLocationGatheringContext *ctx; - MMSharedCinterion *self; - Private *priv; - - self = MM_SHARED_CINTERION (g_task_get_source_object (task)); - priv = get_private (self); - ctx = (EnableLocationGatheringContext *) g_task_get_task_data (task); - - /* Only one of both supported */ - g_assert ((priv->sgpss_support == FEATURE_SUPPORTED) || (priv->sgpsc_support == FEATURE_SUPPORTED)); - g_assert (!((priv->sgpss_support == FEATURE_SUPPORTED) && (priv->sgpsc_support == FEATURE_SUPPORTED))); - - switch (ctx->gps_step) { - case ENABLE_LOCATION_GATHERING_GPS_STEP_FIRST: - ctx->gps_step++; - /* fall through */ - - case ENABLE_LOCATION_GATHERING_GPS_STEP_SGPSS: - if (priv->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 through */ - - case ENABLE_LOCATION_GATHERING_GPS_STEP_SGPSC_OUTPUT: - if (priv->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 through */ - - case ENABLE_LOCATION_GATHERING_GPS_STEP_SGPSC_ANTENNA: - if (priv->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 through */ - - case ENABLE_LOCATION_GATHERING_GPS_STEP_SGPSC_ENGINE: - if (priv->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 through */ - - 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)) { - MMPortSerialGps *gps_port; - GError *error = NULL; - - gps_port = mm_base_modem_peek_port_gps (MM_BASE_MODEM (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"); - g_object_unref (task); - return; - } - } - - /* Success */ - priv->enabled_sources |= ctx->source; - g_task_return_boolean (task, TRUE); - g_object_unref (task); - return; - - default: - g_assert_not_reached (); - } -} - -static void -parent_enable_location_gathering_ready (MMIfaceModemLocation *self, - GAsyncResult *res, - GTask *task) -{ - GError *error = NULL; - Private *priv; - - priv = get_private (MM_SHARED_CINTERION (self)); - - g_assert (priv->iface_modem_location_parent); - if (!priv->iface_modem_location_parent->enable_location_gathering_finish (self, res, &error)) - g_task_return_error (task, error); - else - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -void -mm_shared_cinterion_enable_location_gathering (MMIfaceModemLocation *self, - MMModemLocationSource source, - GAsyncReadyCallback callback, - gpointer user_data) -{ - Private *priv; - GTask *task; - EnableLocationGatheringContext *ctx; - - - task = g_task_new (self, NULL, callback, user_data); - - priv = get_private (MM_SHARED_CINTERION (self)); - g_assert (priv->iface_modem_location_parent); - g_assert (priv->iface_modem_location_parent->enable_location_gathering); - g_assert (priv->iface_modem_location_parent->enable_location_gathering_finish); - - /* Only consider request if it applies to one of the sources we are - * supporting, otherwise run parent enable */ - if (!(priv->supported_sources & source)) { - priv->iface_modem_location_parent->enable_location_gathering (self, - source, - (GAsyncReadyCallback)parent_enable_location_gathering_ready, - task); - return; - } - - /* We only expect GPS sources here */ - g_assert (source & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA | - MM_MODEM_LOCATION_SOURCE_GPS_RAW | - MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED)); - - /* If GPS already started, store new flag and we're done */ - if (priv->enabled_sources & (MM_MODEM_LOCATION_SOURCE_GPS_NMEA | - MM_MODEM_LOCATION_SOURCE_GPS_RAW | - MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED)) { - priv->enabled_sources |= source; - g_task_return_boolean (task, TRUE); - g_object_unref (task); - return; - } - - ctx = g_slice_new0 (EnableLocationGatheringContext); - ctx->source = source; - ctx->gps_step = ENABLE_LOCATION_GATHERING_GPS_STEP_FIRST; - g_task_set_task_data (task, ctx, (GDestroyNotify) enable_location_gathering_context_free); - - enable_location_gathering_context_gps_step (task); -} - -/*****************************************************************************/ - -MMBaseCall * -mm_shared_cinterion_create_call (MMIfaceModemVoice *self, - MMCallDirection direction, - const gchar *number) -{ - Private *priv; - - /* If ^SLCC is supported create a cinterion call object */ - priv = get_private (MM_SHARED_CINTERION (self)); - if (priv->slcc_support == FEATURE_SUPPORTED) { - mm_obj_dbg (self, "created new call with ^SLCC support"); - return mm_base_call_new (MM_BASE_MODEM (self), - direction, - number, - /* When SLCC is supported we have support for detailed - * call list events via call list report URCs */ - TRUE, /* incoming timeout not required */ - TRUE, /* dialing->ringing supported */ - TRUE); /* ringing->active supported */ - } - - /* otherwise, run parent's generic base call logic */ - g_assert (priv->iface_modem_voice_parent); - g_assert (priv->iface_modem_voice_parent->create_call); - return priv->iface_modem_voice_parent->create_call (self, direction, number); -} - -/*****************************************************************************/ -/* Common enable/disable voice unsolicited events */ - -typedef struct { - gboolean enable; - MMPortSerialAt *primary; - MMPortSerialAt *secondary; - gchar *slcc_command; - gboolean slcc_primary_done; - gboolean slcc_secondary_done; -} VoiceUnsolicitedEventsContext; - -static void -voice_unsolicited_events_context_free (VoiceUnsolicitedEventsContext *ctx) -{ - g_clear_object (&ctx->secondary); - g_clear_object (&ctx->primary); - g_free (ctx->slcc_command); - g_slice_free (VoiceUnsolicitedEventsContext, ctx); -} - -static gboolean -common_voice_enable_disable_unsolicited_events_finish (MMSharedCinterion *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void run_voice_enable_disable_unsolicited_events (GTask *task); - -static void -slcc_command_ready (MMBaseModem *self, - GAsyncResult *res, - GTask *task) -{ - VoiceUnsolicitedEventsContext *ctx; - g_autoptr(GError) error = NULL; - - ctx = g_task_get_task_data (task); - - if (!mm_base_modem_at_command_full_finish (self, res, &error)) - mm_obj_dbg (self, "couldn't %s ^SLCC reporting: %s", - ctx->enable ? "enable" : "disable", - error->message); - - /* Continue on next port */ - run_voice_enable_disable_unsolicited_events (task); -} - -static void -run_voice_enable_disable_unsolicited_events (GTask *task) -{ - MMSharedCinterion *self; - Private *priv; - VoiceUnsolicitedEventsContext *ctx; - MMPortSerialAt *port = NULL; - - self = MM_SHARED_CINTERION (g_task_get_source_object (task)); - priv = get_private (self); - ctx = g_task_get_task_data (task); - - /* If not ^SLCC supported, we're done */ - if (priv->slcc_support == FEATURE_NOT_SUPPORTED) { - g_task_return_boolean (task, TRUE); - g_object_unref (task); - return; - } - - if (!ctx->slcc_primary_done && ctx->primary) { - mm_obj_dbg (self, "%s ^SLCC extended list of current calls reporting in primary port...", - ctx->enable ? "enabling" : "disabling"); - ctx->slcc_primary_done = TRUE; - port = ctx->primary; - } else if (!ctx->slcc_secondary_done && ctx->secondary) { - mm_obj_dbg (self, "%s ^SLCC extended list of current calls reporting in secondary port...", - ctx->enable ? "enabling" : "disabling"); - ctx->slcc_secondary_done = TRUE; - port = ctx->secondary; - } - - if (port) { - mm_base_modem_at_command_full (MM_BASE_MODEM (self), - port, - ctx->slcc_command, - 3, - FALSE, - FALSE, - NULL, - (GAsyncReadyCallback)slcc_command_ready, - task); - return; - } - - /* Fully done now */ - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -static void -common_voice_enable_disable_unsolicited_events (MMSharedCinterion *self, - gboolean enable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - VoiceUnsolicitedEventsContext *ctx; - GTask *task; - - task = g_task_new (self, NULL, callback, user_data); - - ctx = g_slice_new0 (VoiceUnsolicitedEventsContext); - ctx->enable = enable; - if (enable) - ctx->slcc_command = g_strdup ("^SLCC=1"); - else - ctx->slcc_command = g_strdup ("^SLCC=0"); - ctx->primary = mm_base_modem_get_port_primary (MM_BASE_MODEM (self)); - ctx->secondary = mm_base_modem_get_port_secondary (MM_BASE_MODEM (self)); - g_task_set_task_data (task, ctx, (GDestroyNotify) voice_unsolicited_events_context_free); - - run_voice_enable_disable_unsolicited_events (task); -} - -/*****************************************************************************/ -/* Disable unsolicited events (Voice interface) */ - -gboolean -mm_shared_cinterion_voice_disable_unsolicited_events_finish (MMIfaceModemVoice *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -parent_voice_disable_unsolicited_events_ready (MMIfaceModemVoice *self, - GAsyncResult *res, - GTask *task) -{ - g_autoptr(GError) error = NULL; - Private *priv; - - priv = get_private (MM_SHARED_CINTERION (self)); - - if (!priv->iface_modem_voice_parent->disable_unsolicited_events_finish (self, res, &error)) - mm_obj_warn (self, "couldn't disable parent voice unsolicited events: %s", error->message); - - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -static void -voice_disable_unsolicited_events_ready (MMSharedCinterion *self, - GAsyncResult *res, - GTask *task) -{ - Private *priv; - g_autoptr(GError) error = NULL; - - if (!common_voice_enable_disable_unsolicited_events_finish (self, res, &error)) - mm_obj_warn (self, "couldn't disable Cinterion-specific voice unsolicited events: %s", error->message); - - priv = get_private (MM_SHARED_CINTERION (self)); - g_assert (priv->iface_modem_voice_parent); - g_assert (priv->iface_modem_voice_parent->disable_unsolicited_events); - g_assert (priv->iface_modem_voice_parent->disable_unsolicited_events_finish); - - /* Chain up parent's disable */ - priv->iface_modem_voice_parent->disable_unsolicited_events ( - MM_IFACE_MODEM_VOICE (self), - (GAsyncReadyCallback)parent_voice_disable_unsolicited_events_ready, - task); -} - -void -mm_shared_cinterion_voice_disable_unsolicited_events (MMIfaceModemVoice *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - GTask *task; - - task = g_task_new (self, NULL, callback, user_data); - - /* our own disabling first */ - common_voice_enable_disable_unsolicited_events (MM_SHARED_CINTERION (self), - FALSE, - (GAsyncReadyCallback) voice_disable_unsolicited_events_ready, - task); -} - -/*****************************************************************************/ -/* Enable unsolicited events (Voice interface) */ - -gboolean -mm_shared_cinterion_voice_enable_unsolicited_events_finish (MMIfaceModemVoice *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -voice_enable_unsolicited_events_ready (MMSharedCinterion *self, - GAsyncResult *res, - GTask *task) -{ - g_autoptr(GError) error = NULL; - - if (!common_voice_enable_disable_unsolicited_events_finish (self, res, &error)) - mm_obj_warn (self, "couldn't enable Cinterion-specific voice unsolicited events: %s", error->message); - - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -static void -parent_voice_enable_unsolicited_events_ready (MMIfaceModemVoice *self, - GAsyncResult *res, - GTask *task) -{ - g_autoptr(GError) error = NULL; - Private *priv; - - priv = get_private (MM_SHARED_CINTERION (self)); - - if (!priv->iface_modem_voice_parent->enable_unsolicited_events_finish (self, res, &error)) - mm_obj_warn (self, "couldn't enable parent voice unsolicited events: %s", error->message); - - /* our own enabling next */ - common_voice_enable_disable_unsolicited_events (MM_SHARED_CINTERION (self), - TRUE, - (GAsyncReadyCallback) voice_enable_unsolicited_events_ready, - task); -} - -void -mm_shared_cinterion_voice_enable_unsolicited_events (MMIfaceModemVoice *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - Private *priv; - GTask *task; - - task = g_task_new (self, NULL, callback, user_data); - - priv = get_private (MM_SHARED_CINTERION (self)); - g_assert (priv->iface_modem_voice_parent); - g_assert (priv->iface_modem_voice_parent->enable_unsolicited_events); - g_assert (priv->iface_modem_voice_parent->enable_unsolicited_events_finish); - - /* chain up parent's enable first */ - priv->iface_modem_voice_parent->enable_unsolicited_events ( - self, - (GAsyncReadyCallback)parent_voice_enable_unsolicited_events_ready, - task); -} - -/*****************************************************************************/ -/* Common setup/cleanup voice unsolicited events */ - -static void -slcc_received (MMPortSerialAt *port, - GMatchInfo *match_info, - MMSharedCinterion *self) -{ - g_autofree gchar *full = NULL; - g_autoptr(GError) error = NULL; - GList *call_info_list = NULL; - - full = g_match_info_fetch (match_info, 0); - if (!mm_cinterion_parse_slcc_list (full, self, &call_info_list, &error)) - mm_obj_warn (self, "couldn't parse ^SLCC list: %s", error->message); - else - mm_iface_modem_voice_report_all_calls (MM_IFACE_MODEM_VOICE (self), call_info_list); - mm_cinterion_call_info_list_free (call_info_list); -} - -static void -common_voice_setup_cleanup_unsolicited_events (MMSharedCinterion *self, - gboolean enable) -{ - Private *priv; - MMPortSerialAt *ports[2]; - guint i; - - priv = get_private (MM_SHARED_CINTERION (self)); - - ports[0] = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)); - ports[1] = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self)); - - for (i = 0; i < G_N_ELEMENTS (ports); i++) { - if (!ports[i]) - continue; - - mm_port_serial_at_add_unsolicited_msg_handler (ports[i], - priv->slcc_regex, - enable ? (MMPortSerialAtUnsolicitedMsgFn)slcc_received : NULL, - enable ? self : NULL, - NULL); - } -} - -/*****************************************************************************/ -/* Cleanup unsolicited events (Voice interface) */ - -gboolean -mm_shared_cinterion_voice_cleanup_unsolicited_events_finish (MMIfaceModemVoice *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -parent_voice_cleanup_unsolicited_events_ready (MMIfaceModemVoice *self, - GAsyncResult *res, - GTask *task) -{ - g_autoptr(GError) error = NULL; - Private *priv; - - priv = get_private (MM_SHARED_CINTERION (self)); - - if (!priv->iface_modem_voice_parent->cleanup_unsolicited_events_finish (self, res, &error)) - mm_obj_warn (self, "couldn't cleanup parent voice unsolicited events: %s", error->message); - - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -void -mm_shared_cinterion_voice_cleanup_unsolicited_events (MMIfaceModemVoice *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - Private *priv; - GTask *task; - - task = g_task_new (self, NULL, callback, user_data); - - priv = get_private (MM_SHARED_CINTERION (self)); - g_assert (priv->iface_modem_voice_parent); - g_assert (priv->iface_modem_voice_parent->cleanup_unsolicited_events); - g_assert (priv->iface_modem_voice_parent->cleanup_unsolicited_events_finish); - - /* our own cleanup first */ - common_voice_setup_cleanup_unsolicited_events (MM_SHARED_CINTERION (self), FALSE); - - /* Chain up parent's cleanup */ - priv->iface_modem_voice_parent->cleanup_unsolicited_events ( - self, - (GAsyncReadyCallback)parent_voice_cleanup_unsolicited_events_ready, - task); -} - -/*****************************************************************************/ -/* Setup unsolicited events (Voice interface) */ - -gboolean -mm_shared_cinterion_voice_setup_unsolicited_events_finish (MMIfaceModemVoice *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -parent_voice_setup_unsolicited_events_ready (MMIfaceModemVoice *self, - GAsyncResult *res, - GTask *task) -{ - g_autoptr(GError) error = NULL; - Private *priv; - - priv = get_private (MM_SHARED_CINTERION (self)); - - if (!priv->iface_modem_voice_parent->setup_unsolicited_events_finish (self, res, &error)) - mm_obj_warn (self, "Couldn't setup parent voice unsolicited events: %s", error->message); - - /* our own setup next */ - common_voice_setup_cleanup_unsolicited_events (MM_SHARED_CINTERION (self), TRUE); - - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -void -mm_shared_cinterion_voice_setup_unsolicited_events (MMIfaceModemVoice *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - Private *priv; - GTask *task; - - task = g_task_new (self, NULL, callback, user_data); - - priv = get_private (MM_SHARED_CINTERION (self)); - g_assert (priv->iface_modem_voice_parent); - g_assert (priv->iface_modem_voice_parent->setup_unsolicited_events); - g_assert (priv->iface_modem_voice_parent->setup_unsolicited_events_finish); - - /* chain up parent's setup first */ - priv->iface_modem_voice_parent->setup_unsolicited_events ( - self, - (GAsyncReadyCallback)parent_voice_setup_unsolicited_events_ready, - task); -} - -/*****************************************************************************/ -/* Check if Voice supported (Voice interface) */ - -gboolean -mm_shared_cinterion_voice_check_support_finish (MMIfaceModemVoice *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -slcc_format_check_ready (MMBroadbandModem *self, - GAsyncResult *res, - GTask *task) -{ - Private *priv; - - priv = get_private (MM_SHARED_CINTERION (self)); - - /* ^SLCC supported unless we got any error response */ - priv->slcc_support = (!!mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, NULL) ? - FEATURE_SUPPORTED : FEATURE_NOT_SUPPORTED); - - /* If ^SLCC supported we won't need polling in the parent */ - g_object_set (self, - MM_IFACE_MODEM_VOICE_PERIODIC_CALL_LIST_CHECK_DISABLED, (priv->slcc_support == FEATURE_SUPPORTED), - NULL); - - /* ^SLCC command is supported; assume we have full voice capabilities */ - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -static void -parent_voice_check_support_ready (MMIfaceModemVoice *self, - GAsyncResult *res, - GTask *task) -{ - Private *priv; - GError *error = NULL; - - priv = get_private (MM_SHARED_CINTERION (self)); - if (!priv->iface_modem_voice_parent->check_support_finish (self, res, &error)) { - g_task_return_error (task, error); - g_object_unref (task); - return; - } - - /* voice is supported, check if ^SLCC is available */ - mm_base_modem_at_command (MM_BASE_MODEM (self), - "^SLCC=?", - 3, - /* Do NOT cache as the reply may be different if PIN locked - * or unlocked. E.g. we may not support ^SLCC for emergency - * voice calls. */ - FALSE, - (GAsyncReadyCallback) slcc_format_check_ready, - task); -} - -void -mm_shared_cinterion_voice_check_support (MMIfaceModemVoice *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - Private *priv; - GTask *task; - - task = g_task_new (self, NULL, callback, user_data); - - priv = get_private (MM_SHARED_CINTERION (self)); - g_assert (priv->iface_modem_voice_parent); - g_assert (priv->iface_modem_voice_parent->check_support); - g_assert (priv->iface_modem_voice_parent->check_support_finish); - - /* chain up parent's setup first */ - priv->iface_modem_voice_parent->check_support ( - self, - (GAsyncReadyCallback)parent_voice_check_support_ready, - task); -} - -/*****************************************************************************/ -/* Common setup/cleanup time unsolicited events */ - -static void -ctzu_received (MMPortSerialAt *port, - GMatchInfo *match_info, - MMSharedCinterion *self) -{ - g_autofree gchar *iso8601 = NULL; - g_autoptr(MMNetworkTimezone) tz = NULL; - g_autoptr(GError) error = NULL; - - if (!mm_cinterion_parse_ctzu_urc (match_info, &iso8601, &tz, &error)) { - mm_obj_dbg (self, "couldn't process +CTZU URC: %s", error->message); - return; - } - - mm_obj_dbg (self, "+CTZU URC received: %s", iso8601); - mm_iface_modem_time_update_network_time (MM_IFACE_MODEM_TIME (self), iso8601); - mm_iface_modem_time_update_network_timezone (MM_IFACE_MODEM_TIME (self), tz); -} - -static void -common_time_setup_cleanup_unsolicited_events (MMSharedCinterion *self, - gboolean enable) -{ - Private *priv; - MMPortSerialAt *ports[2]; - guint i; - - priv = get_private (MM_SHARED_CINTERION (self)); - - ports[0] = mm_base_modem_peek_port_primary (MM_BASE_MODEM (self)); - ports[1] = mm_base_modem_peek_port_secondary (MM_BASE_MODEM (self)); - - mm_obj_dbg (self, "%s up time unsolicited events...", - enable ? "setting" : "cleaning"); - - for (i = 0; i < G_N_ELEMENTS (ports); i++) { - if (!ports[i]) - continue; - - mm_port_serial_at_add_unsolicited_msg_handler (ports[i], - priv->ctzu_regex, - enable ? (MMPortSerialAtUnsolicitedMsgFn)ctzu_received : NULL, - enable ? self : NULL, - NULL); - } -} - -/*****************************************************************************/ -/* Cleanup unsolicited events (Time interface) */ - -gboolean -mm_shared_cinterion_time_cleanup_unsolicited_events_finish (MMIfaceModemTime *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -parent_time_cleanup_unsolicited_events_ready (MMIfaceModemTime *self, - GAsyncResult *res, - GTask *task) -{ - g_autoptr(GError) error = NULL; - Private *priv; - - priv = get_private (MM_SHARED_CINTERION (self)); - - if (!priv->iface_modem_time_parent->cleanup_unsolicited_events_finish (self, res, &error)) - mm_obj_warn (self, "couldn't cleanup parent time unsolicited events: %s", error->message); - - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -void -mm_shared_cinterion_time_cleanup_unsolicited_events (MMIfaceModemTime *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - Private *priv; - GTask *task; - - task = g_task_new (self, NULL, callback, user_data); - - priv = get_private (MM_SHARED_CINTERION (self)); - g_assert (priv->iface_modem_time_parent); - - /* our own cleanup first */ - common_time_setup_cleanup_unsolicited_events (MM_SHARED_CINTERION (self), FALSE); - - if (priv->iface_modem_time_parent->cleanup_unsolicited_events && - priv->iface_modem_time_parent->cleanup_unsolicited_events_finish) { - /* Chain up parent's cleanup */ - priv->iface_modem_time_parent->cleanup_unsolicited_events ( - self, - (GAsyncReadyCallback)parent_time_cleanup_unsolicited_events_ready, - task); - return; - } - - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -/*****************************************************************************/ -/* Setup unsolicited events (Time interface) */ - -gboolean -mm_shared_cinterion_time_setup_unsolicited_events_finish (MMIfaceModemTime *self, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_boolean (G_TASK (res), error); -} - -static void -own_time_setup_unsolicited_events (GTask *task) -{ - MMSharedCinterion *self; - - self = g_task_get_source_object (task); - - /* our own setup next */ - common_time_setup_cleanup_unsolicited_events (MM_SHARED_CINTERION (self), TRUE); - - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -static void -parent_time_setup_unsolicited_events_ready (MMIfaceModemTime *self, - GAsyncResult *res, - GTask *task) -{ - g_autoptr(GError) error = NULL; - Private *priv; - - priv = get_private (MM_SHARED_CINTERION (self)); - - if (!priv->iface_modem_time_parent->cleanup_unsolicited_events_finish (self, res, &error)) - mm_obj_warn (self, "Couldn't cleanup parent time unsolicited events: %s", error->message); - - own_time_setup_unsolicited_events (task); -} - -void -mm_shared_cinterion_time_setup_unsolicited_events (MMIfaceModemTime *self, - GAsyncReadyCallback callback, - gpointer user_data) -{ - Private *priv; - GTask *task; - - task = g_task_new (self, NULL, callback, user_data); - - priv = get_private (MM_SHARED_CINTERION (self)); - g_assert (priv->iface_modem_time_parent); - - if (priv->iface_modem_time_parent->setup_unsolicited_events && - priv->iface_modem_time_parent->setup_unsolicited_events_finish) { - /* chain up parent's setup first */ - priv->iface_modem_time_parent->setup_unsolicited_events ( - self, - (GAsyncReadyCallback)parent_time_setup_unsolicited_events_ready, - task); - return; - } - - own_time_setup_unsolicited_events (task); -} - -/*****************************************************************************/ - -static void -shared_cinterion_init (gpointer g_iface) -{ -} - -GType -mm_shared_cinterion_get_type (void) -{ - static GType shared_cinterion_type = 0; - - if (!G_UNLIKELY (shared_cinterion_type)) { - static const GTypeInfo info = { - sizeof (MMSharedCinterion), /* class_size */ - shared_cinterion_init, /* base_init */ - NULL, /* base_finalize */ - }; - - shared_cinterion_type = g_type_register_static (G_TYPE_INTERFACE, "MMSharedCinterion", &info, 0); - g_type_interface_add_prerequisite (shared_cinterion_type, MM_TYPE_IFACE_MODEM); - g_type_interface_add_prerequisite (shared_cinterion_type, MM_TYPE_IFACE_MODEM_VOICE); - g_type_interface_add_prerequisite (shared_cinterion_type, MM_TYPE_IFACE_MODEM_TIME); - g_type_interface_add_prerequisite (shared_cinterion_type, MM_TYPE_IFACE_MODEM_LOCATION); - } - - return shared_cinterion_type; -} diff --git a/plugins/cinterion/mm-shared-cinterion.h b/plugins/cinterion/mm-shared-cinterion.h deleted file mode 100644 index eb6beac8..00000000 --- a/plugins/cinterion/mm-shared-cinterion.h +++ /dev/null @@ -1,153 +0,0 @@ -/* -*- 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 - * Copyright (C) 2014 - 2018 Aleksander Morgado <aleksander@aleksander.es> - * Copyright (C) 2019 Purism SPC - */ - -#ifndef MM_SHARED_CINTERION_H -#define MM_SHARED_CINTERION_H - -#include <glib-object.h> -#include <gio/gio.h> - -#define _LIBMM_INSIDE_MM -#include <libmm-glib.h> - -#include "mm-broadband-modem.h" -#include "mm-iface-modem.h" -#include "mm-iface-modem-location.h" -#include "mm-iface-modem-voice.h" -#include "mm-iface-modem-time.h" - -#define MM_TYPE_SHARED_CINTERION (mm_shared_cinterion_get_type ()) -#define MM_SHARED_CINTERION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_SHARED_CINTERION, MMSharedCinterion)) -#define MM_IS_SHARED_CINTERION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_SHARED_CINTERION)) -#define MM_SHARED_CINTERION_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), MM_TYPE_SHARED_CINTERION, MMSharedCinterion)) - -typedef struct _MMSharedCinterion MMSharedCinterion; - -struct _MMSharedCinterion { - GTypeInterface g_iface; - - /* Peek modem interface of the parent class of the object */ - MMIfaceModem * (* peek_parent_interface) (MMSharedCinterion *self); - - /* Peek location interface of the parent class of the object */ - MMIfaceModemLocation * (* peek_parent_location_interface) (MMSharedCinterion *self); - - /* Peek voice interface of the parent class of the object */ - MMIfaceModemVoice * (* peek_parent_voice_interface) (MMSharedCinterion *self); - - /* Peek time interface of the parent class of the object */ - MMIfaceModemTime * (* peek_parent_time_interface) (MMSharedCinterion *self); -}; - -GType mm_shared_cinterion_get_type (void); - -/*****************************************************************************/ -/* Modem interface */ - -void mm_shared_cinterion_modem_reset (MMIfaceModem *self, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean mm_shared_cinterion_modem_reset_finish (MMIfaceModem *self, - GAsyncResult *res, - GError **error); - -/*****************************************************************************/ -/* Location interface */ - -void mm_shared_cinterion_location_load_capabilities (MMIfaceModemLocation *self, - GAsyncReadyCallback callback, - gpointer user_data); -MMModemLocationSource mm_shared_cinterion_location_load_capabilities_finish (MMIfaceModemLocation *self, - GAsyncResult *res, - GError **error); - -void mm_shared_cinterion_enable_location_gathering (MMIfaceModemLocation *self, - MMModemLocationSource source, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean mm_shared_cinterion_enable_location_gathering_finish (MMIfaceModemLocation *self, - GAsyncResult *res, - GError **error); - -void mm_shared_cinterion_disable_location_gathering (MMIfaceModemLocation *self, - MMModemLocationSource source, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean mm_shared_cinterion_disable_location_gathering_finish (MMIfaceModemLocation *self, - GAsyncResult *res, - GError **error); - -/*****************************************************************************/ -/* Voice interface */ - -MMBaseCall *mm_shared_cinterion_create_call (MMIfaceModemVoice *self, - MMCallDirection direction, - const gchar *number); - -void mm_shared_cinterion_voice_check_support (MMIfaceModemVoice *self, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean mm_shared_cinterion_voice_check_support_finish (MMIfaceModemVoice *self, - GAsyncResult *res, - GError **error); - -void mm_shared_cinterion_voice_setup_unsolicited_events (MMIfaceModemVoice *self, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean mm_shared_cinterion_voice_setup_unsolicited_events_finish (MMIfaceModemVoice *self, - GAsyncResult *res, - GError **error); - -void mm_shared_cinterion_voice_cleanup_unsolicited_events (MMIfaceModemVoice *self, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean mm_shared_cinterion_voice_cleanup_unsolicited_events_finish (MMIfaceModemVoice *self, - GAsyncResult *res, - GError **error); - -void mm_shared_cinterion_voice_enable_unsolicited_events (MMIfaceModemVoice *self, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean mm_shared_cinterion_voice_enable_unsolicited_events_finish (MMIfaceModemVoice *self, - GAsyncResult *res, - GError **error); - -void mm_shared_cinterion_voice_disable_unsolicited_events (MMIfaceModemVoice *self, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean mm_shared_cinterion_voice_disable_unsolicited_events_finish (MMIfaceModemVoice *self, - GAsyncResult *res, - GError **error); - -/*****************************************************************************/ -/* Time interface */ - -void mm_shared_cinterion_time_setup_unsolicited_events (MMIfaceModemTime *self, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean mm_shared_cinterion_time_setup_unsolicited_events_finish (MMIfaceModemTime *self, - GAsyncResult *res, - GError **error); - -void mm_shared_cinterion_time_cleanup_unsolicited_events (MMIfaceModemTime *self, - GAsyncReadyCallback callback, - gpointer user_data); -gboolean mm_shared_cinterion_time_cleanup_unsolicited_events_finish (MMIfaceModemTime *self, - GAsyncResult *res, - GError **error); - -#endif /* MM_SHARED_CINTERION_H */ diff --git a/plugins/cinterion/tests/test-modem-helpers-cinterion.c b/plugins/cinterion/tests/test-modem-helpers-cinterion.c deleted file mode 100644 index d4816199..00000000 --- a/plugins/cinterion/tests/test-modem-helpers-cinterion.c +++ /dev/null @@ -1,1967 +0,0 @@ -/* -*- 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 Aleksander Morgado <aleksander@aleksander.es> - */ - -#include <glib.h> -#include <glib-object.h> -#include <locale.h> - -#include <ModemManager.h> -#define _LIBMM_INSIDE_MM -#include <libmm-glib.h> -#include <math.h> - -#include "mm-log-test.h" -#include "mm-modem-helpers.h" -#include "mm-modem-helpers-cinterion.h" - -#define g_assert_cmpfloat_tolerance(val1, val2, tolerance) \ - g_assert_cmpfloat (fabs (val1 - val2), <, tolerance) - -/*****************************************************************************/ -/* Test ^SCFG test responses */ - -static void -common_test_scfg (const gchar *response, - GArray *expected_bands, - MMModemCharset charset, - MMCinterionModemFamily modem_family) -{ - GArray *bands = NULL; - gchar *expected_bands_str; - gchar *bands_str; - GError *error = NULL; - gboolean res; - MMCinterionRadioBandFormat format; - - res = mm_cinterion_parse_scfg_test (response, - modem_family, - charset, - &bands, - &format, - &error); - g_assert_no_error (error); - g_assert (res == TRUE); - g_assert (bands != NULL); - - mm_common_bands_garray_sort (bands); - mm_common_bands_garray_sort (expected_bands); - - expected_bands_str = mm_common_build_bands_string ((const MMModemBand *)(gconstpointer)expected_bands->data, - expected_bands->len); - bands_str = mm_common_build_bands_string ((const MMModemBand *)(gconstpointer)bands->data, - bands->len); - - /* Instead of comparing the array one by one, compare the strings built from the mask - * (we get a nicer error if it fails) */ - g_assert_cmpstr (bands_str, ==, expected_bands_str); - - g_free (bands_str); - g_free (expected_bands_str); - g_array_unref (bands); -} - -static void -test_scfg (void) -{ - GArray *expected_bands; - MMModemBand single; - const gchar *response = - "^SCFG: \"Audio/Loop\",(\"0\",\"1\")\r\n" - "^SCFG: \"Call/ECC\",(\"0\"-\"255\")\r\n" - "^SCFG: \"Call/Speech/Codec\",(\"0\",\"1\")\r\n" - "^SCFG: \"GPRS/Auth\",(\"0\",\"1\",\"2\")\r\n" - "^SCFG: \"GPRS/AutoAttach\",(\"disabled\",\"enabled\")\r\n" - "^SCFG: \"GPRS/MaxDataRate/HSDPA\",(\"0\",\"1\")\r\n" - "^SCFG: \"GPRS/MaxDataRate/HSUPA\",(\"0\",\"1\")\r\n" - "^SCFG: \"Ident/Manufacturer\",(25)\r\n" - "^SCFG: \"Ident/Product\",(25)\r\n" - "^SCFG: \"MEopMode/Airplane\",(\"off\",\"on\")\r\n" - "^SCFG: \"MEopMode/CregRoam\",(\"0\",\"1\")\r\n" - "^SCFG: \"MEopMode/CFUN\",(\"0\",\"1\")\r\n" - "^SCFG: \"MEopMode/PowerMgmt/LCI\",(\"disabled\",\"enabled\")\r\n" - "^SCFG: \"MEopMode/PowerMgmt/VExt\",(\"high\",\"low\")\r\n" - "^SCFG: \"MEopMode/PwrSave\",(\"disabled\",\"enabled\"),(\"0-600\"),(\"1-36000\")\r\n" - "^SCFG: \"MEopMode/RingOnData\",(\"on\",\"off\")\r\n" - "^SCFG: \"MEopMode/RingUrcOnCall\",(\"on\",\"off\")\r\n" - "^SCFG: \"MEShutdown/OnIgnition\",(\"on\",\"off\")\r\n" - "^SCFG: \"Radio/Band\",(\"1-511\",\"0-1\")\r\n" - "^SCFG: \"Radio/NWSM\",(\"0\",\"1\",\"2\")\r\n" - "^SCFG: \"Radio/OutputPowerReduction\",(\"4\"-\"8\")\r\n" - "^SCFG: \"Serial/USB/DDD\",(\"0\",\"1\"),(\"0\"),(4),(4),(4),(63),(63),(4)\r\n" - "^SCFG: \"URC/DstIfc\",(\"mdm\",\"app\")\r\n" - "^SCFG: \"URC/Datamode/Ringline\",(\"off\",\"on\")\r\n" - "^SCFG: \"URC/Ringline\",(\"off\",\"local\",\"asc0\",\"wakeup\")\r\n" - "^SCFG: \"URC/Ringline/ActiveTime\",(\"0\",\"1\",\"2\",\"keep\")\r\n"; - - expected_bands = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), 9); - single = MM_MODEM_BAND_EGSM, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_DCS, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_PCS, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_G850, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_1, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_2, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_5, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_8, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_6, g_array_append_val (expected_bands, single); - - common_test_scfg (response, expected_bands, MM_MODEM_CHARSET_UNKNOWN, MM_CINTERION_MODEM_FAMILY_DEFAULT); - - g_array_unref (expected_bands); -} - -static void -test_scfg_ehs5 (void) -{ - GArray *expected_bands; - MMModemBand single; - const gchar *response = - "^SCFG: \"Audio/Loop\",(\"0\",\"1\")\r\n" - "^SCFG: \"Call/ECC\",(\"0\"-\"255\")\r\n" - "^SCFG: \"Call/Ecall/AckTimeout\",(\"0-2147483646\")\r\n" - "^SCFG: \"Call/Ecall/Callback\",(\"0\",\"1\")\r\n" - "^SCFG: \"Call/Ecall/CallbackTimeout\",(\"0-2147483646\")\r\n" - "^SCFG: \"Call/Ecall/Msd\",(\"280\")\r\n" - "^SCFG: \"Call/Ecall/Pullmode\",(\"0\",\"1\")\r\n" - "^SCFG: \"Call/Ecall/SessionTimeout\",(\"0-2147483646\")\r\n" - "^SCFG: \"Call/Ecall/StartTimeout\",(\"0-2147483646\")\r\n" - "^SCFG: \"Call/Speech/Codec\",(\"0\",\"1\")\r\n" - "^SCFG: \"GPRS/AutoAttach\",(\"disabled\",\"enabled\")\r\n" - "^SCFG: \"Gpio/mode/ASC1\",(\"std\",\"gpio\",\"rsv\")\r\n" - "^SCFG: \"Gpio/mode/DAI\",(\"std\",\"gpio\",\"rsv\")\r\n" - "^SCFG: \"Gpio/mode/DCD0\",(\"std\",\"gpio\",\"rsv\")\r\n" - "^SCFG: \"Gpio/mode/DSR0\",(\"std\",\"gpio\",\"rsv\")\r\n" - "^SCFG: \"Gpio/mode/DTR0\",(\"std\",\"gpio\",\"rsv\")\r\n" - "^SCFG: \"Gpio/mode/FSR\",(\"std\",\"gpio\",\"rsv\")\r\n" - "^SCFG: \"Gpio/mode/PULSE\",(\"std\",\"gpio\",\"rsv\")\r\n" - "^SCFG: \"Gpio/mode/PWM\",(\"std\",\"gpio\",\"rsv\")\r\n" - "^SCFG: \"Gpio/mode/RING0\",(\"std\",\"gpio\",\"rsv\")\r\n" - "^SCFG: \"Gpio/mode/SPI\",(\"std\",\"gpio\",\"rsv\")\r\n" - "^SCFG: \"Gpio/mode/SYNC\",(\"std\",\"gpio\",\"rsv\")\r\n" - "^SCFG: \"Ident/Manufacturer\",(25)\r\n" - "^SCFG: \"Ident/Product\",(25)\r\n" - "^SCFG: \"MEShutdown/Fso\",(\"0\",\"1\")\r\n" - "^SCFG: \"MEShutdown/sVsup/threshold\",(\"-4\",\"-3\",\"-2\",\"-1\",\"0\",\"1\",\"2\",\"3\",\"4\"),(\"0\")\r\n" - "^SCFG: \"MEopMode/CFUN\",(\"0\",\"1\"),(\"1\",\"4\")\r\n" - "^SCFG: \"MEopMode/Dormancy\",(\"0\",\"1\")\r\n" - "^SCFG: \"MEopMode/SoR\",(\"off\",\"on\")\r\n" - "^SCFG: \"Radio/Band\",(\"1\"-\"147\")\r\n" - "^SCFG: \"Radio/Mtpl\",(\"0\"-\"3\"),(\"1\"-\"8\"),(\"1\",\"8\"),(\"18\"-\"33\"),(\"18\"-\"27\")\r\n" - "^SCFG: \"Radio/Mtpl\",(\"0\"-\"3\"),(\"1\"-\"8\"),(\"16\",\"32\",\"64\",\"128\",\"256\"),(\"18\"-\"24\")\r\n" - "^SCFG: \"Radio/Mtpl\",(\"0\"-\"3\"),(\"1\"-\"8\"),(\"2\",\"4\"),(\"18\"-\"30\"),(\"18\"-\"26\")\r\n" - "^SCFG: \"Radio/OutputPowerReduction\",(\"0\",\"1\",\"2\",\"3\",\"4\")\r\n" - "^SCFG: \"Serial/Interface/Allocation\",(\"0\",\"1\",\"2\"),(\"0\",\"1\",\"2\")\r\n" - "^SCFG: \"Serial/USB/DDD\",(\"0\",\"1\"),(\"0\"),(4),(4),(4),(63),(63),(4)\r\n" - "^SCFG: \"Tcp/IRT\",(\"1\"-\"60\")\r\n" - "^SCFG: \"Tcp/MR\",(\"1\"-\"30\")\r\n" - "^SCFG: \"Tcp/OT\",(\"1\"-\"6000\")\r\n" - "^SCFG: \"Tcp/WithURCs\",(\"on\",\"off\")\r\n" - "^SCFG: \"Trace/Syslog/OTAP\",(\"0\",\"1\"),(\"null\",\"asc0\",\"asc1\",\"usb\",\"usb1\",\"usb2\",\"usb3\",\"usb4\",\"usb5\",\"file\",\"udp\",\"system\"),(\"1\"-\"65535\"),(125),(\"buffered\",\"secure\"),(\"off\",\"on\")\r\n" - "^SCFG: \"URC/Ringline\",(\"off\",\"local\",\"asc0\")\r\n" - "^SCFG: \"URC/Ringline/ActiveTime\",(\"0\",\"1\",\"2\")\r\n" - "^SCFG: \"Userware/Autostart\",(\"0\",\"1\")\r\n" - "^SCFG: \"Userware/Autostart/Delay\",(\"0\"-\"10000\")\r\n" - "^SCFG: \"Userware/DebugInterface\",(\"0\"-\"255\")|(\"FE80::\"-\"FE80::FFFFFFFFFFFFFFFF\"),(\"0\"-\"255\")|(\"FE80::\"-\"FE80::FFFFFFFFFFFFFFFF\"),(\"0\",\"1\")\r\n" - "^SCFG: \"Userware/DebugMode\",(\"off\",\"on\")\r\n" - "^SCFG: \"Userware/Passwd\",(\"0\"-\"8\")\r\n" - "^SCFG: \"Userware/Stdout\",(\"null\",\"asc0\",\"asc1\",\"usb\",\"usb1\",\"usb2\",\"usb3\",\"usb4\",\"usb5\",\"file\",\"udp\",\"system\"),(\"1\"-\"65535\"),(\"0\"-\"125\"),(\"buffered\",\"secure\"),(\"off\",\"on\")\r\n" - "^SCFG: \"Userware/Watchdog\",(\"0\",\"1\",\"2\")\r\n"; - - expected_bands = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), 4); - single = MM_MODEM_BAND_EGSM, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_DCS, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_1, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_8, g_array_append_val (expected_bands, single); - - common_test_scfg (response, expected_bands, MM_MODEM_CHARSET_UNKNOWN, MM_CINTERION_MODEM_FAMILY_DEFAULT); - - g_array_unref (expected_bands); -} - -static void -test_scfg_pls62_gsm (void) -{ - GArray *expected_bands; - MMModemBand single; - const gchar *response = - "^SCFG: \"MEopMode/Prov/AutoSelect\",(\"off\",\"on\")\r\n" - "^SCFG: \"MEopMode/Prov/Cfg\",(\"fallback\",\"attus\")\r\n" - "^SCFG: \"Serial/Ifc\",(\"Current\",\"ASC0\",\"USB0\",\"USB1\",\"USB2\",\"MUX1\",\"MUX2\",\"MUX3\",\"0\"),(\"0\",\"3\"),(\"1200\",\"2400\",\"4800\",\"9600\",\"19200\",\"38400\",\"57600\",\"115200\",\"230400\",\"460800\",\"500000\",\"750000\",\"921600\"),(\"0)\r\n" - "^SCFG: \"RemoteWakeUp/Ports\",(\"current\",\"powerup\"),(\"asc0\",\"acm1\",\"acm2\",\"acm3\",\"rmnet0\",\"rmnet1\")\r\n" - "^SCFG: \"Gpio/mode/ASC1\",(\"std\",\"gpio\",\"rsv\")\r\n" - "^SCFG: \"Gpio/mode/DCD0\",(\"std\",\"gpio\",\"rsv\")\r\n" - "^SCFG: \"Gpio/mode/DSR0\",(\"std\",\"gpio\",\"rsv\")\r\n" - "^SCFG: \"Gpio/mode/DTR0\",(\"std\",\"gpio\",\"rsv\")\r\n" - "^SCFG: \"Gpio/mode/FSR\",(\"std\",\"gpio\",\"rsv\")\r\n" - "^SCFG: \"Gpio/mode/PULSE\",(\"std\",\"gpio\",\"rsv\")\r\n" - "^SCFG: \"Gpio/mode/PWM\",(\"std\",\"gpio\",\"rsv\")\r\n" - "^SCFG: \"Gpio/mode/HWAKEUP\",(\"std\",\"gpio\",\"rsv\")\r\n" - "^SCFG: \"Gpio/mode/RING0\",(\"std\",\"gpio\",\"rsv\")\r\n" - "^SCFG: \"Gpio/mode/SPI\",(\"std\",\"gpio\",\"rsv\")\r\n" - "^SCFG: \"Gpio/mode/SYNC\",(\"std\",\"gpio\",\"rsv\")\r\n" - "^SCFG: \"GPRS/AutoAttach\",(\"disabled\",\"enabled\")\r\n" - "^SCFG: \"Ident/Manufacturer\",(25)\r\n" - "^SCFG: \"Ident/Product\",(25)\r\n" - "^SCFG: \"MEopMode/SoR\",(\"off\",\"on\")\r\n" - "^SCFG: \"MEopMode/CregRoam\",(\"0\",\"1\")\r\n" - "^SCFG: \"MeOpMode/SRPOM\",(\"0\",\"1\")\r\n" - "^SCFG: \"MEopMode/RingOnData\",(\"off\",\"on\")\r\n" - "^SCFG: \"MEShutdown/Fso\",(\"0\",\"1\")\r\n" - "^SCFG: \"MEShutdown/sVsup/threshold\",(\"-4\",\"-3\",\"-2\",\"-1\",\"0\",\"1\",\"2\",\"3\",\"4\"),(\"0\")\r\n" - "^SCFG: \"Radio/Band/2G\",(\"0x00000004\"-\"0x00000074\")\r\n" - "^SCFG: \"Radio/Band/3G\",(\"0x00000001\"-\"0x0004019B\")\r\n" - "^SCFG: \"Radio/Band/4G\",(\"0x00000001\"-\"0x080E08DF\")\r\n" - "^SCFG: \"Radio/Mtpl/2G\",(\"0\"-\"3\"),(\"1\"-\"8\"),(\"0x00000004\",\"0x00000010\",\"0x00000020\",\"0x00000040\"),,(\"18\"-\"33\"),(\"18\"-\"27\")\r\n" - "^SCFG: \"Radio/Mtpl/3G\",(\"0\"-\"3\"),(\"1\"-\"8\"),(\"0x00000001\",\"0x00000002\",\"0x00000008\",\"0x00000010\",\"0x00000080\",\"0x00000100\",\"0x00040000\"),,(\"18\"-\"24\")\r\n" - "^SCFG: \"Radio/Mtpl/4G\",(\"0\"-\"3\"),(\"1\"-\"8\"),(\"0x00000001\",\"0x00000002\",\"0x00000004\",\"0x00000008\",\"0x00000010\",\"0x00000040\",\"0x00000080\",\"0x00000800\",\"0x00020000\",\"0x00040000\",\"0x00080000\",\"0x08000000\"),,(\"18)\r\n" - "^SCFG: \"Radio/OutputPowerReduction\",(\"0\",\"1\",\"2\",\"3\",\"4\")\r\n" - "^SCFG: \"Serial/Interface/Allocation\",(\"0\",\"1\"),(\"0\",\"1\")\r\n" - "^SCFG: \"Serial/USB/DDD\",(\"0\",\"1\"),(\"0\"),(4),(4),(4),(63),(63),(4)\r\n" - "^SCFG: \"Tcp/IRT\",(\"1\"-\"60\")\r\n" - "^SCFG: \"Tcp/MR\",(\"2\"-\"30\")\r\n" - "^SCFG: \"Tcp/OT\",(\"1\"-\"6000\")\r\n" - "^SCFG: \"Tcp/WithURCs\",(\"on\",\"off\")\r\n" - "^SCFG: \"Trace/Syslog/OTAP\",(\"0\",\"1\"),(\"null\",\"asc0\",\"asc1\",\"usb\",\"usb1\",\"usb2\",\"file\",\"system\"),(\"1\"-\"65535\"),(125),(\"buffered\",\"secure\"),(\"off\",\"on\")\r\n" - "^SCFG: \"Urc/Ringline\",(\"off\",\"local\",\"asc0\",\"wakeup\")\r\n" - "^SCFG: \"Urc/Ringline/ActiveTime\",(\"0\",\"1\",\"2\")\r\n" - "^SCFG: \"Userware/Autostart\",(\"0\",\"1\")\r\n" - "^SCFG: \"Userware/Autostart/Delay\",(\"0\"-\"10000\")\r\n" - "^SCFG: \"Userware/DebugInterface\",(\"0\"-\"255\")|(\"FE80::\"-\"FE80::FFFFFFFFFFFFFFFF\"),(\"0\"-\"255\")|(\"FE80::\"-\"FE80::FFFFFFFFFFFFFFFF\"),(\"0\",\"1\")\r\n" - "^SCFG: \"Userware/DebugMode\",(\"off\",\"on\")\r\n" - "^SCFG: \"Userware/Passwd\",(\"0\"-\"8\")\r\n" - "^SCFG: \"Userware/Stdout\",(\"null\",\"asc0\",\"asc1\",\"usb\",\"usb1\",\"usb2\",\"file\",\"system\"),(\"1\"-\"65535\"),(\"0\"-\"125\"),(\"buffered\",\"secure\"),(\"off\",\"on\")\r\n" - "^SCFG: \"Userware/Watchdog\",(\"0\",\"1\",\"2\")\r\n" - "^SCFG: \"MEopMode/ExpectDTR\",(\"current\",\"powerup\"),(\"asc0\",\"acm1\",\"acm2\",\"acm3\")\r\n"; - - expected_bands = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), 23); - single = MM_MODEM_BAND_EGSM, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_DCS, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_PCS, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_G850, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_1, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_2, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_4, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_5, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_8, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_9, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_19, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_1, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_2, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_3, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_4, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_5, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_7, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_8, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_12, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_18, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_19, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_20, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_28, g_array_append_val (expected_bands, single); - - common_test_scfg (response, expected_bands, MM_MODEM_CHARSET_GSM, MM_CINTERION_MODEM_FAMILY_IMT); - - g_array_unref (expected_bands); -} - -static void -test_scfg_pls62_ucs2 (void) -{ - GArray *expected_bands; - MMModemBand single; - const gchar *response = - "^SCFG: \"MEopMode/Prov/AutoSelect\",(\"006F00660066\",\"006F006E\")\r\n" - "^SCFG: \"MEopMode/Prov/Cfg\",(\"fallback\",\"attus\")\r\n" - "^SCFG: \"Serial/Ifc\",(\"00430075007200720065006E0074\",\"0041005300430030\",\"0055005300420030\",\"0055005300420031\",\"0055005300420032\",\"004D005500580031\",\"004D005500580032\",\"004D005500580033\",\"0030\"),(\"0030\",\"0033)\r\n" - "^SCFG: \"RemoteWakeUp/Ports\",(\"00630075007200720065006E0074\",\"0070006F00770065007200750070\"),(\"0061007300630030\",\"00610063006D0031\",\"00610063006D0032\",\"00610063006D0033\",\"0072006D006E006500740030\",\"0072006D0)\r\n" - "^SCFG: \"Gpio/mode/ASC1\",(\"007300740064\",\"006700700069006F\",\"007200730076\")\r\n" - "^SCFG: \"Gpio/mode/DCD0\",(\"007300740064\",\"006700700069006F\",\"007200730076\")\r\n" - "^SCFG: \"Gpio/mode/DSR0\",(\"007300740064\",\"006700700069006F\",\"007200730076\")\r\n" - "^SCFG: \"Gpio/mode/DTR0\",(\"007300740064\",\"006700700069006F\",\"007200730076\")\r\n" - "^SCFG: \"Gpio/mode/FSR\",(\"007300740064\",\"006700700069006F\",\"007200730076\")\r\n" - "^SCFG: \"Gpio/mode/PULSE\",(\"007300740064\",\"006700700069006F\",\"007200730076\")\r\n" - "^SCFG: \"Gpio/mode/PWM\",(\"007300740064\",\"006700700069006F\",\"007200730076\")\r\n" - "^SCFG: \"Gpio/mode/HWAKEUP\",(\"007300740064\",\"006700700069006F\",\"007200730076\")\r\n" - "^SCFG: \"Gpio/mode/RING0\",(\"007300740064\",\"006700700069006F\",\"007200730076\")\r\n" - "^SCFG: \"Gpio/mode/SPI\",(\"007300740064\",\"006700700069006F\",\"007200730076\")\r\n" - "^SCFG: \"Gpio/mode/SYNC\",(\"007300740064\",\"006700700069006F\",\"007200730076\")\r\n" - "^SCFG: \"GPRS/AutoAttach\",(\"00640069007300610062006C00650064\",\"0065006E00610062006C00650064\")\r\n" - "^SCFG: \"Ident/Manufacturer\",(25)\r\n" - "^SCFG: \"Ident/Product\",(25)\r\n" - "^SCFG: \"MEopMode/SoR\",(\"006F00660066\",\"006F006E\")\r\n" - "^SCFG: \"MEopMode/CregRoam\",(\"0030\",\"0031\")\r\n" - "^SCFG: \"MeOpMode/SRPOM\",(\"0030\",\"0031\")\r\n" - "^SCFG: \"MEopMode/RingOnData\",(\"006F00660066\",\"006F006E\")\r\n" - "^SCFG: \"MEShutdown/Fso\",(\"0030\",\"0031\")\r\n" - "^SCFG: \"MEShutdown/sVsup/threshold\",(\"002D0034\",\"002D0033\",\"002D0032\",\"002D0031\",\"0030\",\"0031\",\"0032\",\"0033\",\"0034\"),(\"0030\")\r\n" - "^SCFG: \"Radio/Band/2G\",(\"0030007800300030003000300030003000300034\"-\"0030007800300030003000300030003000370034\")\r\n" - "^SCFG: \"Radio/Band/3G\",(\"0030007800300030003000300030003000300031\"-\"0030007800300030003000340030003100390042\")\r\n" - "^SCFG: \"Radio/Band/4G\",(\"0030007800300030003000300030003000300031\"-\"0030007800300038003000450030003800440046\")\r\n" - "^SCFG: \"Radio/Mtpl/2G\",(\"00300022002D00220033\"),(\"00310022002D00220038\"),(\"00300078003000300030003000300030003000340022002C002200300078003000300030003000300030003100300022002C0022003000780030003000300030003)\r\n" - "^SCFG: \"Radio/Mtpl/3G\",(\"00300022002D00220033\"),(\"00310022002D00220038\"),(\"00300078003000300030003000300030003000310022002C002200300078003000300030003000300030003000320022002C0022003000780030003000300030003)\r\n" - "^SCFG: \"Radio/Mtpl/4G\",(\"00300022002D00220033\"),(\"00310022002D00220038\"),(\"00310022002D00220038\"),,(\"003100380022002D002200320033\")\r\n" - "^SCFG: \"Radio/OutputPowerReduction\",(\"0030\",\"0031\",\"0032\",\"0033\",\"0034\")\r\n" - "^SCFG: \"Serial/Interface/Allocation\",(\"0030\",\"0031\"),(\"0030\",\"0031\")\r\n" - "^SCFG: \"Serial/USB/DDD\",(\"0030\",\"0031\"),(\"0030\"),(4),(4),(4),(63),(63),(4)\r\n" - "^SCFG: \"Tcp/IRT\",(\"0031\"-\"00360030\")\r\n" - "^SCFG: \"Tcp/MR\",(\"0032\"-\"00330030\")\r\n" - "^SCFG: \"Tcp/OT\",(\"0031\"-\"0036003000300030\")\r\n" - "^SCFG: \"Tcp/WithURCs\",(\"006F006E\",\"006F00660066\")\r\n" - "^SCFG: \"Trace/Syslog/OTAP\",(\"0030\",\"0031\"),(\"006E0075006C006C\",\"0061007300630030\",\"0061007300630031\",\"007500730062\",\"0075007300620031\",\"0075007300620032\",\"00660069006C0065\",\"00730079007300740065006D\"),(\"003)\r\n" - "^SCFG: \"Urc/Ringline\",(\"006F00660066\",\"006C006F00630061006C\",\"0061007300630030\",\"00770061006B006500750070\")\r\n" - "^SCFG: \"Urc/Ringline/ActiveTime\",(\"0030\",\"0031\",\"0032\")\r\n" - "^SCFG: \"Userware/Autostart\",(\"0030\",\"0031\")\r\n" - "^SCFG: \"Userware/Autostart/Delay\",(\"00300022002D002200310030003000300030\")\r\n" - "^SCFG: \"Userware/DebugInterface\",(\"0030\"-\"003200350035\")|(\"0046004500380030003A003A\"-\"0046004500380030003A003A0046004600460046004600460046004600460046004600460046004600460046\"),(\"0030\"-\"003200350035\")|(\"004)\r\n" - "^SCFG: \"Userware/DebugMode\",(\"006F00660066\",\"006F006E\")\r\n" - "^SCFG: \"Userware/Passwd\",(\"0030\"-\"0038\")\r\n" - "^SCFG: \"Userware/Stdout\",(\"006E0075006C006C\",\"0061007300630030\",\"0061007300630031\",\"007500730062\",\"0075007300620031\",\"0075007300620032\",\"00660069006C0065\",\"00730079007300740065006D\"),(\"0031\"-\"00360035003500)\r\n" - "^SCFG: \"Userware/Watchdog\",(\"0030\",\"0031\",\"0032\")\r\n" - "^SCFG: \"MEopMode/ExpectDTR\",(\"00630075007200720065006E0074\",\"0070006F00770065007200750070\"),(\"0061007300630030\",\"00610063006D0031\",\"00610063006D0032\",\"00610063006D0033\")\r\n"; - - expected_bands = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), 23); - single = MM_MODEM_BAND_EGSM, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_DCS, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_PCS, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_G850, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_1, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_2, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_4, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_5, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_8, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_9, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_19, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_1, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_2, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_3, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_4, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_5, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_7, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_8, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_12, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_18, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_19, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_20, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_28, g_array_append_val (expected_bands, single); - - common_test_scfg (response, expected_bands, MM_MODEM_CHARSET_UCS2, MM_CINTERION_MODEM_FAMILY_IMT); - - g_array_unref (expected_bands); -} - -static void -test_scfg_alas5 (void) -{ - GArray *expected_bands; - MMModemBand single; - const gchar *response = - "^SCFG: \"Audio/Loop\",(\"0\",\"1\")\r\n" - "^SCFG: \"Audio/SvTone\",(\"0-2047\")\r\n" - "^SCFG: \"Call/Ecall/AckTimeout\",(\"0-60000\")\r\n" - "^SCFG: \"Call/Ecall/BlockSMSPP\",(\"0\",\"1\")\r\n" - "^SCFG: \"Call/Ecall/Callback\",(\"0\",\"1\")\r\n" - "^SCFG: \"Call/Ecall/CallbackTimeout\",(\"0-86400000\")\r\n" - "^SCFG: \"Call/Ecall/Force\",(\"0\",\"1\",\"2\")\r\n" - "^SCFG: \"Call/Ecall/Msd\",(280)\r\n" - "^SCFG: \"Call/Ecall/Pullmode\",(\"0\",\"1\")\r\n" - "^SCFG: \"Call/Ecall/SessionTimeout\",(\"0-300000\")\r\n" - "^SCFG: \"Call/Ecall/StartTimeout\",(\"0-600000\")\r\n" - "^SCFG: \"Call/ECC\",(\"0\"-\"255\")\r\n" - "^SCFG: \"Call/Speech/Codec\",(\"0\",\"2\")\r\n" - "^SCFG: \"GPRS/Auth\",(\"0\",\"1\",\"2\")\r\n" - "^SCFG: \"GPRS/AutoAttach\",(\"disabled\",\"enabled\")\r\n" - "^SCFG: \"GPRS/MTU/Mode\",(\"0-1\")\r\n" - "^SCFG: \"GPRS/MTU/Size\",(\"1280-4096\")\r\n" - "^SCFG: \"MEopMode/CFUN\",(\"0\",\"1\")\r\n" - "^SCFG: \"MEopMode/CregRoam\",(\"0\",\"1\")\r\n" - "^SCFG: \"MEopMode/Dormancy\",(\"0\",\"1\",\"9\")\r\n" - "^SCFG: \"MEopMode/DTM/Mode\",(\"0\",\"1\",\"2\")\r\n" - "^SCFG: \"MEopMode/ExpectDTR\",(\"current\",\"powerup\"),(\"acm0\",\"acm1\",\"acm2\",\"acm3\",\"diag\",\"mbim\",\"asc0\")\r\n" - "^SCFG: \"MEopMode/FGI/Split\",(\"0\",\"1\")\r\n" - "^SCFG: \"MEopMode/IMS\",(\"0\",\"1\")\r\n" - "^SCFG: \"MEopMode/NonBlock/Cops\",(\"0\",\"1\")\r\n" - "^SCFG: \"MEopMode/PowerMgmt/LCI\",(\"disabled\",\"enabled\"),(\"GPIO1\",\"GPIO3\",\"GPIO4\",\"GPIO5\",\"GPIO6\",\"GPIO7\",\"GPIO8\",\"GPIO11\",\"GPIO12\",\"GPIO13\",\"GPIO14\",\"GPIO15\",\"GPIO16\",\"GPIO17\",\"GPIO22\")\r\n" - "^SCFG: \"MEopMode/Prov/AutoFallback\",(\"on\",\"off\")\r\n" - "^SCFG: \"MEopMode/Prov/AutoSelect\",(\"on\",\"off\")\r\n" - "^SCFG: \"MEopMode/Prov/Cfg\",(\"vdfde\",\"tmode\",\"clarobr\",\"telenorno\",\"telenorse\",\"vdfpt\",\"fallb3gpp*\",\"vdfww\",\"vdfes\",\"swisscomch\",\"eeuk\",\"orangero\",\"orangees\",\"tefde\",\"telenordk\",\"timit\",\"tn1de\",\"tefes\",\"tels)\r\n" - "^SCFG: \"MEopMode/PwrSave\",(\"disabled\",\"enabled\"),(\"0-36000\"),(\"0-36000\"),(\"CPU-A\",\"CPU-M\"),(\"powerup\",\"current\")\r\n" - "^SCFG: \"MEopMode/SRPOM\",(\"0\",\"1\")\r\n" - "^SCFG: \"MEopMode/USB/KeepData\",(\"current\",\"powerup\"),(\"acm0\",\"acm1\",\"acm2\",\"acm3\",\"diag\",\"mbim\",\"asc0\")\r\n" - "^SCFG: \"MEShutdown/OnIgnition\",(\"on\",\"off\")\r\n" - "^SCFG: \"MEShutdown/Timer\",(\"off\",\"0\"-\"525600\")\r\n" - "^SCFG: \"Misc/CId\",(290)\r\n" - "^SCFG: \"Radio/Band/2G\",(\"00000001-0000000f\"),,(\"0\",\"1\")\r\n" - "^SCFG: \"Radio/Band/3G\",(\"00000001-000400b5\"),,(\"0\",\"1\")\r\n" - "^SCFG: \"Radio/Band/4G\",(\"00000001-8a0e00d5\"),(\"00000002-000001e2\"),(\"0\",\"1\")\r\n" - "^SCFG: \"Radio/CNS\",(\"0\",\"1\")\r\n" - "^SCFG: \"Radio/Mtpl\",(\"0-1\"),(\"1-8\")\r\n" - "^SCFG: \"Radio/Mtpl/2G\",(\"2-3\"),(\"1-8\"),(\"00000001-0000000f\"),,(\"18-33\"),(\"18-27\")\r\n" - "^SCFG: \"Radio/Mtpl/3G\",(\"2-3\"),(\"1-8\"),(\"00000001-000000b5\"),,(\"18-24\")\r\n" - "^SCFG: \"Radio/Mtpl/4G\",(\"2-3\"),(\"1-8\"),(\"00000001-8a0e00d5\"),(\"00000002-000000e2\"),(\"18-24\")\r\n" - "^SCFG: \"Radio/OutputPowerReduction\",(\"4\"-\"8\")\r\n" - "^SCFG: \"RemoteWakeUp/Event/ASC\",(\"none\",\"GPIO1\",\"GPIO3\",\"GPIO4\",\"GPIO5\",\"GPIO6\",\"GPIO7\",\"GPIO8\",\"GPIO11\",\"GPIO12\",\"GPIO13\",\"GPIO14\",\"GPIO15\",\"GPIO16\",\"GPIO17\",\"GPIO22\")\r\n" - "^SCFG: \"RemoteWakeUp/Event/URC\",(\"none\",\"GPIO1\",\"GPIO3\",\"GPIO4\",\"GPIO5\",\"GPIO6\",\"GPIO7\",\"GPIO8\",\"GPIO11\",\"GPIO12\",\"GPIO13\",\"GPIO14\",\"GPIO15\",\"GPIO16\",\"GPIO17\",\"GPIO22\")\r\n" - "^SCFG: \"RemoteWakeUp/Event/USB\",(\"none\",\"GPIO1\",\"GPIO3\",\"GPIO4\",\"GPIO5\",\"GPIO6\",\"GPIO7\",\"GPIO8\",\"GPIO11\",\"GPIO12\",\"GPIO13\",\"GPIO14\",\"GPIO15\",\"GPIO16\",\"GPIO17\",\"GPIO22\")\r\n" - "^SCFG: \"RemoteWakeUp/Ports\",(\"current\",\"powerup\"),(\"acm0\",\"acm1\",\"acm2\",\"acm3\",\"diag\",\"mbim\",\"asc0\")\r\n" - "^SCFG: \"RemoteWakeUp/Pulse\",(\"1\"-\"100\")\r\n" - "^SCFG: \"Serial/USB/DDD\",(\"0-1\"),(\"0\"),(\"0001-ffff\"),(\"0000-ffff\"),(\"0000-ffff\"),(63),(63),(4)\r\n" - "^SCFG: \"SIM/CS\",(\"NOSIM\",\"SIM1\",\"SIM2\")\r\n" - "^SCFG: \"SMS/4GPREF\",(\"IMS\",\"CSPS\")\r\n" - "^SCFG: \"SMS/AutoAck\",(\"0\",\"1\")\r\n" - "^SCFG: \"SMS/RETRM\",(\"1-45\")\r\n" - "^SCFG: \"URC/Ringline\",(\"off\",\"local\",\"asc0\")\r\n" - "^SCFG: \"URC/Ringline/ActiveTime\",(\"2\",\"on\",\"off\")\r\n"; - - expected_bands = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), 23); - single = MM_MODEM_BAND_EGSM, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_DCS, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_PCS, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_G850, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_1, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_3, g_array_append_val (expected_bands, single); // - single = MM_MODEM_BAND_UTRAN_5, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_6, g_array_append_val (expected_bands, single); // - single = MM_MODEM_BAND_UTRAN_8, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_19, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_1, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_3, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_5, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_7, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_8, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_18, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_19, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_20, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_26, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_28, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_38, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_39, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_40, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_41, g_array_append_val (expected_bands, single); - - common_test_scfg (response, expected_bands, MM_MODEM_CHARSET_GSM, MM_CINTERION_MODEM_FAMILY_DEFAULT); - - g_array_unref (expected_bands); -} - -/*****************************************************************************/ -/* Test ^SCFG responses */ - -static void -common_test_scfg_response (const gchar *response, - MMModemCharset charset, - GArray *expected_bands, - MMCinterionModemFamily modem_family, - MMCinterionRadioBandFormat rbf) -{ - GArray *bands = NULL; - gchar *expected_bands_str; - gchar *bands_str; - GError *error = NULL; - gboolean res; - - res = mm_cinterion_parse_scfg_response (response, modem_family, charset, &bands, rbf, &error); - g_assert_no_error (error); - g_assert (res == TRUE); - g_assert (bands != NULL); - - mm_common_bands_garray_sort (bands); - mm_common_bands_garray_sort (expected_bands); - - expected_bands_str = mm_common_build_bands_string ((const MMModemBand *)(gconstpointer)expected_bands->data, - expected_bands->len); - bands_str = mm_common_build_bands_string ((const MMModemBand *)(gconstpointer)bands->data, - bands->len); - - /* Instead of comparing the array one by one, compare the strings built from the mask - * (we get a nicer error if it fails) */ - g_assert_cmpstr (bands_str, ==, expected_bands_str); - - g_free (bands_str); - g_free (expected_bands_str); - g_array_unref (bands); -} - -static void -test_scfg_response_2g (void) -{ - GArray *expected_bands; - MMModemBand single; - const gchar *response = - "^SCFG: \"Radio/Band\",\"3\",\"3\"\r\n" - "\r\n"; - - expected_bands = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), 9); - single = MM_MODEM_BAND_EGSM, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_DCS, g_array_append_val (expected_bands, single); - - common_test_scfg_response (response, MM_MODEM_CHARSET_UNKNOWN, expected_bands, MM_CINTERION_MODEM_FAMILY_DEFAULT, MM_CINTERION_RADIO_BAND_FORMAT_SINGLE); - - g_array_unref (expected_bands); -} - -static void -test_scfg_response_3g (void) -{ - GArray *expected_bands; - MMModemBand single; - const gchar *response = - "^SCFG: \"Radio/Band\",127\r\n" - "\r\n"; - - expected_bands = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), 9); - single = MM_MODEM_BAND_EGSM, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_DCS, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_PCS, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_G850, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_1, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_2, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_5, g_array_append_val (expected_bands, single); - - common_test_scfg_response (response, MM_MODEM_CHARSET_UNKNOWN, expected_bands, MM_CINTERION_MODEM_FAMILY_DEFAULT, MM_CINTERION_RADIO_BAND_FORMAT_SINGLE); - - g_array_unref (expected_bands); -} - -static void -test_scfg_response_pls62_gsm (void) -{ - GArray *expected_bands; - MMModemBand single; - const gchar *response = - "^SCFG: \"MEopMode/Prov/AutoSelect\",\"off\"\r\n" - "^SCFG: \"MEopMode/Prov/Cfg\",\"attus\"\r\n" - "^SCFG: \"Serial/Ifc\",\"0\"\r\n" - "^SCFG: \"RemoteWakeUp/Ports\",\"current\"\r\n" - "^SCFG: \"RemoteWakeUp/Ports\",\"powerup\"\r\n" - "^SCFG: \"Gpio/mode/ASC1\",\"gpio\"\r\n" - "^SCFG: \"Gpio/mode/DCD0\",\"gpio\"\r\n" - "^SCFG: \"Gpio/mode/DSR0\",\"gpio\"\r\n" - "^SCFG: \"Gpio/mode/DTR0\",\"gpio\"\r\n" - "^SCFG: \"Gpio/mode/FSR\",\"gpio\"\r\n" - "^SCFG: \"Gpio/mode/PULSE\",\"gpio\"\r\n" - "^SCFG: \"Gpio/mode/PWM\",\"gpio\"\r\n" - "^SCFG: \"Gpio/mode/HWAKEUP\",\"gpio\"\r\n" - "^SCFG: \"Gpio/mode/RING0\",\"gpio\"\r\n" - "^SCFG: \"Gpio/mode/SPI\",\"gpio\"\r\n" - "^SCFG: \"Gpio/mode/SYNC\",\"gpio\"\r\n" - "^SCFG: \"GPRS/AutoAttach\",\"enabled\"\r\n" - "^SCFG: \"Ident/Manufacturer\",\"Cinterion\"\r\n" - "^SCFG: \"Ident/Product\",\"PLS62-W\"\r\n" - "^SCFG: \"MEopMode/SoR\",\"off\"\r\n" - "^SCFG: \"MEopMode/CregRoam\",\"0\"\r\n" - "^SCFG: \"MeOpMode/SRPOM\",\"0\"\r\n" - "^SCFG: \"MEopMode/RingOnData\",\"off\"\r\n" - "^SCFG: \"MEShutdown/Fso\",\"0\"\r\n" - "^SCFG: \"MEShutdown/sVsup/threshold\",\"0\",\"0\"\r\n" - "^SCFG: \"Radio/Band/2G\",\"0x00000014\"\r\n" - "^SCFG: \"Radio/Band/3G\",\"0x00000182\"\r\n" - "^SCFG: \"Radio/Band/4G\",\"0x080E0000\"\r\n" - "^SCFG: \"Radio/Mtpl/2G\",\"0\"\r\n" - "^SCFG: \"Radio/Mtpl/3G\",\"0\"\r\n" - "^SCFG: \"Radio/Mtpl/4G\",\"0\"\r\n" - "^SCFG: \"Radio/OutputPowerReduction\",\"4\"\r\n" - "^SCFG: \"Serial/Interface/Allocation\",\"0\",\"0\"\r\n" - "^SCFG: \"Serial/USB/DDD\",\"0\",\"0\",\"0409\",\"1E2D\",\"005B\",\"Cinterion Wireless Modules\",\"PLSx\",\"\"\r\n" - "^SCFG: \"Tcp/IRT\",\"3\"\r\n" - "^SCFG: \"Tcp/MR\",\"10\"\r\n" - "^SCFG: \"Tcp/OT\",\"6000\"\r\n" - "^SCFG: \"Tcp/WithURCs\",\"on\"\r\n" - "^SCFG: \"Trace/Syslog/OTAP\",\"0\"\r\n" - "^SCFG: \"Urc/Ringline\",\"local\"\r\n" - "^SCFG: \"Urc/Ringline/ActiveTime\",\"2\"\r\n" - "^SCFG: \"Userware/Autostart\",\"0\"\r\n" - "^SCFG: \"Userware/Autostart/Delay\",\"0\"\r\n" - "^SCFG: \"Userware/DebugInterface\",\"0.0.0.0\",\"0.0.0.0\",\"0\"\r\n" - "^SCFG: \"Userware/DebugMode\",\"off\"\r\n" - "^SCFG: \"Userware/Passwd\",\r\n" - "^SCFG: \"Userware/Stdout\",\"null\",,,,\"off\"\r\n" - "^SCFG: \"Userware/Watchdog\",\"0\"\r\n" - "^SCFG: \"MEopMode/ExpectDTR\",\"current\"\r\n" - "^SCFG: \"MEopMode/ExpectDTR\",\"powerup\"\r\n"; - - expected_bands = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), 9); - single = MM_MODEM_BAND_EGSM, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_DCS, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_2, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_8, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_9, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_18, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_19, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_20, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_28, g_array_append_val (expected_bands, single); - - common_test_scfg_response (response, MM_MODEM_CHARSET_GSM, expected_bands, MM_CINTERION_MODEM_FAMILY_IMT, MM_CINTERION_RADIO_BAND_FORMAT_MULTIPLE); - - g_array_unref (expected_bands); -} - -static void -test_scfg_response_pls62_ucs2 (void) -{ - GArray *expected_bands; - MMModemBand single; - const gchar *response = - "^SCFG: \"MEopMode/Prov/AutoSelect\",\"006F00660066\"\r\n" - "^SCFG: \"MEopMode/Prov/Cfg\",\"00610074007400750073\"\r\n" - "^SCFG: \"Serial/Ifc\",\"0\"\r\n" - "^SCFG: \"RemoteWakeUp/Ports\",\"00630075007200720065006E0074\"\r\n" - "^SCFG: \"RemoteWakeUp/Ports\",\"0070006F00770065007200750070\"\r\n" - "^SCFG: \"Gpio/mode/ASC1\",\"006700700069006F\"\r\n" - "^SCFG: \"Gpio/mode/DCD0\",\"006700700069006F\"\r\n" - "^SCFG: \"Gpio/mode/DSR0\",\"006700700069006F\"\r\n" - "^SCFG: \"Gpio/mode/DTR0\",\"006700700069006F\"\r\n" - "^SCFG: \"Gpio/mode/FSR\",\"006700700069006F\"\r\n" - "^SCFG: \"Gpio/mode/PULSE\",\"006700700069006F\"\r\n" - "^SCFG: \"Gpio/mode/PWM\",\"006700700069006F\"\r\n" - "^SCFG: \"Gpio/mode/HWAKEUP\",\"006700700069006F\"\r\n" - "^SCFG: \"Gpio/mode/RING0\",\"006700700069006F\"\r\n" - "^SCFG: \"Gpio/mode/SPI\",\"006700700069006F\"\r\n" - "^SCFG: \"Gpio/mode/SYNC\",\"006700700069006F\"\r\n" - "^SCFG: \"GPRS/AutoAttach\",\"0065006E00610062006C00650064\"\r\n" - "^SCFG: \"Ident/Manufacturer\",\"Cinterion\"\r\n" - "^SCFG: \"Ident/Product\",\"PLS62-W\"\r\n" - "^SCFG: \"MEopMode/SoR\",\"006F00660066\"\r\n" - "^SCFG: \"MEopMode/CregRoam\",\"0030\"\r\n" - "^SCFG: \"MeOpMode/SRPOM\",\"0030\"\r\n" - "^SCFG: \"MEopMode/RingOnData\",\"006F00660066\"\r\n" - "^SCFG: \"MEShutdown/Fso\",\"0030\"\r\n" - "^SCFG: \"MEShutdown/sVsup/threshold\",\"0030\",\"0030\"\r\n" - "^SCFG: \"Radio/Band/2G\",\"0030007800300030003000300030003000310034\"\r\n" - "^SCFG: \"Radio/Band/3G\",\"0030007800300030003000300030003100380032\"\r\n" - "^SCFG: \"Radio/Band/4G\",\"0030007800300038003000450030003000300030\"\r\n" - "^SCFG: \"Radio/Mtpl/2G\",\"0030\"\r\n" - "^SCFG: \"Radio/Mtpl/3G\",\"0030\"\r\n" - "^SCFG: \"Radio/Mtpl/4G\",\"0030\"\r\n" - "^SCFG: \"Radio/OutputPowerReduction\",\"0034\"\r\n" - "^SCFG: \"Serial/Interface/Allocation\",\"0030\",\"0030\"\r\n" - "^SCFG: \"Serial/USB/DDD\",\"0030\",\"0030\",\"0030003400300039\",\"0031004500320044\",\"0030003000350042\",\"00430069006E0074006500720069006F006E00200057006900720065006C0065007300730020004D006F00640075006C00650073\",\"005\"\r\n" - "^SCFG: \"Tcp/IRT\",\"0033\"\r\n" - "^SCFG: \"Tcp/MR\",\"00310030\"\r\n" - "^SCFG: \"Tcp/OT\",\"0036003000300030\"\r\n" - "^SCFG: \"Tcp/WithURCs\",\"006F006E\"\r\n" - "^SCFG: \"Trace/Syslog/OTAP\",\"0030\"\r\n" - "^SCFG: \"Urc/Ringline\",\"006C006F00630061006C\"\r\n" - "^SCFG: \"Urc/Ringline/ActiveTime\",\"0032\"\r\n" - "^SCFG: \"Userware/Autostart\",\"0030\"\r\n" - "^SCFG: \"Userware/Autostart/Delay\",\"0030\"\r\n" - "^SCFG: \"Userware/DebugInterface\",\"0030002E0030002E0030002E0030\",\"0030002E0030002E0030002E0030\",\"0030\"\r\n" - "^SCFG: \"Userware/DebugMode\",\"006F00660066\"\r\n" - "^SCFG: \"Userware/Passwd\",\r\n" - "^SCFG: \"Userware/Stdout\",\"006E0075006C006C\",,,,\"006F00660066\"\r\n" - "^SCFG: \"Userware/Watchdog\",\"0030\"\r\n" - "^SCFG: \"MEopMode/ExpectDTR\",\"00630075007200720065006E0074\"\r\n" - "^SCFG: \"MEopMode/ExpectDTR\",\"0070006F00770065007200750070\"\r\n"; - - expected_bands = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), 9); - single = MM_MODEM_BAND_EGSM, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_DCS, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_2, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_8, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_9, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_18, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_19, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_20, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_28, g_array_append_val (expected_bands, single); - - common_test_scfg_response (response, MM_MODEM_CHARSET_UCS2, expected_bands, MM_CINTERION_MODEM_FAMILY_IMT, MM_CINTERION_RADIO_BAND_FORMAT_MULTIPLE); - - g_array_unref (expected_bands); -} - -static void -test_scfg_response_alas5 (void) -{ - GArray *expected_bands; - MMModemBand single; - const gchar *response = - "^SCFG: \"Audio/Loop\",\"0\"\r\n" - "^SCFG: \"Audio/SvTone\",\"0\"\r\n" - "^SCFG: \"Call/Ecall/AckTimeout\",\"5000\"\r\n" - "^SCFG: \"Call/Ecall/BlockSMSPP\",\"0\"\r\n" - "^SCFG: \"Call/Ecall/Callback\",\"0\"\r\n" - "^SCFG: \"Call/Ecall/CallbackTimeout\",\"43200000\"\r\n" - "^SCFG: \"Call/Ecall/Force\",\"1\"\r\n" - "^SCFG: \"Call/Ecall/Msd\",\"\"\r\n" - "^SCFG: \"Call/Ecall/Pullmode\",\"0\"\r\n" - "^SCFG: \"Call/Ecall/SessionTimeout\",\"20000\"\r\n" - "^SCFG: \"Call/Ecall/StartTimeout\",\"5000\"\r\n" - "^SCFG: \"Call/ECC\",\"0\"\r\n" - "^SCFG: \"Call/Speech/Codec\",\"0\"\r\n" - "^SCFG: \"GPRS/Auth\",\"2\"\r\n" - "^SCFG: \"GPRS/AutoAttach\",\"enabled\"\r\n" - "^SCFG: \"GPRS/MTU/Mode\",\"0\"\r\n" - "^SCFG: \"GPRS/MTU/Size\",1500\r\n" - "^SCFG: \"MEopMode/CFUN\",\"1\",\"1\"\r\n" - "^SCFG: \"MEopMode/CregRoam\",\"0\"\r\n" - "^SCFG: \"MEopMode/Dormancy\",\"0\",\"0\"\r\n" - "^SCFG: \"MEopMode/DTM/Mode\",\"2\"\r\n" - "^SCFG: \"MEopMode/ExpectDTR\",\"current\",\"acm0\",\"acm1\",\"acm2\",\"acm3\",\"mbim\",\"asc0\"\r\n" - "^SCFG: \"MEopMode/ExpectDTR\",\"powerup\",\"acm0\",\"acm1\",\"acm2\",\"acm3\",\"mbim\",\"asc0\"\r\n" - "^SCFG: \"MEopMode/FGI/Split\",\"1\"\r\n" - "^SCFG: \"MEopMode/IMS\",\"1\"\r\n" - "^SCFG: \"MEopMode/NonBlock/Cops\",\"0\"\r\n" - "^SCFG: \"MEopMode/PowerMgmt/LCI\",\"disabled\"\r\n" - "^SCFG: \"MEopMode/Prov/AutoFallback\",\"off\"\r\n" - "^SCFG: \"MEopMode/Prov/AutoSelect\",\"on\"\r\n" - "^SCFG: \"MEopMode/Prov/Cfg\",\"vdfde\"\r\n" - "^SCFG: \"MEopMode/PwrSave\",\"enabled\",\"52\",\"50\",\"CPU-A\",\"powerup\"\r\n" - "^SCFG: \"MEopMode/PwrSave\",\"enabled\",\"52\",\"50\",\"CPU-A\",\"current\"\r\n" - "^SCFG: \"MEopMode/PwrSave\",\"enabled\",\"0\",\"0\",\"CPU-M\",\"powerup\"\r\n" - "^SCFG: \"MEopMode/PwrSave\",\"enabled\",\"0\",\"0\",\"CPU-M\",\"current\"\r\n" - "^SCFG: \"MEopMode/SRPOM\",\"0\"\r\n" - "^SCFG: \"MEopMode/USB/KeepData\",\"current\",\"acm0\",\"acm1\",\"acm2\",\"acm3\",\"diag\",\"mbim\",\"asc0\"\r\n" - "^SCFG: \"MEopMode/USB/KeepData\",\"powerup\",\"acm0\",\"acm1\",\"acm2\",\"acm3\",\"diag\",\"mbim\",\"asc0\"\r\n" - "^SCFG: \"MEShutdown/OnIgnition\",\"off\"\r\n" - "^SCFG: \"MEShutdown/Timer\",\"off\"\r\n" - "^SCFG: \"Misc/CId\",\"\"\r\n" - "^SCFG: \"Radio/Band/2G\",\"0000000f\"\r\n" - "^SCFG: \"Radio/Band/3G\",\"000400b5\"\r\n" - "^SCFG: \"Radio/Band/4G\",\"8a0e00d5\",\"000000e2\"\r\n" - "^SCFG: \"Radio/CNS\",\"0\"\r\n" - "^SCFG: \"Radio/Mtpl\",\"0\"\r\n" - "^SCFG: \"Radio/Mtpl/2G\",\"0\"\r\n" - "^SCFG: \"Radio/Mtpl/3G\",\"0\"\r\n" - "^SCFG: \"Radio/Mtpl/4G\",\"0\"\r\n" - "^SCFG: \"Radio/OutputPowerReduction\",\"4\"\r\n" - "^SCFG: \"RemoteWakeUp/Event/ASC\",\"none\"\r\n" - "^SCFG: \"RemoteWakeUp/Event/URC\",\"none\"\r\n" - "^SCFG: \"RemoteWakeUp/Event/USB\",\"GPIO4\"\r\n" - "^SCFG: \"RemoteWakeUp/Ports\",\"current\",\"acm0\",\"acm1\",\"acm2\",\"acm3\",\"diag\",\"mbim\",\"asc0\"\r\n" - "^SCFG: \"RemoteWakeUp/Ports\",\"powerup\",\"acm0\",\"acm1\",\"acm2\",\"acm3\",\"diag\",\"mbim\",\"asc0\"\r\n" - "^SCFG: \"RemoteWakeUp/Pulse\",\"10\"\r\n" - "^SCFG: \"Serial/USB/DDD\",\"0\",\"0\",\"0409\",\"1e2d\",\"0065\",\"Cinterion\",\"LTE Modem\",\"8d8f\"\r\n" - "^SCFG: \"SIM/CS\",\"SIM1\"\r\n" - "^SCFG: \"SMS/4GPREF\",\"IMS\"\r\n" - "^SCFG: \"SMS/AutoAck\",\"0\"\r\n" - "^SCFG: \"SMS/RETRM\",\"30\"\r\n" - "^SCFG: \"URC/Ringline\",\"local\"\r\n" - "^SCFG: \"URC/Ringline/ActiveTime\",\"2\"\r\n"; - - expected_bands = g_array_sized_new (FALSE, FALSE, sizeof (MMModemBand), 25); - single = MM_MODEM_BAND_EGSM, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_DCS, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_PCS, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_G850, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_1, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_3, g_array_append_val (expected_bands, single); // - single = MM_MODEM_BAND_UTRAN_5, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_6, g_array_append_val (expected_bands, single); // - single = MM_MODEM_BAND_UTRAN_8, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_UTRAN_19, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_1, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_3, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_5, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_7, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_8, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_18, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_19, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_20, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_26, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_28, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_38, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_39, g_array_append_val (expected_bands, single); - single = MM_MODEM_BAND_EUTRAN_40, g_array_append_val (expected_bands, single); - - common_test_scfg_response (response, MM_MODEM_CHARSET_GSM, expected_bands, MM_CINTERION_MODEM_FAMILY_DEFAULT, MM_CINTERION_RADIO_BAND_FORMAT_MULTIPLE); - - g_array_unref (expected_bands); -} - -/*****************************************************************************/ -/* Test ^SCFG test */ - -static void -compare_arrays (const GArray *supported, - const GArray *expected) -{ - guint i; - - g_assert_cmpuint (supported->len, ==, expected->len); - for (i = 0; i < supported->len; i++) { - gboolean found = FALSE; - guint j; - - for (j = 0; j < expected->len && !found; j++) { - if (g_array_index (supported, guint, i) == g_array_index (expected, guint, j)) - found = TRUE; - } - g_assert (found); - } -} - -static void -common_test_cnmi (const gchar *response, - const GArray *expected_mode, - const GArray *expected_mt, - const GArray *expected_bm, - const GArray *expected_ds, - const GArray *expected_bfr) -{ - GArray *supported_mode = NULL; - GArray *supported_mt = NULL; - GArray *supported_bm = NULL; - GArray *supported_ds = NULL; - GArray *supported_bfr = NULL; - GError *error = NULL; - gboolean res; - - g_assert (expected_mode != NULL); - g_assert (expected_mt != NULL); - g_assert (expected_bm != NULL); - g_assert (expected_ds != NULL); - g_assert (expected_bfr != NULL); - - res = mm_cinterion_parse_cnmi_test (response, - &supported_mode, - &supported_mt, - &supported_bm, - &supported_ds, - &supported_bfr, - &error); - g_assert_no_error (error); - g_assert (res == TRUE); - g_assert (supported_mode != NULL); - g_assert (supported_mt != NULL); - g_assert (supported_bm != NULL); - g_assert (supported_ds != NULL); - g_assert (supported_bfr != NULL); - - compare_arrays (supported_mode, expected_mode); - compare_arrays (supported_mt, expected_mt); - compare_arrays (supported_bm, expected_bm); - compare_arrays (supported_ds, expected_ds); - compare_arrays (supported_bfr, expected_bfr); - - g_array_unref (supported_mode); - g_array_unref (supported_mt); - g_array_unref (supported_bm); - g_array_unref (supported_ds); - g_array_unref (supported_bfr); -} - -static void -test_cnmi_phs8 (void) -{ - GArray *expected_mode; - GArray *expected_mt; - GArray *expected_bm; - GArray *expected_ds; - GArray *expected_bfr; - guint val; - const gchar *response = - "+CNMI: (0,1,2),(0,1),(0,2),(0),(1)\r\n" - "\r\n"; - - expected_mode = g_array_sized_new (FALSE, FALSE, sizeof (guint), 3); - val = 0, g_array_append_val (expected_mode, val); - val = 1, g_array_append_val (expected_mode, val); - val = 2, g_array_append_val (expected_mode, val); - - expected_mt = g_array_sized_new (FALSE, FALSE, sizeof (guint), 2); - val = 0, g_array_append_val (expected_mt, val); - val = 1, g_array_append_val (expected_mt, val); - - expected_bm = g_array_sized_new (FALSE, FALSE, sizeof (guint), 2); - val = 0, g_array_append_val (expected_bm, val); - val = 2, g_array_append_val (expected_bm, val); - - expected_ds = g_array_sized_new (FALSE, FALSE, sizeof (guint), 1); - val = 0, g_array_append_val (expected_ds, val); - - expected_bfr = g_array_sized_new (FALSE, FALSE, sizeof (guint), 1); - val = 1, g_array_append_val (expected_bfr, val); - - common_test_cnmi (response, - expected_mode, - expected_mt, - expected_bm, - expected_ds, - expected_bfr); - - g_array_unref (expected_mode); - g_array_unref (expected_mt); - g_array_unref (expected_bm); - g_array_unref (expected_ds); - g_array_unref (expected_bfr); -} - -static void -test_cnmi_other (void) -{ - GArray *expected_mode; - GArray *expected_mt; - GArray *expected_bm; - GArray *expected_ds; - GArray *expected_bfr; - guint val; - const gchar *response = - "+CNMI: (0-3),(0,1),(0,2,3),(0,2),(1)\r\n" - "\r\n"; - - expected_mode = g_array_sized_new (FALSE, FALSE, sizeof (guint), 3); - val = 0, g_array_append_val (expected_mode, val); - val = 1, g_array_append_val (expected_mode, val); - val = 2, g_array_append_val (expected_mode, val); - val = 3, g_array_append_val (expected_mode, val); - - expected_mt = g_array_sized_new (FALSE, FALSE, sizeof (guint), 2); - val = 0, g_array_append_val (expected_mt, val); - val = 1, g_array_append_val (expected_mt, val); - - expected_bm = g_array_sized_new (FALSE, FALSE, sizeof (guint), 2); - val = 0, g_array_append_val (expected_bm, val); - val = 2, g_array_append_val (expected_bm, val); - val = 3, g_array_append_val (expected_bm, val); - - expected_ds = g_array_sized_new (FALSE, FALSE, sizeof (guint), 1); - val = 0, g_array_append_val (expected_ds, val); - val = 2, g_array_append_val (expected_ds, val); - - expected_bfr = g_array_sized_new (FALSE, FALSE, sizeof (guint), 1); - val = 1, g_array_append_val (expected_bfr, val); - - common_test_cnmi (response, - expected_mode, - expected_mt, - expected_bm, - expected_ds, - expected_bfr); - - g_array_unref (expected_mode); - g_array_unref (expected_mt); - g_array_unref (expected_bm); - g_array_unref (expected_ds); - g_array_unref (expected_bfr); -} - -/*****************************************************************************/ -/* Test ^SWWAN read */ - -#define SWWAN_TEST_MAX_CIDS 2 - -typedef struct { - guint cid; - MMBearerConnectionStatus state; -} PdpContextState; - -typedef struct { - const gchar *response; - PdpContextState expected_items[SWWAN_TEST_MAX_CIDS]; - gboolean skip_test_other_cids; -} SwwanTest; - -/* Note: all tests are based on checking CIDs 2 and 3 */ -static const SwwanTest swwan_tests[] = { - /* No active PDP context reported (all disconnected) */ - { - .response = "", - .expected_items = { - { .cid = 2, .state = MM_BEARER_CONNECTION_STATUS_DISCONNECTED }, - { .cid = 3, .state = MM_BEARER_CONNECTION_STATUS_DISCONNECTED } - }, - /* Don't test other CIDs because for those we would also return - * DISCONNECTED, not UNKNOWN. */ - .skip_test_other_cids = TRUE - }, - /* Single PDP context active (short version without interface index) */ - { - .response = "^SWWAN: 3,1\r\n", - .expected_items = { - { .cid = 2, .state = MM_BEARER_CONNECTION_STATUS_UNKNOWN }, - { .cid = 3, .state = MM_BEARER_CONNECTION_STATUS_CONNECTED } - } - }, - /* Single PDP context active (long version with interface index) */ - { - .response = "^SWWAN: 3,1,1\r\n", - .expected_items = { - { .cid = 2, .state = MM_BEARER_CONNECTION_STATUS_UNKNOWN }, - { .cid = 3, .state = MM_BEARER_CONNECTION_STATUS_CONNECTED } - } - }, - /* Single PDP context inactive (short version without interface index) */ - { - .response = "^SWWAN: 3,0\r\n", - .expected_items = { - { .cid = 2, .state = MM_BEARER_CONNECTION_STATUS_UNKNOWN }, - { .cid = 3, .state = MM_BEARER_CONNECTION_STATUS_DISCONNECTED } - } - }, - /* Single PDP context inactive (long version with interface index) */ - { - .response = "^SWWAN: 3,0,1\r\n", - .expected_items = { - { .cid = 2, .state = MM_BEARER_CONNECTION_STATUS_UNKNOWN }, - { .cid = 3, .state = MM_BEARER_CONNECTION_STATUS_DISCONNECTED } - } - }, - /* Multiple PDP contexts active (short version without interface index) */ - { - .response = "^SWWAN: 2,1\r\n^SWWAN: 3,1\r\n", - .expected_items = { - { .cid = 2, .state = MM_BEARER_CONNECTION_STATUS_CONNECTED }, - { .cid = 3, .state = MM_BEARER_CONNECTION_STATUS_CONNECTED } - } - }, - /* Multiple PDP contexts active (long version with interface index) */ - { - .response = "^SWWAN: 2,1,3\r\n^SWWAN: 3,1,1\r\n", - .expected_items = { - { .cid = 2, .state = MM_BEARER_CONNECTION_STATUS_CONNECTED }, - { .cid = 3, .state = MM_BEARER_CONNECTION_STATUS_CONNECTED } - } - }, - /* Multiple PDP contexts inactive (short version without interface index) */ - { - .response = "^SWWAN: 2,0\r\n^SWWAN: 3,0\r\n", - .expected_items = { - { .cid = 2, .state = MM_BEARER_CONNECTION_STATUS_DISCONNECTED }, - { .cid = 3, .state = MM_BEARER_CONNECTION_STATUS_DISCONNECTED } - } - }, - /* Multiple PDP contexts inactive (long version with interface index) */ - { - .response = "^SWWAN: 2,0,3\r\n^SWWAN: 3,0,1\r\n", - .expected_items = { - { .cid = 2, .state = MM_BEARER_CONNECTION_STATUS_DISCONNECTED }, - { .cid = 3, .state = MM_BEARER_CONNECTION_STATUS_DISCONNECTED } - } - }, - /* Multiple PDP contexts active/inactive (short version without interface index) */ - { - .response = "^SWWAN: 2,0\r\n^SWWAN: 3,1\r\n", - .expected_items = { - { .cid = 2, .state = MM_BEARER_CONNECTION_STATUS_DISCONNECTED }, - { .cid = 3, .state = MM_BEARER_CONNECTION_STATUS_CONNECTED } - } - }, - /* Multiple PDP contexts active/inactive (long version with interface index) */ - { - .response = "^SWWAN: 2,0,3\r\n^SWWAN: 3,1,1\r\n", - .expected_items = { - { .cid = 2, .state = MM_BEARER_CONNECTION_STATUS_DISCONNECTED }, - { .cid = 3, .state = MM_BEARER_CONNECTION_STATUS_CONNECTED } - } - } -}; - -static void -test_swwan_pls8 (void) -{ - MMBearerConnectionStatus read_state; - GError *error = NULL; - guint i; - - /* Base tests for successful responses */ - for (i = 0; i < G_N_ELEMENTS (swwan_tests); i++) { - guint j; - - /* Query for the expected items (CIDs 2 and 3) */ - for (j = 0; j < SWWAN_TEST_MAX_CIDS; j++) { - read_state = mm_cinterion_parse_swwan_response (swwan_tests[i].response, swwan_tests[i].expected_items[j].cid, NULL, &error); - if (swwan_tests[i].expected_items[j].state == MM_BEARER_CONNECTION_STATUS_UNKNOWN) { - g_assert_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED); - g_clear_error (&error); - } else - g_assert_no_error (error); - g_assert_cmpint (read_state, ==, swwan_tests[i].expected_items[j].state); - } - - /* Query for a CID which isn't replied (e.g. 12) */ - if (!swwan_tests[i].skip_test_other_cids) { - read_state = mm_cinterion_parse_swwan_response (swwan_tests[i].response, 12, NULL, &error); - g_assert_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED); - g_assert_cmpint (read_state, ==, MM_BEARER_CONNECTION_STATUS_UNKNOWN); - g_clear_error (&error); - } - } - - /* Additional tests for errors */ - read_state = mm_cinterion_parse_swwan_response ("^GARBAGE", 2, NULL, &error); - g_assert_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED); - g_assert_cmpint (read_state, ==, MM_BEARER_CONNECTION_STATUS_UNKNOWN); - g_clear_error (&error); -} - -/*****************************************************************************/ -/* Test ^SIND responses */ - -static void -common_test_sind_response (const gchar *response, - const gchar *expected_description, - guint expected_mode, - guint expected_value) -{ - GError *error = NULL; - gboolean res; - gchar *description; - guint mode; - guint value; - - res = mm_cinterion_parse_sind_response (response, - &description, - &mode, - &value, - &error); - g_assert_no_error (error); - g_assert (res == TRUE); - - g_assert_cmpstr (description, ==, expected_description); - g_assert_cmpuint (mode, ==, expected_mode); - g_assert_cmpuint (value, ==, expected_value); - - g_free (description); -} - -static void -test_sind_response_simstatus (void) -{ - common_test_sind_response ("^SIND: simstatus,1,5", "simstatus", 1, 5); -} - -/*****************************************************************************/ -/* Test ^SMONG responses */ - -static void -common_test_smong_response (const gchar *response, - gboolean success, - MMModemAccessTechnology expected_access_tech) -{ - GError *error = NULL; - gboolean res; - MMModemAccessTechnology access_tech; - - res = mm_cinterion_parse_smong_response (response, &access_tech, &error); - - if (success) { - g_assert_no_error (error); - g_assert (res); - g_assert_cmpuint (access_tech, ==, expected_access_tech); - } else { - g_assert (error); - g_assert (!res); - } -} - -static void -test_smong_response_tc63i (void) -{ - const gchar *response = - "\r\n" - "GPRS Monitor\r\n" - "BCCH G PBCCH PAT MCC MNC NOM TA RAC # Cell #\r\n" - "0073 1 - - 262 02 2 00 01\r\n"; - common_test_smong_response (response, TRUE, MM_MODEM_ACCESS_TECHNOLOGY_GPRS); -} - -static void -test_smong_response_other (void) -{ - const gchar *response = - "\r\n" - "GPRS Monitor\r\n" - "\r\n" - "BCCH G PBCCH PAT MCC MNC NOM TA RAC # Cell #\r\n" - " 44 1 - - 234 10 - - - \r\n"; - common_test_smong_response (response, TRUE, MM_MODEM_ACCESS_TECHNOLOGY_GPRS); -} - -static void -test_smong_response_no_match (void) -{ - const gchar *response = - "\r\n" - "GPRS Monitor\r\n" - "\r\n" - "BCCH K PBCCH PAT MCC MNC NOM TA RAC # Cell #\r\n" - " 44 1 - - 234 10 - - - \r\n"; - common_test_smong_response (response, FALSE, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN); -} - -/*****************************************************************************/ -/* Test ^SLCC URCs */ - -static void -common_test_slcc_urc (const gchar *urc, - const MMCallInfo *expected_call_info_list, - guint expected_call_info_list_size) -{ - g_autoptr(GRegex) slcc_regex = NULL; - g_autoptr(GMatchInfo) match_info = NULL; - g_autofree gchar *str = NULL; - GError *error = NULL; - GList *call_info_list = NULL; - GList *l; - gboolean result; - - slcc_regex = mm_cinterion_get_slcc_regex (); - - /* Same matching logic as done in MMSerialPortAt when processing URCs! */ - result = g_regex_match_full (slcc_regex, urc, -1, 0, 0, &match_info, &error); - g_assert_no_error (error); - g_assert (result); - - /* read full matched content */ - str = g_match_info_fetch (match_info, 0); - g_assert (str); - - result = mm_cinterion_parse_slcc_list (str, NULL, &call_info_list, &error); - g_assert_no_error (error); - g_assert (result); - - g_debug ("found %u calls", g_list_length (call_info_list)); - - if (expected_call_info_list) { - g_assert (call_info_list); - g_assert_cmpuint (g_list_length (call_info_list), ==, expected_call_info_list_size); - } else - g_assert (!call_info_list); - - for (l = call_info_list; l; l = g_list_next (l)) { - const MMCallInfo *call_info = (const MMCallInfo *)(l->data); - gboolean found = FALSE; - guint i; - - g_debug ("call at index %u: direction %s, state %s, number %s", - call_info->index, - mm_call_direction_get_string (call_info->direction), - mm_call_state_get_string (call_info->state), - call_info->number ? call_info->number : "n/a"); - - for (i = 0; !found && i < expected_call_info_list_size; i++) - found = ((call_info->index == expected_call_info_list[i].index) && - (call_info->direction == expected_call_info_list[i].direction) && - (call_info->state == expected_call_info_list[i].state) && - (g_strcmp0 (call_info->number, expected_call_info_list[i].number) == 0)); - - g_assert (found); - } - - mm_cinterion_call_info_list_free (call_info_list); -} - -static void -test_slcc_urc_empty (void) -{ - const gchar *urc = "\r\n^SLCC: \r\n"; - - common_test_slcc_urc (urc, NULL, 0); -} - -static void -test_slcc_urc_single (void) -{ - static const MMCallInfo expected_call_info_list[] = { - { 1, MM_CALL_DIRECTION_INCOMING, MM_CALL_STATE_ACTIVE, (gchar *) "123456789" } - }; - - const gchar *urc = - "\r\n^SLCC: 1,1,0,0,0,0,\"123456789\",161" - "\r\n^SLCC: \r\n"; - - common_test_slcc_urc (urc, expected_call_info_list, G_N_ELEMENTS (expected_call_info_list)); -} - -static void -test_slcc_urc_multiple (void) -{ - static const MMCallInfo expected_call_info_list[] = { - { 1, MM_CALL_DIRECTION_INCOMING, MM_CALL_STATE_ACTIVE, NULL }, - { 2, MM_CALL_DIRECTION_INCOMING, MM_CALL_STATE_ACTIVE, (gchar *) "123456789" }, - { 3, MM_CALL_DIRECTION_INCOMING, MM_CALL_STATE_ACTIVE, (gchar *) "987654321" }, - }; - - const gchar *urc = - "\r\n^SLCC: 1,1,0,0,1,0" /* number unknown */ - "\r\n^SLCC: 2,1,0,0,1,0,\"123456789\",161" - "\r\n^SLCC: 3,1,0,0,1,0,\"987654321\",161,\"Alice\"" - "\r\n^SLCC: \r\n"; - - common_test_slcc_urc (urc, expected_call_info_list, G_N_ELEMENTS (expected_call_info_list)); -} - -static void -test_slcc_urc_complex (void) -{ - static const MMCallInfo expected_call_info_list[] = { - { 1, MM_CALL_DIRECTION_INCOMING, MM_CALL_STATE_ACTIVE, (gchar *) "123456789" }, - { 2, MM_CALL_DIRECTION_INCOMING, MM_CALL_STATE_WAITING, (gchar *) "987654321" }, - }; - - const gchar *urc = - "\r\n^CIEV: 1,0" /* some different URC before our match */ - "\r\n^SLCC: 1,1,0,0,0,0,\"123456789\",161" - "\r\n^SLCC: 2,1,5,0,0,0,\"987654321\",161" - "\r\n^SLCC: \r\n" - "\r\n^CIEV: 1,0" /* some different URC after our match */; - - common_test_slcc_urc (urc, expected_call_info_list, G_N_ELEMENTS (expected_call_info_list)); -} - -/*****************************************************************************/ -/* Test +CTZU URCs */ - -static void -common_test_ctzu_urc (const gchar *urc, - const gchar *expected_iso8601, - gint expected_offset, - gint expected_dst_offset) -{ - g_autoptr(GRegex) ctzu_regex = NULL; - g_autoptr(GMatchInfo) match_info = NULL; - g_autofree gchar *iso8601 = NULL; - GError *error = NULL; - gboolean result; - MMNetworkTimezone *tz = NULL; - - ctzu_regex = mm_cinterion_get_ctzu_regex (); - - /* Same matching logic as done in MMSerialPortAt when processing URCs! */ - result = g_regex_match_full (ctzu_regex, urc, -1, 0, 0, &match_info, &error); - g_assert_no_error (error); - g_assert (result); - - result = mm_cinterion_parse_ctzu_urc (match_info, &iso8601, &tz, &error); - g_assert_no_error (error); - g_assert (result); - - g_assert (iso8601); - g_assert_cmpstr (expected_iso8601, ==, iso8601); - - g_assert (tz); - g_assert_cmpint (expected_offset, ==, mm_network_timezone_get_offset (tz)); - - if (expected_dst_offset >= 0) - g_assert_cmpuint ((guint)expected_dst_offset, ==, mm_network_timezone_get_dst_offset (tz)); - - g_object_unref (tz); -} - -static void -test_ctzu_urc_simple (void) -{ - const gchar *urc = "\r\n+CTZU: \"19/07/09,11:15:40\",+08\r\n"; - const gchar *expected_iso8601 = "2019-07-09T11:15:40+02"; - gint expected_offset = 120; - gint expected_dst_offset = -1; /* not given */ - - common_test_ctzu_urc (urc, expected_iso8601, expected_offset, expected_dst_offset); -} - -static void -test_ctzu_urc_full (void) -{ - const gchar *urc = "\r\n+CTZU: \"19/07/09,11:15:40\",+08,1\r\n"; - const gchar *expected_iso8601 = "2019-07-09T11:15:40+02"; - gint expected_offset = 120; - gint expected_dst_offset = 60; - - common_test_ctzu_urc (urc, expected_iso8601, expected_offset, expected_dst_offset); -} - -/*****************************************************************************/ -/* Test ^SMONI responses */ - -typedef struct { - const gchar *str; - MMCinterionRadioGen tech; - gdouble rssi; - gdouble ecn0; - gdouble rscp; - gdouble rsrp; - gdouble rsrq; -} SMoniResponseTest; - -static const SMoniResponseTest smoni_response_tests[] = { - { - .str = "^SMONI: 2G,71,-61,262,02,0143,83BA,33,33,3,6,G,NOCONN", - .tech = MM_CINTERION_RADIO_GEN_2G, - .rssi = -61.0, - .ecn0 = 0.0, - .rscp = 0.0, - .rsrp = 0.0, - .rsrq = 0.0 - }, - { - .str = "^SMONI: 2G,SEARCH,SEARCH", - .tech = MM_CINTERION_RADIO_GEN_NONE, - .rssi = 0.0, - .ecn0 = 0.0, - .rscp = 0.0, - .rsrp = 0.0, - .rsrq = 0.0 - }, - { - .str = "^SMONI: 2G,673,-89,262,07,4EED,A500,16,16,7,4,G,5,-107,LIMSRV", - .tech = MM_CINTERION_RADIO_GEN_2G, - .rssi = -89.0, - .ecn0 = 0.0, - .rscp = 0.0, - .rsrp = 0.0, - .rsrq = 0.0 - }, - { - .str = "^SMONI: 2G,673,-80,262,07,4EED,A500,35,35,7,4,G,643,4,0,-80,0,S_FR", - .tech = MM_CINTERION_RADIO_GEN_2G, - .rssi = -80.0, - .ecn0 = 0.0, - .rscp = 0.0, - .rsrp = 0.0, - .rsrq = 0.0 - }, - { - .str = "^SMONI: 3G,10564,296,-7.5,-79,262,02,0143,00228FF,-92,-78,NOCONN", - .tech = MM_CINTERION_RADIO_GEN_3G, - .rssi = 0.0, - .ecn0 = -7.5, - .rscp = -79.0, - .rsrp = 0.0, - .rsrq = 0.0 - }, - { - .str = "^SMONI: 3G,SEARCH,SEARCH", - .tech = MM_CINTERION_RADIO_GEN_NONE, - .rssi = 0.0, - .ecn0 = 0, - .rscp = 0, - .rsrp = 0.0, - .rsrq = 0.0 - }, - { - .str = "^SMONI: 3G,10564,96,-6.5,-77,262,02,0143,00228FF,-92,-78,LIMSRV", - .tech = MM_CINTERION_RADIO_GEN_3G, - .rssi = 0.0, - .ecn0 = -6.5, - .rscp = -77.0, - .rsrp = 0.0, - .rsrq = 0.0 - }, - { - .str = "^SMONI: 3G,10737,131,-5,-93,260,01,7D3D,C80BC9A,--,--,----,---,-,-5,-93,0,01,06", - .tech = MM_CINTERION_RADIO_GEN_3G, - .rssi = 0.0, - .ecn0 = -5.0, - .rscp = -93.0, - .rsrp = 0.0, - .rsrq = 0.0 - }, - { - .str = "^SMONI: 4G,6300,20,10,10,FDD,262,02,BF75,0345103,350,33,-94,-7,NOCONN", - .tech = MM_CINTERION_RADIO_GEN_4G, - .rssi = 0.0, - .ecn0 = 0.0, - .rscp = 0.0, - .rsrp = -94.0, - .rsrq = -7.0 - }, - { - .str = "^SMONI: 4G,SEARCH", - .tech = MM_CINTERION_RADIO_GEN_NONE, - .rssi = 0.0, - .ecn0 = 0.0, - .rscp = 0.0, - .rsrp = 0.0, - .rsrq = 0.0 - }, - { - .str = "^SMONI: 4G,6300,20,10,10,FDD,262,02,BF75,0345103,350,33,-90,-6,LIMSRV", - .tech = MM_CINTERION_RADIO_GEN_4G, - .rssi = 0.0, - .ecn0 = 0.0, - .rscp = 0.0, - .rsrp = -90.0, - .rsrq = -6.0 - }, - { - .str = "^SMONI: 4G,6300,20,10,10,FDD,262,02,BF75,0345103,350,90,-101,-7,CONN", - .tech = MM_CINTERION_RADIO_GEN_4G, - .rssi = 0.0, - .ecn0 = 0.0, - .rscp = 0.0, - .rsrp = -101.0, - .rsrq = -7.0 - }, - { - .str = "^SMONI: 4G,2850,7,20,20,FDD,262,02,C096,027430F,275,11,-114,-9,NOCONN", - .tech = MM_CINTERION_RADIO_GEN_4G, - .rssi = 0.0, - .ecn0 = 0.0, - .rscp = 0.0, - .rsrp = -114.0, - .rsrq = -9.0 - }, - { - .str = "^SMONI: 4G,2850,7,20,20,FDD,262,02,C096,027430F,275,-,-113,-8,CONN", - .tech = MM_CINTERION_RADIO_GEN_4G, - .rssi = 0.0, - .ecn0 = 0.0, - .rscp = 0.0, - .rsrp = -113.0, - .rsrq = -8.0 - } -}; - -static void -test_smoni_response (void) -{ - guint i; - - for (i = 0; i < G_N_ELEMENTS (smoni_response_tests); i++) { - GError *error = NULL; - gboolean success; - MMCinterionRadioGen tech = MM_CINTERION_RADIO_GEN_NONE; - gdouble rssi = MM_SIGNAL_UNKNOWN; - gdouble ecn0 = MM_SIGNAL_UNKNOWN; - gdouble rscp = MM_SIGNAL_UNKNOWN; - gdouble rsrp = MM_SIGNAL_UNKNOWN; - gdouble rsrq = MM_SIGNAL_UNKNOWN; - - success = mm_cinterion_parse_smoni_query_response (smoni_response_tests[i].str, - &tech, &rssi, - &ecn0, &rscp, - &rsrp, &rsrq, - &error); - g_assert_no_error (error); - g_assert (success); - - g_assert_cmpuint (smoni_response_tests[i].tech, ==, tech); - switch (smoni_response_tests[i].tech) { - case MM_CINTERION_RADIO_GEN_2G: - g_assert_cmpfloat_tolerance (rssi, smoni_response_tests[i].rssi, 0.1); - break; - case MM_CINTERION_RADIO_GEN_3G: - g_assert_cmpfloat_tolerance (ecn0, smoni_response_tests[i].ecn0, 0.1); - g_assert_cmpfloat_tolerance (rscp, smoni_response_tests[i].rscp, 0.1); - break; - case MM_CINTERION_RADIO_GEN_4G: - g_assert_cmpfloat_tolerance (rsrp, smoni_response_tests[i].rsrp, 0.1); - g_assert_cmpfloat_tolerance (rsrq, smoni_response_tests[i].rsrq, 0.1); - break; - case MM_CINTERION_RADIO_GEN_NONE: - default: - break; - } - } -} - -static void -test_smoni_response_to_signal (void) -{ - guint i; - - for (i = 0; i < G_N_ELEMENTS (smoni_response_tests); i++) { - GError *error = NULL; - gboolean success; - MMSignal *gsm = NULL; - MMSignal *umts = NULL; - MMSignal *lte = NULL; - - success = mm_cinterion_smoni_response_to_signal_info (smoni_response_tests[i].str, - &gsm, &umts, <e, - &error); - g_assert_no_error (error); - g_assert (success); - - switch (smoni_response_tests[i].tech) { - case MM_CINTERION_RADIO_GEN_2G: - g_assert (gsm); - g_assert_cmpfloat_tolerance (mm_signal_get_rssi (gsm), smoni_response_tests[i].rssi, 0.1); - g_object_unref (gsm); - g_assert (!umts); - g_assert (!lte); - break; - case MM_CINTERION_RADIO_GEN_3G: - g_assert (umts); - g_assert_cmpfloat_tolerance (mm_signal_get_rscp (umts), smoni_response_tests[i].rscp, 0.1); - g_assert_cmpfloat_tolerance (mm_signal_get_ecio (umts), smoni_response_tests[i].ecn0, 0.1); - g_object_unref (umts); - g_assert (!gsm); - g_assert (!lte); - break; - case MM_CINTERION_RADIO_GEN_4G: - g_assert (lte); - g_assert_cmpfloat_tolerance (mm_signal_get_rsrp (lte), smoni_response_tests[i].rsrp, 0.1); - g_assert_cmpfloat_tolerance (mm_signal_get_rsrq (lte), smoni_response_tests[i].rsrq, 0.1); - g_object_unref (lte); - g_assert (!gsm); - g_assert (!umts); - break; - case MM_CINTERION_RADIO_GEN_NONE: - default: - g_assert (!gsm); - g_assert (!umts); - g_assert (!lte); - break; - } - } -} - -/*****************************************************************************/ -/* Test ^SCFG="MEopMode/Prov/Cfg" responses */ - -typedef struct { - const gchar *str; - MMCinterionModemFamily modem_family; - gboolean success; - guint expected_cid; -} ProvcfgResponseTest; - -static const ProvcfgResponseTest provcfg_response_tests[] = { - { - - .str = "^SCFG: \"MEopMode/Prov/Cfg\",\"vdfde\"", - .modem_family = MM_CINTERION_MODEM_FAMILY_DEFAULT, - .success = TRUE, - .expected_cid = 1, - }, - { - - .str = "* ^SCFG: \"MEopMode/Prov/Cfg\",\"attus\"", - .modem_family = MM_CINTERION_MODEM_FAMILY_IMT, - .success = TRUE, - .expected_cid = 1, - }, - { - - .str = "* ^SCFG: \"MEopMode/Prov/Cfg\",\"2\"", - .modem_family = MM_CINTERION_MODEM_FAMILY_DEFAULT, - .success = TRUE, - .expected_cid = 3, - }, - { - - .str = "* ^SCFG: \"MEopMode/Prov/Cfg\",\"vzwdcus\"", - .modem_family = MM_CINTERION_MODEM_FAMILY_DEFAULT, - .success = TRUE, - .expected_cid = 3, - }, - { - - .str = "* ^SCFG: \"MEopMode/Prov/Cfg\",\"tmode\"", - .modem_family = MM_CINTERION_MODEM_FAMILY_DEFAULT, - .success = TRUE, - .expected_cid = 2, - }, - { - .str = "* ^SCFG: \"MEopMode/Prov/Cfg\",\"fallback*\"", - .modem_family = MM_CINTERION_MODEM_FAMILY_DEFAULT, - .success = TRUE, - .expected_cid = 1, - }, - { - /* commas not allowed by the regex */ - .str = "* ^SCFG: \"MEopMode/Prov/Cfg\",\"something,with,commas\"", - .modem_family = MM_CINTERION_MODEM_FAMILY_DEFAULT, - .success = FALSE, - } -}; - -static void -test_provcfg_response (void) -{ - guint i; - - for (i = 0; i < G_N_ELEMENTS (provcfg_response_tests); i++) { - gint cid = -1; - gboolean result; - GError *error = NULL; - - result = mm_cinterion_provcfg_response_to_cid (provcfg_response_tests[i].str, - provcfg_response_tests[i].modem_family, - MM_MODEM_CHARSET_GSM, - NULL, - &cid, - &error); - if (provcfg_response_tests[i].success) { - g_assert_no_error (error); - g_assert (result); - g_assert_cmpuint (cid, ==, provcfg_response_tests[i].expected_cid); - } else { - g_assert (error); - g_assert (!result); - } - } -} - -/*****************************************************************************/ -/* Test ^SGAUTH responses */ - -static void -test_sgauth_response (void) -{ - gboolean result; - MMBearerAllowedAuth auth = MM_BEARER_ALLOWED_AUTH_UNKNOWN; - gchar *username = NULL; - GError *error = NULL; - - const gchar *response = - "^SGAUTH: 1,2,\"vf\"\r\n" - "^SGAUTH: 2,1,\"\"\r\n" - "^SGAUTH: 3,0\r\n"; - - /* CID 1 */ - result = mm_cinterion_parse_sgauth_response (response, 1, &auth, &username, &error); - g_assert_no_error (error); - g_assert (result); - g_assert_cmpuint (auth, ==, MM_BEARER_ALLOWED_AUTH_CHAP); - g_assert_cmpstr (username, ==, "vf"); - - auth = MM_BEARER_ALLOWED_AUTH_UNKNOWN; - g_clear_pointer (&username, g_free); - - /* CID 2 */ - result = mm_cinterion_parse_sgauth_response (response, 2, &auth, &username, &error); - g_assert_no_error (error); - g_assert (result); - g_assert_cmpuint (auth, ==, MM_BEARER_ALLOWED_AUTH_PAP); - g_assert_null (username); - - auth = MM_BEARER_ALLOWED_AUTH_UNKNOWN; - - /* CID 3 */ - result = mm_cinterion_parse_sgauth_response (response, 3, &auth, &username, &error); - g_assert_no_error (error); - g_assert (result); - g_assert_cmpuint (auth, ==, MM_BEARER_ALLOWED_AUTH_NONE); - g_assert_null (username); - - auth = MM_BEARER_ALLOWED_AUTH_UNKNOWN; - - /* CID 4 */ - result = mm_cinterion_parse_sgauth_response (response, 4, &auth, &username, &error); - g_assert_error (error, MM_CORE_ERROR, MM_CORE_ERROR_NOT_FOUND); - g_assert (!result); -} - -/*****************************************************************************/ -/* Test ^SXRAT responses */ - -static void -common_test_sxrat (const gchar *response, - const GArray *expected_rat, - const GArray *expected_pref1, - const GArray *expected_pref2) -{ - GArray *supported_rat = NULL; - GArray *supported_pref1 = NULL; - GArray *supported_pref2 = NULL; - GError *error = NULL; - gboolean res; - - g_assert (expected_rat != NULL); - g_assert (expected_pref1 != NULL); - - res = mm_cinterion_parse_sxrat_test (response, - &supported_rat, - &supported_pref1, - &supported_pref2, - &error); - g_assert_no_error (error); - g_assert (res == TRUE); - g_assert (supported_rat != NULL); - g_assert (supported_pref1 != NULL); - if (expected_pref2) - g_assert (supported_pref2 != NULL); - else - g_assert (supported_pref2 == NULL); - - compare_arrays (supported_rat, expected_rat); - compare_arrays (supported_pref1, expected_pref1); - if (expected_pref2) - compare_arrays (supported_pref2, expected_pref2); - - g_array_unref (supported_rat); - g_array_unref (supported_pref1); - if (supported_pref2) - g_array_unref (supported_pref2); -} - -static void -test_sxrat_response_els61 (void) -{ - GArray *expected_rat; - GArray *expected_pref1; - GArray *expected_pref2; - guint val; - const gchar *response = - "^SXRAT: (0-6),(0,2,3),(0,2,3)\r\n" - "\r\n"; - - expected_rat = g_array_sized_new (FALSE, FALSE, sizeof (guint), 7); - val = 0, g_array_append_val (expected_rat, val); - val = 1, g_array_append_val (expected_rat, val); - val = 2, g_array_append_val (expected_rat, val); - val = 3, g_array_append_val (expected_rat, val); - val = 4, g_array_append_val (expected_rat, val); - val = 5, g_array_append_val (expected_rat, val); - val = 6, g_array_append_val (expected_rat, val); - - expected_pref1 = g_array_sized_new (FALSE, FALSE, sizeof (guint), 3); - val = 0, g_array_append_val (expected_pref1, val); - val = 2, g_array_append_val (expected_pref1, val); - val = 3, g_array_append_val (expected_pref1, val); - - expected_pref2 = g_array_sized_new (FALSE, FALSE, sizeof (guint), 3); - val = 0, g_array_append_val (expected_pref2, val); - val = 2, g_array_append_val (expected_pref2, val); - val = 3, g_array_append_val (expected_pref2, val); - - common_test_sxrat (response, - expected_rat, - expected_pref1, - expected_pref2); - - g_array_unref (expected_rat); - g_array_unref (expected_pref1); - g_array_unref (expected_pref2); -} - -static void -test_sxrat_response_other (void) -{ - GArray *expected_rat; - GArray *expected_pref1; - GArray *expected_pref2 = NULL; - guint val; - const gchar *response = - "^SXRAT: (0-2),(0,2)\r\n" - "\r\n"; - - expected_rat = g_array_sized_new (FALSE, FALSE, sizeof (guint), 3); - val = 0, g_array_append_val (expected_rat, val); - val = 1, g_array_append_val (expected_rat, val); - val = 2, g_array_append_val (expected_rat, val); - - expected_pref1 = g_array_sized_new (FALSE, FALSE, sizeof (guint), 3); - val = 0, g_array_append_val (expected_pref1, val); - val = 2, g_array_append_val (expected_pref1, val); - - common_test_sxrat (response, - expected_rat, - expected_pref1, - expected_pref2); - - g_array_unref (expected_rat); - g_array_unref (expected_pref1); -} - -typedef struct { - const gchar *str; - MMModemMode allowed; - MMModemMode preferred; - gboolean success; -} SxratBuildTest; - -static const SxratBuildTest sxrat_build_tests[] = { - { - .str = "^SXRAT=0", - .allowed = MM_MODEM_MODE_2G, - .preferred = MM_MODEM_MODE_NONE, - .success = TRUE, - }, - { - .str = "^SXRAT=3", - .allowed = MM_MODEM_MODE_4G, - .preferred = MM_MODEM_MODE_NONE, - .success = TRUE, - }, - { - .str = "^SXRAT=1,2", - .allowed = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G, - .preferred = MM_MODEM_MODE_3G, - .success = TRUE, - }, - { - .str = "^SXRAT=6,3", - .allowed = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G, - .preferred = MM_MODEM_MODE_4G, - .success = TRUE, - }, - { - .str = NULL, - .allowed = MM_MODEM_MODE_2G | MM_MODEM_MODE_3G | MM_MODEM_MODE_4G, - .preferred = MM_MODEM_MODE_3G | MM_MODEM_MODE_4G, - .success = FALSE, - }, - { - .str = NULL, - .allowed = MM_MODEM_MODE_5G, - .preferred = MM_MODEM_MODE_NONE, - .success = FALSE, - }, - -}; - -static void -test_sxrat (void) -{ - guint i; - - for (i = 0; i < G_N_ELEMENTS (sxrat_build_tests); i++) { - GError *error = NULL; - gchar* result; - - result = mm_cinterion_build_sxrat_set_command (sxrat_build_tests[i].allowed, - sxrat_build_tests[i].preferred, - &error); - if (sxrat_build_tests[i].success) { - g_assert_no_error (error); - g_assert (result); - g_assert_cmpstr (result, ==, sxrat_build_tests[i].str); - } else { - g_assert (error); - g_assert (!result); - } - } -} -/*****************************************************************************/ - -int main (int argc, char **argv) -{ - setlocale (LC_ALL, ""); - - g_test_init (&argc, &argv, NULL); - - g_test_add_func ("/MM/cinterion/scfg", test_scfg); - g_test_add_func ("/MM/cinterion/scfg/ehs5", test_scfg_ehs5); - g_test_add_func ("/MM/cinterion/scfg/pls62/gsm", test_scfg_pls62_gsm); - g_test_add_func ("/MM/cinterion/scfg/pls62/ucs2", test_scfg_pls62_ucs2); - g_test_add_func ("/MM/cinterion/scfg/alas5", test_scfg_alas5); - g_test_add_func ("/MM/cinterion/scfg/response/3g", test_scfg_response_3g); - g_test_add_func ("/MM/cinterion/scfg/response/2g", test_scfg_response_2g); - g_test_add_func ("/MM/cinterion/scfg/response/pls62/gsm", test_scfg_response_pls62_gsm); - g_test_add_func ("/MM/cinterion/scfg/response/pls62/ucs2",test_scfg_response_pls62_ucs2); - g_test_add_func ("/MM/cinterion/scfg/response/alas5", test_scfg_response_alas5); - g_test_add_func ("/MM/cinterion/cnmi/phs8", test_cnmi_phs8); - g_test_add_func ("/MM/cinterion/cnmi/other", test_cnmi_other); - g_test_add_func ("/MM/cinterion/swwan/pls8", test_swwan_pls8); - g_test_add_func ("/MM/cinterion/sind/response/simstatus", test_sind_response_simstatus); - g_test_add_func ("/MM/cinterion/smong/response/tc63i", test_smong_response_tc63i); - g_test_add_func ("/MM/cinterion/smong/response/other", test_smong_response_other); - g_test_add_func ("/MM/cinterion/smong/response/no-match", test_smong_response_no_match); - g_test_add_func ("/MM/cinterion/slcc/urc/empty", test_slcc_urc_empty); - g_test_add_func ("/MM/cinterion/slcc/urc/single", test_slcc_urc_single); - g_test_add_func ("/MM/cinterion/slcc/urc/multiple", test_slcc_urc_multiple); - g_test_add_func ("/MM/cinterion/slcc/urc/complex", test_slcc_urc_complex); - g_test_add_func ("/MM/cinterion/ctzu/urc/simple", test_ctzu_urc_simple); - g_test_add_func ("/MM/cinterion/ctzu/urc/full", test_ctzu_urc_full); - g_test_add_func ("/MM/cinterion/smoni/query_response", test_smoni_response); - g_test_add_func ("/MM/cinterion/smoni/query_response_to_signal", test_smoni_response_to_signal); - g_test_add_func ("/MM/cinterion/scfg/provcfg", test_provcfg_response); - g_test_add_func ("/MM/cinterion/sgauth", test_sgauth_response); - g_test_add_func ("/MM/cinterion/sxrat", test_sxrat); - g_test_add_func ("/MM/cinterion/sxrat/response/els61", test_sxrat_response_els61); - g_test_add_func ("/MM/cinterion/sxrat/response/other", test_sxrat_response_other); - - return g_test_run (); -} |