For QCDM devices we want most of what MMSerialPort does, but not the AT command handling stuff since the commands and responses aren't AT commands nor are they even strings. So convert everything that MMSerialPort does into a GByteArray, and let MMAtSerialPort handle the conversion to strings when necessary.
828 lines
25 KiB
C
828 lines
25 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* Copyright (C) 2008 Ericsson AB
|
|
*
|
|
* Author: Per Hallsmark <per.hallsmark@ericsson.com>
|
|
* Bjorn Runaker <bjorn.runaker@ericsson.com>
|
|
* Torgny Johansson <torgny.johansson@ericsson.com>
|
|
* Jonas Sjöquist <jonas.sjoquist@ericsson.com>
|
|
*
|
|
* 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.
|
|
*
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#include "mm-modem-mbm.h"
|
|
#include "mm-modem-simple.h"
|
|
#include "mm-errors.h"
|
|
#include "mm-callback-info.h"
|
|
|
|
static void modem_init (MMModem *modem_class);
|
|
static void modem_gsm_network_init (MMModemGsmNetwork *gsm_network_class);
|
|
static void modem_simple_init (MMModemSimple *class);
|
|
|
|
G_DEFINE_TYPE_EXTENDED (MMModemMbm, mm_modem_mbm, MM_TYPE_GENERIC_GSM, 0,
|
|
G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM, modem_init)
|
|
G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_GSM_NETWORK, modem_gsm_network_init)
|
|
G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_SIMPLE, modem_simple_init))
|
|
|
|
#define MM_MODEM_MBM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), MM_TYPE_MODEM_MBM, MMModemMbmPrivate))
|
|
|
|
#define MBM_E2NAP_DISCONNECTED 0
|
|
#define MBM_E2NAP_CONNECTED 1
|
|
#define MBM_E2NAP_CONNECTING 2
|
|
|
|
#define MBM_SIGNAL_INDICATOR 2
|
|
|
|
#define MBM_NETWORK_MODE_ANY 1
|
|
#define MBM_NETWORK_MODE_2G 5
|
|
#define MBM_NETWORK_MODE_3G 6
|
|
|
|
#define MBM_ERINFO_2G_GPRS 1
|
|
#define MBM_ERINFO_2G_EGPRS 2
|
|
#define MBM_ERINFO_3G_UMTS 1
|
|
#define MBM_ERINFO_3G_HSDPA 2
|
|
|
|
typedef struct {
|
|
guint reg_id;
|
|
gboolean have_emrdy;
|
|
char *network_device;
|
|
MMCallbackInfo *pending_connect_info;
|
|
int account_index;
|
|
int network_mode;
|
|
const char *username;
|
|
const char *password;
|
|
} MMModemMbmPrivate;
|
|
|
|
enum {
|
|
PROP_0,
|
|
PROP_NETWORK_DEVICE,
|
|
|
|
LAST_PROP
|
|
};
|
|
|
|
static void
|
|
mbm_modem_authenticate (MMModemMbm *self,
|
|
const char *username,
|
|
const char *password,
|
|
gpointer user_data);
|
|
|
|
static const char *
|
|
mbm_simple_get_string_property (GHashTable *properties, const char *name, GError **error);
|
|
|
|
static uint
|
|
mbm_simple_get_uint_property (GHashTable *properties, const char *name, GError **error);
|
|
|
|
MMModem *
|
|
mm_modem_mbm_new (const char *device,
|
|
const char *driver,
|
|
const char *plugin)
|
|
{
|
|
g_return_val_if_fail (device != NULL, NULL);
|
|
g_return_val_if_fail (driver != NULL, NULL);
|
|
g_return_val_if_fail (plugin != NULL, NULL);
|
|
|
|
return MM_MODEM (g_object_new (MM_TYPE_MODEM_MBM,
|
|
MM_MODEM_MASTER_DEVICE, device,
|
|
MM_MODEM_DRIVER, driver,
|
|
MM_MODEM_PLUGIN, plugin,
|
|
MM_MODEM_IP_METHOD, MM_MODEM_IP_METHOD_DHCP,
|
|
NULL));
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* Gsm network class override functions */
|
|
/*****************************************************************************/
|
|
|
|
typedef struct {
|
|
MMModemGsmNetwork *modem;
|
|
const char *network_id;
|
|
MMModemFn callback;
|
|
gpointer user_data;
|
|
} RegisterData;
|
|
|
|
static gboolean
|
|
register_done (gpointer user_data)
|
|
{
|
|
RegisterData *reg_data = user_data;
|
|
MMModemMbm *self = MM_MODEM_MBM (reg_data->modem);
|
|
MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (self);
|
|
MMModemGsmNetwork *parent_modem_iface;
|
|
MMAtSerialPort *primary;
|
|
|
|
priv->reg_id = 0;
|
|
|
|
primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PRIMARY);
|
|
g_assert (primary);
|
|
|
|
mm_at_serial_port_queue_command (primary, "+CREG=1", 3, NULL, NULL);
|
|
mm_at_serial_port_queue_command (primary, "+CMER=3,0,0,1", 3, NULL, NULL);
|
|
|
|
parent_modem_iface = g_type_interface_peek_parent (MM_MODEM_GSM_NETWORK_GET_INTERFACE (self));
|
|
parent_modem_iface->do_register (MM_MODEM_GSM_NETWORK (self),
|
|
reg_data->network_id,
|
|
reg_data->callback,
|
|
reg_data->user_data);
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
do_register (MMModemGsmNetwork *modem,
|
|
const char *network_id,
|
|
MMModemFn callback,
|
|
gpointer user_data)
|
|
{
|
|
MMModemMbm *self = MM_MODEM_MBM (modem);
|
|
MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (self);
|
|
RegisterData *reg_data;
|
|
|
|
reg_data = g_malloc0 (sizeof(RegisterData));
|
|
reg_data->modem = modem;
|
|
reg_data->network_id = network_id;
|
|
reg_data->callback = callback;
|
|
reg_data->user_data = user_data;
|
|
|
|
/* wait so sim pin is done */
|
|
if (priv->reg_id)
|
|
g_source_remove (priv->reg_id);
|
|
priv->reg_id = g_timeout_add_full (G_PRIORITY_DEFAULT, 500,
|
|
register_done, reg_data,
|
|
g_free);
|
|
}
|
|
|
|
static int
|
|
mbm_parse_network_mode (MMModemGsmMode network_mode)
|
|
{
|
|
switch (network_mode) {
|
|
case MM_MODEM_GSM_MODE_ANY:
|
|
case MM_MODEM_GSM_MODE_3G_PREFERRED:
|
|
case MM_MODEM_GSM_MODE_2G_PREFERRED:
|
|
return MBM_NETWORK_MODE_ANY;
|
|
case MM_MODEM_GSM_MODE_GPRS:
|
|
case MM_MODEM_GSM_MODE_EDGE:
|
|
case MM_MODEM_GSM_MODE_2G_ONLY:
|
|
return MBM_NETWORK_MODE_2G;
|
|
case MM_MODEM_GSM_MODE_3G_ONLY:
|
|
case MM_MODEM_GSM_MODE_HSDPA:
|
|
case MM_MODEM_GSM_MODE_HSUPA:
|
|
case MM_MODEM_GSM_MODE_HSPA:
|
|
return MBM_NETWORK_MODE_3G;
|
|
default:
|
|
return MBM_NETWORK_MODE_ANY;
|
|
}
|
|
}
|
|
|
|
static void
|
|
mbm_set_network_mode_done (MMAtSerialPort *port,
|
|
GString *response,
|
|
GError *error,
|
|
gpointer user_data)
|
|
{
|
|
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
|
|
|
|
if (error)
|
|
info->error = g_error_copy (error);
|
|
|
|
mm_callback_info_schedule (info);
|
|
}
|
|
|
|
static void
|
|
set_network_mode (MMModemGsmNetwork *modem,
|
|
MMModemGsmMode mode,
|
|
MMModemFn callback,
|
|
gpointer user_data)
|
|
{
|
|
MMCallbackInfo *info;
|
|
char *command;
|
|
MMAtSerialPort *primary;
|
|
|
|
info = mm_callback_info_new (MM_MODEM (modem), callback, user_data);
|
|
primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
|
|
g_assert (primary);
|
|
|
|
command = g_strdup_printf ("+CFUN=%d", mbm_parse_network_mode (mode));
|
|
mm_at_serial_port_queue_command (primary, command, 3, mbm_set_network_mode_done, info);
|
|
g_free (command);
|
|
}
|
|
|
|
static void
|
|
get_network_mode_done (MMAtSerialPort *port,
|
|
GString *response,
|
|
GError *error,
|
|
gpointer user_data)
|
|
{
|
|
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
|
|
char *erinfo;
|
|
int mode = 0, gsm = 0, umts = 0;
|
|
gboolean parsed = FALSE;
|
|
|
|
if (error) {
|
|
info->error = g_error_copy (error);
|
|
goto done;
|
|
}
|
|
|
|
erinfo = strstr (response->str, "*ERINFO:");
|
|
if (!erinfo)
|
|
goto done;
|
|
|
|
if (sscanf (erinfo + 8, "%d,%d,%d", &mode, &gsm, &umts) != 3)
|
|
goto done;
|
|
|
|
if (gsm || umts) {
|
|
MMModemGsmMode mm_mode = MM_MODEM_GSM_MODE_ANY;
|
|
|
|
if (gsm == MBM_ERINFO_2G_GPRS)
|
|
mm_mode = MM_MODEM_GSM_MODE_GPRS;
|
|
else if (gsm == MBM_ERINFO_2G_EGPRS)
|
|
mm_mode = MM_MODEM_GSM_MODE_EDGE;
|
|
else if (umts == MBM_ERINFO_3G_UMTS)
|
|
mm_mode = MM_MODEM_GSM_MODE_UMTS;
|
|
else if (umts == MBM_ERINFO_3G_HSDPA)
|
|
mm_mode = MM_MODEM_GSM_MODE_HSDPA;
|
|
else
|
|
g_debug ("%s unknown network mode %d,%d", __FUNCTION__, gsm, umts);
|
|
|
|
mm_callback_info_set_result (info, GUINT_TO_POINTER (mm_mode), NULL);
|
|
parsed = TRUE;
|
|
}
|
|
|
|
done:
|
|
if (!error && !parsed) {
|
|
info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
|
|
"Could not parse network mode results");
|
|
}
|
|
|
|
mm_callback_info_schedule (info);
|
|
}
|
|
|
|
static void
|
|
get_network_mode (MMModemGsmNetwork *modem,
|
|
MMModemUIntFn callback,
|
|
gpointer user_data)
|
|
{
|
|
MMCallbackInfo *info;
|
|
MMAtSerialPort *primary;
|
|
|
|
info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
|
|
primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
|
|
g_assert (primary);
|
|
mm_at_serial_port_queue_command (primary, "*ERINFO?", 3, get_network_mode_done, info);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* Simple Modem class override functions */
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
simple_connect (MMModemSimple *simple,
|
|
GHashTable *properties,
|
|
MMModemFn callback,
|
|
gpointer user_data)
|
|
{
|
|
MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (simple);
|
|
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
|
|
MMModemSimple *parent_iface;
|
|
uint network_mode = 0;
|
|
|
|
priv->username = mbm_simple_get_string_property (properties, "username", &info->error);
|
|
priv->password = mbm_simple_get_string_property (properties, "password", &info->error);
|
|
|
|
network_mode = mbm_simple_get_uint_property (properties, "network_mode", &info->error);
|
|
priv->network_mode = mbm_parse_network_mode (network_mode);
|
|
|
|
parent_iface = g_type_interface_peek_parent (MM_MODEM_SIMPLE_GET_INTERFACE (simple));
|
|
parent_iface->connect (MM_MODEM_SIMPLE (simple), properties, callback, info);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* Modem class override functions */
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
mbm_enable_done (MMAtSerialPort *port,
|
|
GString *response,
|
|
GError *error,
|
|
gpointer user_data)
|
|
{
|
|
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
|
|
|
|
mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info);
|
|
}
|
|
|
|
static void
|
|
mbm_enap0_done (MMAtSerialPort *port,
|
|
GString *response,
|
|
GError *error,
|
|
gpointer user_data)
|
|
{
|
|
MMCallbackInfo *info = user_data;
|
|
MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (info->modem);
|
|
char *command;
|
|
|
|
if (!priv->network_mode)
|
|
priv->network_mode = MBM_NETWORK_MODE_ANY;
|
|
|
|
command = g_strdup_printf ("+CFUN=%d", priv->network_mode);
|
|
mm_at_serial_port_queue_command (port, command, 3, mbm_enable_done, info);
|
|
g_free (command);
|
|
}
|
|
|
|
static void
|
|
mbm_init_done (MMAtSerialPort *port,
|
|
GString *response,
|
|
GError *error,
|
|
gpointer user_data)
|
|
{
|
|
MMCallbackInfo *info = user_data;
|
|
MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (info->modem);
|
|
|
|
if (error) {
|
|
mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info);
|
|
return;
|
|
}
|
|
|
|
if (!priv->network_mode)
|
|
priv->network_mode = MBM_NETWORK_MODE_ANY;
|
|
|
|
mm_at_serial_port_queue_command (port, "*ENAP=0", 3, mbm_enap0_done, info);
|
|
}
|
|
|
|
static void
|
|
do_init (MMAtSerialPort *port, MMCallbackInfo *info)
|
|
{
|
|
mm_at_serial_port_queue_command (port, "&F E0 V1 X4 &C1 +CMEE=1", 3, mbm_init_done, info);
|
|
}
|
|
|
|
static void
|
|
mbm_emrdy_done (MMAtSerialPort *port,
|
|
GString *response,
|
|
GError *error,
|
|
gpointer user_data)
|
|
{
|
|
MMCallbackInfo *info = user_data;
|
|
MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (info->modem);
|
|
|
|
if ( error
|
|
&& error->domain == MM_SERIAL_ERROR
|
|
&& error->code == MM_SERIAL_RESPONSE_TIMEOUT) {
|
|
g_warning ("%s: timed out waiting for EMRDY response.", __func__);
|
|
} else
|
|
priv->have_emrdy = TRUE;
|
|
|
|
do_init (port, info);
|
|
}
|
|
|
|
static void
|
|
do_enable (MMGenericGsm *self, MMModemFn callback, gpointer user_data)
|
|
{
|
|
MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (self);
|
|
MMCallbackInfo *info;
|
|
MMAtSerialPort *primary;
|
|
|
|
info = mm_callback_info_new (MM_MODEM (self), callback, user_data);
|
|
|
|
primary = mm_generic_gsm_get_at_port (self, MM_PORT_TYPE_PRIMARY);
|
|
g_assert (primary);
|
|
|
|
if (priv->have_emrdy) {
|
|
/* Modem is ready, no need to check EMRDY */
|
|
do_init (primary, info);
|
|
} else
|
|
mm_at_serial_port_queue_command (primary, "*EMRDY?", 5, mbm_emrdy_done, info);
|
|
}
|
|
|
|
typedef struct {
|
|
MMModem *modem;
|
|
MMModemFn callback;
|
|
gpointer user_data;
|
|
} DisableInfo;
|
|
|
|
static void
|
|
disable_creg_cmer_done (MMAtSerialPort *port,
|
|
GString *response,
|
|
GError *error,
|
|
gpointer user_data)
|
|
|
|
{
|
|
MMModem *parent_modem_iface;
|
|
DisableInfo *info = user_data;
|
|
|
|
parent_modem_iface = g_type_interface_peek_parent (MM_MODEM_GET_INTERFACE (info->modem));
|
|
parent_modem_iface->disable (info->modem, info->callback, info->user_data);
|
|
g_free (info);
|
|
}
|
|
|
|
static void
|
|
disable (MMModem *modem,
|
|
MMModemFn callback,
|
|
gpointer user_data)
|
|
{
|
|
MMAtSerialPort *primary;
|
|
DisableInfo *info;
|
|
|
|
info = g_malloc0 (sizeof (DisableInfo));
|
|
info->callback = callback;
|
|
info->user_data = user_data;
|
|
info->modem = modem;
|
|
|
|
primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
|
|
g_assert (primary);
|
|
|
|
/* Turn off unsolicited +CIEV signal strength indicator */
|
|
mm_at_serial_port_queue_command (primary, "+CREG=0;+CMER=0", 5, disable_creg_cmer_done, info);
|
|
}
|
|
|
|
static void
|
|
do_connect (MMModem *modem,
|
|
const char *number,
|
|
MMModemFn callback,
|
|
gpointer user_data)
|
|
{
|
|
MMCallbackInfo *info;
|
|
MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (modem);
|
|
|
|
mm_modem_set_state (modem, MM_MODEM_STATE_CONNECTING, MM_MODEM_STATE_REASON_NONE);
|
|
|
|
info = mm_callback_info_new (modem, callback, user_data);
|
|
priv->pending_connect_info = info;
|
|
|
|
mbm_modem_authenticate (MM_MODEM_MBM (modem), priv->username, priv->password, info);
|
|
}
|
|
|
|
static void
|
|
disconnect (MMModem *modem,
|
|
MMModemFn callback,
|
|
gpointer user_data)
|
|
{
|
|
MMCallbackInfo *info;
|
|
MMAtSerialPort *primary;
|
|
|
|
mm_modem_set_state (modem, MM_MODEM_STATE_DISCONNECTING, MM_MODEM_STATE_REASON_NONE);
|
|
|
|
primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY);
|
|
g_assert (primary);
|
|
mm_at_serial_port_queue_command (primary, "*ENAP=0", 3, NULL, NULL);
|
|
|
|
mm_generic_gsm_update_enabled_state (MM_GENERIC_GSM (modem), FALSE, MM_MODEM_STATE_REASON_NONE);
|
|
|
|
info = mm_callback_info_new (modem, callback, user_data);
|
|
mm_callback_info_schedule (info);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
mbm_emrdy_received (MMAtSerialPort *port,
|
|
GMatchInfo *info,
|
|
gpointer user_data)
|
|
{
|
|
MM_MODEM_MBM_GET_PRIVATE (user_data)->have_emrdy = TRUE;
|
|
}
|
|
|
|
static void
|
|
mbm_pacsp_received (MMAtSerialPort *port,
|
|
GMatchInfo *info,
|
|
gpointer user_data)
|
|
{
|
|
return;
|
|
}
|
|
|
|
static void
|
|
mbm_ciev_received (MMAtSerialPort *port,
|
|
GMatchInfo *info,
|
|
gpointer user_data)
|
|
{
|
|
int quality = 0, ind = 0;
|
|
const char *str;
|
|
|
|
str = g_match_info_fetch (info, 1);
|
|
if (str)
|
|
ind = atoi (str);
|
|
|
|
if (ind == MBM_SIGNAL_INDICATOR) {
|
|
str = g_match_info_fetch (info, 2);
|
|
if (str) {
|
|
quality = atoi (str);
|
|
mm_modem_gsm_network_signal_quality (MM_MODEM_GSM_NETWORK (user_data), quality * 20);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
mbm_do_connect_done (MMModemMbm *self)
|
|
{
|
|
MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (self);
|
|
|
|
if (priv->pending_connect_info) {
|
|
mm_generic_gsm_connect_complete (MM_GENERIC_GSM (self), NULL, priv->pending_connect_info);
|
|
priv->pending_connect_info = NULL;
|
|
}
|
|
}
|
|
|
|
static void
|
|
mbm_e2nap_received (MMAtSerialPort *port,
|
|
GMatchInfo *info,
|
|
gpointer user_data)
|
|
{
|
|
int state = 0;
|
|
const char *str;
|
|
|
|
str = g_match_info_fetch (info, 1);
|
|
if (str)
|
|
state = atoi (str);
|
|
|
|
if (MBM_E2NAP_DISCONNECTED == state)
|
|
g_debug ("%s, disconnected", __func__);
|
|
else if (MBM_E2NAP_CONNECTED == state) {
|
|
g_debug ("%s, connected", __func__);
|
|
mbm_do_connect_done (MM_MODEM_MBM (user_data));
|
|
} else if (MBM_E2NAP_CONNECTING == state)
|
|
g_debug("%s, connecting", __func__);
|
|
else {
|
|
/* Should not happen */
|
|
g_debug("%s, undefined e2nap status",__FUNCTION__);
|
|
g_assert_not_reached ();
|
|
}
|
|
}
|
|
|
|
static void
|
|
enap_poll_response (MMAtSerialPort *port,
|
|
GString *response,
|
|
GError *error,
|
|
gpointer user_data)
|
|
{
|
|
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
|
|
guint state;
|
|
guint count;
|
|
|
|
g_assert (info);
|
|
|
|
count = GPOINTER_TO_UINT (mm_callback_info_get_data (info, "mbm-enap-poll-count"));
|
|
|
|
if (sscanf (response->str, "*ENAP: %d", &state) == 1 && state == 1) {
|
|
/* Success! Connected... */
|
|
mm_generic_gsm_connect_complete (MM_GENERIC_GSM (info->modem), NULL, info);
|
|
return;
|
|
}
|
|
|
|
mm_callback_info_set_data (info, "mbm-enap-poll-count", GUINT_TO_POINTER (++count), NULL);
|
|
|
|
/* lets give it about 50 seconds */
|
|
if (count > 50) {
|
|
GError *poll_error;
|
|
|
|
poll_error = mm_modem_connect_error_for_code (MM_MODEM_CONNECT_ERROR_BUSY);
|
|
mm_generic_gsm_connect_complete (MM_GENERIC_GSM (info->modem), poll_error, info);
|
|
g_error_free (poll_error);
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
enap_poll (gpointer user_data)
|
|
{
|
|
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
|
|
MMAtSerialPort *port;
|
|
|
|
port = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (info->modem), MM_PORT_TYPE_PRIMARY);
|
|
g_assert (port);
|
|
|
|
mm_at_serial_port_queue_command (port, "AT*ENAP?", 3, enap_poll_response, user_data);
|
|
/* we cancel this in the _done function if all is fine */
|
|
return TRUE;
|
|
}
|
|
|
|
static void
|
|
enap_done (MMAtSerialPort *port,
|
|
GString *response,
|
|
GError *error,
|
|
gpointer user_data)
|
|
{
|
|
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
|
|
guint tid;
|
|
|
|
if (error) {
|
|
mm_generic_gsm_connect_complete (MM_GENERIC_GSM (info->modem), error, info);
|
|
return;
|
|
}
|
|
|
|
tid = g_timeout_add_seconds (1, enap_poll, user_data);
|
|
/* remember poll id as callback info object, with source_remove as free func */
|
|
mm_callback_info_set_data (info, "mbm-enap-poll-id", GUINT_TO_POINTER (tid), (GFreeFunc) g_source_remove);
|
|
mm_at_serial_port_queue_command (port, "AT*E2NAP=1", 3, NULL, NULL);
|
|
}
|
|
|
|
static void
|
|
mbm_auth_done (MMAtSerialPort *port,
|
|
GString *response,
|
|
GError *error,
|
|
gpointer user_data)
|
|
{
|
|
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
|
|
MMGenericGsm *modem = MM_GENERIC_GSM (info->modem);
|
|
char *command;
|
|
guint32 cid;
|
|
|
|
if (error) {
|
|
mm_generic_gsm_connect_complete (modem, error, info);
|
|
return;
|
|
}
|
|
|
|
cid = mm_generic_gsm_get_cid (modem);
|
|
command = g_strdup_printf ("AT*ENAP=1,%d", cid);
|
|
mm_at_serial_port_queue_command (port, command, 3, enap_done, user_data);
|
|
g_free (command);
|
|
}
|
|
|
|
static void
|
|
mbm_modem_authenticate (MMModemMbm *self,
|
|
const char *username,
|
|
const char *password,
|
|
gpointer user_data)
|
|
{
|
|
MMAtSerialPort *primary;
|
|
|
|
primary = mm_generic_gsm_get_at_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PRIMARY);
|
|
g_assert (primary);
|
|
|
|
if (username || password) {
|
|
char *command;
|
|
|
|
command = g_strdup_printf ("*EIAAUW=%d,1,\"%s\",\"%s\"",
|
|
mm_generic_gsm_get_cid (MM_GENERIC_GSM (self)),
|
|
username ? username : "",
|
|
password ? password : "");
|
|
|
|
mm_at_serial_port_queue_command (primary, command, 3, mbm_auth_done, user_data);
|
|
g_free (command);
|
|
} else
|
|
mbm_auth_done (primary, NULL, NULL, user_data);
|
|
}
|
|
|
|
static const char *
|
|
mbm_simple_get_string_property (GHashTable *properties, const char *name, GError **error)
|
|
{
|
|
GValue *value;
|
|
|
|
value = (GValue *) g_hash_table_lookup (properties, name);
|
|
if (!value)
|
|
return NULL;
|
|
|
|
if (G_VALUE_HOLDS_STRING (value))
|
|
return g_value_get_string (value);
|
|
|
|
g_set_error (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
|
|
"Invalid property type for '%s': %s (string expected)",
|
|
name, G_VALUE_TYPE_NAME (value));
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static uint
|
|
mbm_simple_get_uint_property (GHashTable *properties, const char *name, GError **error)
|
|
{
|
|
GValue *value;
|
|
|
|
value = (GValue *) g_hash_table_lookup (properties, name);
|
|
if (!value)
|
|
return 0;
|
|
|
|
if (G_VALUE_HOLDS_UINT (value))
|
|
return g_value_get_uint (value);
|
|
|
|
g_set_error (error, MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
|
|
"Invalid property type for '%s': %s (uint expected)",
|
|
name, G_VALUE_TYPE_NAME (value));
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static gboolean
|
|
grab_port (MMModem *modem,
|
|
const char *subsys,
|
|
const char *name,
|
|
MMPortType suggested_type,
|
|
gpointer user_data,
|
|
GError **error)
|
|
{
|
|
MMGenericGsm *gsm = MM_GENERIC_GSM (modem);
|
|
MMPortType ptype = MM_PORT_TYPE_IGNORED;
|
|
MMPort *port = NULL;
|
|
|
|
if (!strcmp (subsys, "tty")) {
|
|
if (suggested_type == MM_PORT_TYPE_UNKNOWN) {
|
|
if (!mm_generic_gsm_get_at_port (gsm, MM_PORT_TYPE_PRIMARY))
|
|
ptype = MM_PORT_TYPE_PRIMARY;
|
|
else if (!mm_generic_gsm_get_at_port (gsm, MM_PORT_TYPE_SECONDARY))
|
|
ptype = MM_PORT_TYPE_SECONDARY;
|
|
} else
|
|
ptype = suggested_type;
|
|
}
|
|
|
|
port = mm_generic_gsm_grab_port (gsm, subsys, name, ptype, error);
|
|
if (port && MM_IS_AT_SERIAL_PORT (port) && (ptype == MM_PORT_TYPE_PRIMARY)) {
|
|
GRegex *regex;
|
|
|
|
mm_generic_gsm_set_unsolicited_registration (MM_GENERIC_GSM (modem), TRUE);
|
|
|
|
regex = g_regex_new ("\\r\\n\\*EMRDY: \\d\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
|
mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, mbm_emrdy_received, modem, NULL);
|
|
g_regex_unref (regex);
|
|
|
|
regex = g_regex_new ("\\r\\n\\*E2NAP: (\\d)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
|
mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, mbm_e2nap_received, modem, NULL);
|
|
g_regex_unref (regex);
|
|
|
|
regex = g_regex_new ("\\r\\n\\+PACSP(\\d)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
|
mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, mbm_pacsp_received, modem, NULL);
|
|
g_regex_unref (regex);
|
|
|
|
regex = g_regex_new ("\\r\\n\\+CIEV: (\\d),(\\d)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
|
mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, mbm_ciev_received, modem, NULL);
|
|
g_regex_unref (regex);
|
|
|
|
/* also consume unsolicited mbm messages we are not interested in them - see LP: #416418 */
|
|
regex = g_regex_new ("\\R\\*ESTKSMENU:.*\\R", G_REGEX_RAW | G_REGEX_OPTIMIZE | G_REGEX_MULTILINE | G_REGEX_NEWLINE_CRLF, G_REGEX_MATCH_NEWLINE_CRLF, NULL);
|
|
mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, NULL, modem, NULL);
|
|
g_regex_unref (regex);
|
|
|
|
regex = g_regex_new ("\\r\\n\\*EMWI: (\\d),(\\d).*\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
|
mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, NULL, NULL, NULL);
|
|
g_regex_unref (regex);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
modem_gsm_network_init (MMModemGsmNetwork *class)
|
|
{
|
|
class->do_register = do_register;
|
|
class->get_network_mode = get_network_mode;
|
|
class->set_network_mode = set_network_mode;
|
|
}
|
|
|
|
static void
|
|
modem_simple_init (MMModemSimple *class)
|
|
{
|
|
class->connect = simple_connect;
|
|
}
|
|
|
|
static void
|
|
modem_init (MMModem *modem_class)
|
|
{
|
|
modem_class->grab_port = grab_port;
|
|
modem_class->disable = disable;
|
|
modem_class->connect = do_connect;
|
|
modem_class->disconnect = disconnect;
|
|
}
|
|
|
|
static void
|
|
mm_modem_mbm_init (MMModemMbm *self)
|
|
{
|
|
}
|
|
|
|
static void
|
|
finalize (GObject *object)
|
|
{
|
|
MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (object);
|
|
|
|
if (priv->reg_id)
|
|
g_source_remove (priv->reg_id);
|
|
|
|
g_free (priv->network_device);
|
|
|
|
G_OBJECT_CLASS (mm_modem_mbm_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
mm_modem_mbm_class_init (MMModemMbmClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
MMGenericGsmClass *gsm_class = MM_GENERIC_GSM_CLASS (klass);
|
|
|
|
mm_modem_mbm_parent_class = g_type_class_peek_parent (klass);
|
|
g_type_class_add_private (object_class, sizeof (MMModemMbmPrivate));
|
|
|
|
/* Virtual methods */
|
|
object_class->finalize = finalize;
|
|
|
|
gsm_class->do_enable = do_enable;
|
|
}
|
|
|