Merge remote branch 'origin/master' into qcdm

This commit is contained in:
Dan Williams
2010-03-10 14:50:41 -08:00
15 changed files with 543 additions and 233 deletions

View File

@@ -14,4 +14,5 @@ EXTRA_DIST = \
mm-modem-gsm-sms.xml \
mm-modem-simple.xml \
mm-serial-error.xml \
mm-modem-location.xml
mm-modem-location.xml \
mm-modem-gsm-ussd.xml

View File

@@ -33,6 +33,7 @@
<xi:include href="mm-modem-gsm-network.xml"/>
<xi:include href="mm-modem-gsm-sms.xml"/>
<xi:include href="mm-modem-gsm-hso.xml"/>
<xi:include href="mm-modem-gsm-ussd.xml"/>
<xi:include href="mm-serial-error.xml"/>
<xi:include href="mm-modem-error.xml"/>

View File

@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8" ?>
<node name="/" xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
<interface name="org.freedesktop.ModemManager.Modem.Gsm.Ussd">
<method name="Initiate">
<tp:docstring>
Sends a USSD command string to the network initiating a USSD session.
When the request is handled by the network, the method returns the
response or an appropriate error. The network may be awaiting further
response from the ME after returning from this method and no new command
can be initiated until this one is cancelled or ended.
</tp:docstring>
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_modem_gsm_ussd_initiate"/>
<arg name="command" type="s" direction="in">
<tp:docstring>
The command to start the USSD session with.
</tp:docstring>
</arg>
<arg name="reply" type="s" direction="out">
<tp:docstring>
The network response to the command which started the USSD session.
</tp:docstring>
</arg>
</method>
<method name="Respond">
<tp:docstring>
Respond to a USSD request that is either initiated by the mobile network,
or that is awaiting further input after Initiate() was called.
</tp:docstring>
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_modem_gsm_ussd_respond"/>
<arg name="response" type="s" direction="in">
<tp:docstring>
The response to network-initiated USSD command, or a response to a
request for further input.
</tp:docstring>
</arg>
</method>
<method name="Cancel">
<tp:docstring>
Cancel an ongoing USSD session, either mobile or network initiated.
</tp:docstring>
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_modem_gsm_ussd_cancel"/>
</method>
<property name="State" type="s" access="read">
<tp:docstring>
Indicates the state of any ongoing USSD session. Values may be one of
the following: "idle" (no active session), "active" (a session is active
and the mobile is waiting for a response), "user-response" (the network
is waiting for the client's response, which must be sent using Respond()).
</tp:docstring>
</property>
<property name="NetworkNotification" type="s" access="read">
<tp:docstring>
Contains any network-initiated request to which no USSD response is
required. When no USSD session is active, or when there is no network-
initiated request, this property will be a zero-length string.
</tp:docstring>
</property>
<property name="NetworkRequest" type="s" access="read">
<tp:docstring>
Contains any pending network-initiated request for a response. Client
should call Respond() with the appropriate response to this request.
When no USSD session is active, or when there is no pending
network-initiated request, this property will be a zero-length string.
</tp:docstring>
</property>
</interface>
</node>

View File

@@ -40,7 +40,6 @@ G_DEFINE_TYPE_EXTENDED (MMModemHuaweiGsm, mm_modem_huawei_gsm, MM_TYPE_GENERIC_G
typedef struct {
/* Cached state */
guint signal_quality;
MMModemGsmBand band;
} MMModemHuaweiGsmPrivate;
@@ -369,29 +368,6 @@ get_band (MMModemGsmNetwork *modem,
}
}
static void
get_signal_quality (MMModemGsmNetwork *modem,
MMModemUIntFn callback,
gpointer user_data)
{
MMModemHuaweiGsmPrivate *priv = MM_MODEM_HUAWEI_GSM_GET_PRIVATE (modem);
if (priv->signal_quality) {
/* have cached signal quality (from an unsolicited message). Use that */
MMCallbackInfo *info;
info = mm_callback_info_uint_new (MM_MODEM (modem), callback, user_data);
mm_callback_info_set_result (info, GUINT_TO_POINTER (priv->signal_quality), NULL);
mm_callback_info_schedule (info);
} else {
/* Use the generic implementation */
MMModemGsmNetwork *parent_gsm_network_iface;
parent_gsm_network_iface = g_type_interface_peek_parent (MM_MODEM_GSM_NETWORK_GET_INTERFACE (modem));
parent_gsm_network_iface->get_signal_quality (modem, callback, user_data);
}
}
/* Unsolicited message handlers */
static void
@@ -400,24 +376,22 @@ handle_signal_quality_change (MMAtSerialPort *port,
gpointer user_data)
{
MMModemHuaweiGsm *self = MM_MODEM_HUAWEI_GSM (user_data);
MMModemHuaweiGsmPrivate *priv = MM_MODEM_HUAWEI_GSM_GET_PRIVATE (self);
char *str;
int quality;
int quality = 0;
str = g_match_info_fetch (match_info, 1);
quality = atoi (str);
g_free (str);
if (quality == 99)
if (quality == 99) {
/* 99 means unknown */
quality = 0;
else
} else {
/* Normalize the quality */
quality = quality * 100 / 31;
quality = CLAMP (quality, 0, 31) * 100 / 31;
}
g_debug ("Signal quality: %d", quality);
priv->signal_quality = (guint32) quality;
mm_modem_gsm_network_signal_quality (MM_MODEM_GSM_NETWORK (self), (guint32) quality);
mm_generic_gsm_update_signal_quality (MM_GENERIC_GSM (self), (guint32) quality);
}
static void
@@ -568,7 +542,6 @@ modem_gsm_network_init (MMModemGsmNetwork *class)
{
class->set_band = set_band;
class->get_band = get_band;
class->get_signal_quality = get_signal_quality;
}
static void

View File

@@ -52,11 +52,6 @@ G_DEFINE_TYPE_EXTENDED (MMModemMbm, mm_modem_mbm, MM_TYPE_GENERIC_GSM, 0,
#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;
@@ -129,9 +124,6 @@ register_done (gpointer user_data)
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,
@@ -214,57 +206,47 @@ set_allowed_mode (MMGenericGsm *gsm,
g_free (command);
}
#if 0
static void
get_network_mode_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
mbm_erinfo_received (MMAtSerialPort *port,
GMatchInfo *info,
gpointer user_data)
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
char *erinfo;
int mode = 0, gsm = 0, umts = 0;
gboolean parsed = FALSE;
MMModemGsmAccessTech act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
char *str;
if (error) {
info->error = g_error_copy (error);
goto done;
str = g_match_info_fetch (info, 2);
if (str) {
switch (atoi (str)) {
case 1:
act = MM_MODEM_GSM_ACCESS_TECH_GPRS;
break;
case 2:
act = MM_MODEM_GSM_ACCESS_TECH_EDGE;
break;
default:
break;
}
}
g_free (str);
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;
/* 3G modes take precedence */
str = g_match_info_fetch (info, 3);
if (str) {
switch (atoi (str)) {
case 1:
act = MM_MODEM_GSM_ACCESS_TECH_UMTS;
break;
case 2:
act = MM_MODEM_GSM_ACCESS_TECH_HSDPA;
break;
default:
break;
}
}
g_free (str);
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);
mm_generic_gsm_update_access_technology (MM_GENERIC_GSM (user_data), act);
}
#endif
static void
get_allowed_mode_done (MMAtSerialPort *port,
@@ -364,6 +346,10 @@ mbm_enable_done (MMAtSerialPort *port,
{
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
/* Start unsolicited signal strength and access technology responses */
mm_at_serial_port_queue_command (port, "+CMER=3,0,0,1", 3, NULL, NULL);
mm_at_serial_port_queue_command (port, "*ERINFO=1", 3, NULL, NULL);
mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info);
}
@@ -456,10 +442,10 @@ typedef struct {
} DisableInfo;
static void
disable_creg_cmer_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
disable_unsolicited_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
MMModem *parent_modem_iface;
@@ -486,8 +472,8 @@ disable (MMModem *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);
/* Turn off unsolicited responses */
mm_at_serial_port_queue_command (primary, "+CMER=0;*ERINFO=0", 5, disable_unsolicited_done, info);
}
static void
@@ -551,18 +537,20 @@ mbm_ciev_received (MMAtSerialPort *port,
gpointer user_data)
{
int quality = 0, ind = 0;
const char *str;
char *str;
str = g_match_info_fetch (info, 1);
if (str)
ind = atoi (str);
g_free (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);
mm_generic_gsm_update_signal_quality (MM_GENERIC_GSM (user_data), quality * 20);
}
g_free (str);
}
}
@@ -592,11 +580,12 @@ mbm_e2nap_received (MMAtSerialPort *port,
gpointer user_data)
{
int state = 0;
const char *str;
char *str;
str = g_match_info_fetch (info, 1);
if (str)
state = atoi (str);
g_free (str);
if (MBM_E2NAP_DISCONNECTED == state) {
g_debug ("%s: disconnected", __func__);
@@ -791,17 +780,19 @@ grab_port (MMModem *modem,
}
port = mm_generic_gsm_grab_port (gsm, subsys, name, ptype, error);
if (port && MM_IS_AT_SERIAL_PORT (port) && (ptype == MM_PORT_TYPE_PRIMARY)) {
if (port && MM_IS_AT_SERIAL_PORT (port)) {
GRegex *regex;
if (ptype == MM_PORT_TYPE_PRIMARY) {
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\\*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);
@@ -812,12 +803,16 @@ grab_port (MMModem *modem,
/* 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);
mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, NULL, NULL, 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);
regex = g_regex_new ("\\r\\n\\*ERINFO:\\s*(\\d),(\\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_erinfo_received, modem, NULL);
g_regex_unref (regex);
}
return TRUE;

View File

@@ -48,13 +48,27 @@ mm_modem_novatel_gsm_new (const char *device,
/* Modem class override functions */
/*****************************************************************************/
static void
dmat_callback2 (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
mm_serial_port_close (MM_SERIAL_PORT (port));
}
static void
dmat_callback (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
mm_serial_port_close (MM_SERIAL_PORT (port));
if (error) {
/* Try it again */
if (mm_serial_port_open (MM_SERIAL_PORT (port), NULL))
mm_at_serial_port_queue_command (port, "$NWDMAT=1", 2, dmat_callback2, NULL);
} else
mm_serial_port_close (MM_SERIAL_PORT (port));
}
static gboolean

View File

@@ -52,6 +52,39 @@ mm_modem_zte_new (const char *device,
NULL));
}
static void
zte_access_tech_changed (MMAtSerialPort *port,
GMatchInfo *info,
gpointer user_data)
{
MMModemGsmAccessTech act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
char *str;
str = g_match_info_fetch (info, 1);
if (str) {
/* Better technologies are listed first since modem sometimes says
* stuff like "GPRS/EDGE" and that should be handled as EDGE.
*/
if (strstr (str, "HSPA"))
act = MM_MODEM_GSM_ACCESS_TECH_HSPA;
else if (strstr (str, "HSUPA"))
act = MM_MODEM_GSM_ACCESS_TECH_HSUPA;
else if (strstr (str, "HSDPA"))
act = MM_MODEM_GSM_ACCESS_TECH_HSDPA;
else if (strstr (str, "UMTS"))
act = MM_MODEM_GSM_ACCESS_TECH_UMTS;
else if (strstr (str, "EDGE"))
act = MM_MODEM_GSM_ACCESS_TECH_EDGE;
else if (strstr (str, "GPRS"))
act = MM_MODEM_GSM_ACCESS_TECH_GPRS;
else if (strstr (str, "GSM"))
act = MM_MODEM_GSM_ACCESS_TECH_GSM;
}
g_free (str);
mm_generic_gsm_update_access_technology (MM_GENERIC_GSM (user_data), act);
}
/*****************************************************************************/
/* Modem class override functions */
/*****************************************************************************/
@@ -223,8 +256,8 @@ grab_port (MMModem *modem,
g_regex_unref (regex);
/* Current network and service domain */
regex = g_regex_new ("\\r\\n\\+ZPASR: (.*)\\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);
regex = g_regex_new ("\\r\\n\\+ZPASR:\\s*(.*)\\r\\n", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
mm_at_serial_port_add_unsolicited_msg_handler (MM_AT_SERIAL_PORT (port), regex, zte_access_tech_changed, modem, NULL);
g_regex_unref (regex);
/* SIM request to Build Main Menu */

View File

@@ -17,6 +17,7 @@
#include <signal.h>
#include <syslog.h>
#include <string.h>
#include <unistd.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus-glib-lowlevel.h>
#include "mm-manager.h"
@@ -33,8 +34,11 @@ mm_signal_handler (int signo)
mm_options_set_debug (!mm_options_debug ());
else if (signo == SIGINT || signo == SIGTERM) {
g_message ("Caught signal %d, shutting down...", signo);
g_main_loop_quit (loop);
}
if (loop)
g_main_loop_quit (loop);
else
_exit (0);
}
}
static void

View File

@@ -358,6 +358,9 @@ enable_all_done (MMModem *modem, GError *error, gpointer user_data)
if (error)
info->error = g_error_copy (error);
else {
/* Try to enable XON/XOFF flow control */
mm_at_serial_port_queue_command (priv->primary, "+IFC=1,1", 3, NULL, NULL);
/* Open up the second port, if one exists */
if (priv->secondary) {
if (!mm_serial_port_open (MM_SERIAL_PORT (priv->secondary), &info->error)) {

View File

@@ -79,6 +79,8 @@ typedef struct {
guint pending_reg_id;
MMCallbackInfo *pending_reg_info;
guint signal_quality_id;
time_t signal_quality_timestamp;
guint32 signal_quality;
guint32 cid;
@@ -113,6 +115,17 @@ static gboolean handle_reg_status_response (MMGenericGsm *self,
static MMModemGsmAccessTech etsi_act_to_mm_act (gint act);
static void _internal_update_access_technology (MMGenericGsm *modem,
MMModemGsmAccessTech act);
static void reg_info_updated (MMGenericGsm *self,
gboolean update_rs,
MMModemGsmNetworkRegStatus status,
gboolean update_code,
const char *oper_code,
gboolean update_name,
const char *oper_name);
MMModem *
mm_generic_gsm_new (const char *device,
const char *driver,
@@ -145,14 +158,6 @@ mm_generic_gsm_get_cid (MMGenericGsm *modem)
return MM_GENERIC_GSM_GET_PRIVATE (modem)->cid;
}
static void
got_signal_quality (MMModem *modem,
guint32 result,
GError *error,
gpointer user_data)
{
}
typedef struct {
const char *result;
const char *normalized;
@@ -699,6 +704,9 @@ mm_generic_gsm_enable_complete (MMGenericGsm *self,
}
}
/* Try to enable XON/XOFF flow control */
mm_at_serial_port_queue_command (priv->primary, "+IFC=1,1", 3, NULL, NULL);
/* Get allowed mode */
if (MM_GENERIC_GSM_GET_CLASS (self)->get_allowed_mode)
MM_GENERIC_GSM_GET_CLASS (self)->get_allowed_mode (self, get_allowed_mode_done, NULL);
@@ -842,13 +850,18 @@ disable_done (MMAtSerialPort *port,
info->error = mm_modem_check_removed (info->modem, error);
if (!info->error) {
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
MMGenericGsm *self = MM_GENERIC_GSM (info->modem);
mm_serial_port_close (MM_SERIAL_PORT (port));
mm_modem_set_state (MM_MODEM (info->modem),
MM_MODEM_STATE_DISABLED,
MM_MODEM_STATE_REASON_NONE);
priv->reg_status = MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN;
/* Clear out registration info */
reg_info_updated (self,
TRUE, MM_MODEM_GSM_NETWORK_REG_STATUS_UNKNOWN,
TRUE, NULL,
TRUE, NULL);
}
mm_callback_info_schedule (info);
}
@@ -903,11 +916,16 @@ disable (MMModem *modem,
priv->poll_id = 0;
}
if (priv->signal_quality_id) {
g_source_remove (priv->signal_quality_id);
priv->signal_quality_id = 0;
}
priv->lac[0] = 0;
priv->lac[1] = 0;
priv->cell_id[0] = 0;
priv->cell_id[1] = 0;
mm_generic_gsm_update_access_technology (self, MM_MODEM_GSM_ACCESS_TECH_UNKNOWN);
_internal_update_access_technology (self, MM_MODEM_GSM_ACCESS_TECH_UNKNOWN);
/* Close the secondary port if its open */
if (priv->secondary && mm_serial_port_is_open (MM_SERIAL_PORT (priv->secondary)))
@@ -1268,6 +1286,49 @@ change_pin (MMModemGsmCard *modem,
g_free (command);
}
static void
reg_info_updated (MMGenericGsm *self,
gboolean update_rs,
MMModemGsmNetworkRegStatus status,
gboolean update_code,
const char *oper_code,
gboolean update_name,
const char *oper_name)
{
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
gboolean changed = FALSE;
if (update_rs) {
if (status != priv->reg_status) {
priv->reg_status = status;
changed = TRUE;
}
}
if (update_code) {
if (g_strcmp0 (oper_code, priv->oper_code) != 0) {
g_free (priv->oper_code);
priv->oper_code = g_strdup (oper_code);
changed = TRUE;
}
}
if (update_name) {
if (g_strcmp0 (oper_name, priv->oper_name) != 0) {
g_free (priv->oper_name);
priv->oper_name = g_strdup (oper_name);
changed = TRUE;
}
}
if (changed) {
mm_modem_gsm_network_registration_info (MM_MODEM_GSM_NETWORK (self),
priv->reg_status,
priv->oper_code,
priv->oper_name);
}
}
static char *
parse_operator (const char *reply)
{
@@ -1300,18 +1361,14 @@ read_operator_code_done (MMAtSerialPort *port,
GError *error,
gpointer user_data)
{
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (user_data);
MMGenericGsm *self = MM_GENERIC_GSM (user_data);
char *oper;
if (error)
return;
oper = parse_operator (response->str);
if (!oper)
return;
g_free (priv->oper_code);
priv->oper_code = oper;
if (!error) {
oper = parse_operator (response->str);
if (oper)
reg_info_updated (self, FALSE, 0, TRUE, oper, FALSE, NULL);
}
}
static void
@@ -1320,23 +1377,14 @@ read_operator_name_done (MMAtSerialPort *port,
GError *error,
gpointer user_data)
{
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (user_data);
MMGenericGsm *self = MM_GENERIC_GSM (user_data);
char *oper;
if (error)
return;
oper = parse_operator (response->str);
if (!oper)
return;
g_free (priv->oper_name);
priv->oper_name = oper;
mm_modem_gsm_network_registration_info (MM_MODEM_GSM_NETWORK (user_data),
priv->reg_status,
priv->oper_code,
priv->oper_name);
if (!error) {
oper = parse_operator (response->str);
if (oper)
reg_info_updated (self, FALSE, 0, FALSE, NULL, TRUE, oper);
}
}
/* Registration */
@@ -1363,6 +1411,15 @@ mm_generic_gsm_pending_registration_stop (MMGenericGsm *modem)
}
}
static void
got_signal_quality (MMModem *modem,
guint32 quality,
GError *error,
gpointer user_data)
{
mm_generic_gsm_update_signal_quality (MM_GENERIC_GSM (modem), quality);
}
void
mm_generic_gsm_set_reg_status (MMGenericGsm *modem,
MMModemGsmNetworkRegStatus status)
@@ -1383,14 +1440,8 @@ mm_generic_gsm_set_reg_status (MMGenericGsm *modem,
mm_at_serial_port_queue_command (priv->primary, "+COPS=3,2;+COPS?", 3, read_operator_code_done, modem);
mm_at_serial_port_queue_command (priv->primary, "+COPS=3,0;+COPS?", 3, read_operator_name_done, modem);
mm_modem_gsm_network_get_signal_quality (MM_MODEM_GSM_NETWORK (modem), got_signal_quality, NULL);
} else {
g_free (priv->oper_code);
g_free (priv->oper_name);
priv->oper_code = priv->oper_name = NULL;
mm_modem_gsm_network_registration_info (MM_MODEM_GSM_NETWORK (modem), priv->reg_status,
priv->oper_code, priv->oper_name);
}
} else
reg_info_updated (MM_GENERIC_GSM (modem), FALSE, 0, TRUE, NULL, TRUE, NULL);
mm_generic_gsm_update_enabled_state (modem, TRUE, MM_MODEM_STATE_REASON_NONE);
}
@@ -1480,14 +1531,21 @@ reg_state_changed (MMAtSerialPort *port,
return;
}
if (reg_status_updated (self, state, NULL)) {
/* If registration is finished (either registered or failed) but the
* registration query hasn't completed yet, just remove the timeout and
* let the registration query complete.
*/
if (priv->pending_reg_id) {
g_source_remove (priv->pending_reg_id);
priv->pending_reg_id = 0;
/* Don't update reg state on CGREG responses since for many devices it's
* unclear what that registration state that actually reflects. We'll
* take CGREG registration state into account later when we have a more
* consistent way of handling it.
*/
if (cgreg == FALSE) {
if (reg_status_updated (self, state, NULL)) {
/* If registration is finished (either registered or failed) but the
* registration query hasn't completed yet, just remove the timeout and
* let the registration query complete.
*/
if (priv->pending_reg_id) {
g_source_remove (priv->pending_reg_id);
priv->pending_reg_id = 0;
}
}
}
@@ -1668,7 +1726,11 @@ registration_timed_out (gpointer data)
g_warn_if_fail (info == priv->pending_reg_info);
priv->reg_status = MM_MODEM_GSM_NETWORK_REG_STATUS_IDLE;
/* Clear out registration info */
reg_info_updated (MM_GENERIC_GSM (info->modem),
TRUE, MM_MODEM_GSM_NETWORK_REG_STATUS_IDLE,
TRUE, NULL,
TRUE, NULL);
info->error = mm_mobile_error_for_code (MM_MOBILE_ERROR_NETWORK_TIMEOUT);
mm_generic_gsm_pending_registration_stop (MM_GENERIC_GSM (info->modem));
@@ -2133,26 +2195,91 @@ set_apn (MMModemGsmNetwork *modem,
/* GetSignalQuality */
static gboolean
emit_signal_quality_change (gpointer user_data)
{
MMGenericGsm *self = MM_GENERIC_GSM (user_data);
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
priv->signal_quality_id = 0;
priv->signal_quality_timestamp = time (NULL);
mm_modem_gsm_network_signal_quality (MM_MODEM_GSM_NETWORK (self), priv->signal_quality);
return FALSE;
}
void
mm_generic_gsm_update_signal_quality (MMGenericGsm *self, guint32 quality)
{
MMGenericGsmPrivate *priv;
guint delay = 0;
g_return_if_fail (self != NULL);
g_return_if_fail (MM_IS_GENERIC_GSM (self));
g_return_if_fail (quality <= 100);
priv = MM_GENERIC_GSM_GET_PRIVATE (self);
if (priv->signal_quality == quality)
return;
priv->signal_quality = quality;
/* Some modems will send unsolcited signal quality changes quite often,
* so rate-limit them to every few seconds. Track the last time we
* emitted signal quality so that we send the signal immediately if there
* haven't been any updates in a while.
*/
if (!priv->signal_quality_id) {
if (priv->signal_quality_timestamp > 0) {
time_t curtime;
long int diff;
curtime = time (NULL);
diff = curtime - priv->signal_quality_timestamp;
if (diff == 0) {
/* If the device is sending more than one update per second,
* make sure we don't spam clients with signals.
*/
delay = 3;
} else if ((diff > 0) && (diff <= 3)) {
/* Emitted an update less than 3 seconds ago; schedule an update
* 3 seconds after the previous one.
*/
delay = (guint) diff;
} else {
/* Otherwise, we haven't emitted an update in the last 3 seconds,
* or the user turned their clock back, or something like that.
*/
delay = 0;
}
}
priv->signal_quality_id = g_timeout_add_seconds (delay,
emit_signal_quality_change,
self);
}
}
static void
get_signal_quality_done (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
MMGenericGsmPrivate *priv;
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
char *reply = response->str;
gboolean parsed = FALSE;
if (error)
info->error = g_error_copy (error);
else if (!strncmp (reply, "+CSQ: ", 6)) {
info->error = mm_modem_check_removed (info->modem, error);
if (info->error)
goto done;
if (!strncmp (reply, "+CSQ: ", 6)) {
/* Got valid reply */
int quality;
int ber;
reply += 6;
if (sscanf (reply, "%d, %d", &quality, &ber)) {
if (sscanf (reply + 6, "%d, %d", &quality, &ber)) {
/* 99 means unknown */
if (quality == 99) {
info->error = g_error_new_literal (MM_MOBILE_ERROR,
@@ -2162,15 +2289,19 @@ get_signal_quality_done (MMAtSerialPort *port,
/* Normalize the quality */
quality = CLAMP (quality, 0, 31) * 100 / 31;
priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
priv->signal_quality = quality;
mm_generic_gsm_update_signal_quality (MM_GENERIC_GSM (info->modem), quality);
mm_callback_info_set_result (info, GUINT_TO_POINTER (quality), NULL);
}
} else
info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
"Could not parse signal quality results");
parsed = TRUE;
}
}
if (!parsed && !info->error) {
info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL,
"Could not parse signal quality results");
}
done:
mm_callback_info_schedule (info);
}
@@ -2185,7 +2316,6 @@ get_signal_quality (MMModemGsmNetwork *modem,
connected = mm_port_get_connected (MM_PORT (priv->primary));
if (connected && !priv->secondary) {
g_message ("Returning saved signal quality %d", priv->signal_quality);
callback (MM_MODEM (modem), priv->signal_quality, NULL, user_data);
return;
}
@@ -2221,19 +2351,19 @@ etsi_act_to_mm_act (gint act)
while (iter->mm_act != MM_MODEM_GSM_ACCESS_TECH_UNKNOWN) {
if (iter->etsi_act == act)
return iter->mm_act;
iter++;
}
return MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
}
void
mm_generic_gsm_update_access_technology (MMGenericGsm *modem,
MMModemGsmAccessTech act)
static void
_internal_update_access_technology (MMGenericGsm *modem,
MMModemGsmAccessTech act)
{
MMGenericGsmPrivate *priv;
g_return_if_fail (modem != NULL);
g_return_if_fail (MM_IS_GENERIC_GSM (modem));
g_return_if_fail (act >= MM_MODEM_GSM_ACCESS_TECH_UNKNOWN && act <= MM_MODEM_GSM_ACCESS_TECH_LAST);
priv = MM_GENERIC_GSM_GET_PRIVATE (modem);
@@ -2250,6 +2380,18 @@ mm_generic_gsm_update_access_technology (MMGenericGsm *modem,
}
}
void
mm_generic_gsm_update_access_technology (MMGenericGsm *self,
MMModemGsmAccessTech act)
{
g_return_if_fail (self != NULL);
g_return_if_fail (MM_IS_GENERIC_GSM (self));
/* For plugins, don't update the access tech when the modem isn't enabled */
if (mm_modem_get_state (MM_MODEM (self)) >= MM_MODEM_STATE_ENABLED)
_internal_update_access_technology (self, act);
}
void
mm_generic_gsm_update_allowed_mode (MMGenericGsm *self,
MMModemGsmAllowedMode mode)
@@ -2509,8 +2651,6 @@ simple_connect (MMModemSimple *simple,
simple_state_machine (MM_MODEM (simple), NULL, info);
}
static void
simple_free_gvalue (gpointer data)
{
@@ -2542,16 +2682,39 @@ simple_string_value (const char *str)
return val;
}
#define NOTDONE_TAG "not-done"
#define SS_HASH_TAG "simple-get-status"
static void
simple_status_complete_item (MMCallbackInfo *info)
{
guint32 completed = GPOINTER_TO_UINT (mm_callback_info_get_data (info, NOTDONE_TAG));
g_warn_if_fail (completed > 0);
/* Decrement the number of outstanding calls and if there aren't any left,
* schedule the callback info completion.
*/
completed--;
mm_callback_info_set_data (info, NOTDONE_TAG, GUINT_TO_POINTER (completed), NULL);
if (completed == 0)
mm_callback_info_schedule (info);
}
static void
simple_status_got_signal_quality (MMModem *modem,
guint32 result,
GError *error,
gpointer user_data)
{
if (error)
g_warning ("Error getting signal quality: %s", error->message);
else
g_hash_table_insert ((GHashTable *) user_data, "signal_quality", simple_uint_value (result));
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
GHashTable *properties;
if (!error) {
properties = (GHashTable *) mm_callback_info_get_data (info, SS_HASH_TAG);
g_hash_table_insert (properties, "signal_quality", simple_uint_value (result));
}
simple_status_complete_item (info);
}
static void
@@ -2560,9 +2723,14 @@ simple_status_got_band (MMModem *modem,
GError *error,
gpointer user_data)
{
/* Ignore band errors since there's no generic implementation for it */
if (!error)
g_hash_table_insert ((GHashTable *) user_data, "band", simple_uint_value (result));
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
GHashTable *properties;
if (!error) {
properties = (GHashTable *) mm_callback_info_get_data (info, SS_HASH_TAG);
g_hash_table_insert (properties, "band", simple_uint_value (result));
}
simple_status_complete_item (info);
}
static void
@@ -2576,17 +2744,15 @@ simple_status_got_reg_info (MMModemGsmNetwork *modem,
MMCallbackInfo *info = (MMCallbackInfo *) user_data;
GHashTable *properties;
if (error)
info->error = g_error_copy (error);
else {
properties = (GHashTable *) mm_callback_info_get_data (info, "simple-get-status");
info->error = mm_modem_check_removed ((MMModem *) modem, error);
if (!info->error) {
properties = (GHashTable *) mm_callback_info_get_data (info, SS_HASH_TAG);
g_hash_table_insert (properties, "registration_status", simple_uint_value (status));
g_hash_table_insert (properties, "operator_code", simple_string_value (oper_code));
g_hash_table_insert (properties, "operator_name", simple_string_value (oper_name));
}
mm_callback_info_schedule (info);
simple_status_complete_item (info);
}
static void
@@ -2595,7 +2761,7 @@ simple_get_status_invoke (MMCallbackInfo *info)
MMModemSimpleGetStatusFn callback = (MMModemSimpleGetStatusFn) info->callback;
callback (MM_MODEM_SIMPLE (info->modem),
(GHashTable *) mm_callback_info_get_data (info, "simple-get-status"),
(GHashTable *) mm_callback_info_get_data (info, SS_HASH_TAG),
info->error, info->user_data);
}
@@ -2615,12 +2781,15 @@ simple_get_status (MMModemSimple *simple,
G_CALLBACK (callback),
user_data);
properties = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, simple_free_gvalue);
mm_callback_info_set_data (info, "simple-get-status", properties, (GDestroyNotify) g_hash_table_unref);
properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, simple_free_gvalue);
mm_callback_info_set_data (info, SS_HASH_TAG, properties, (GDestroyNotify) g_hash_table_unref);
mm_modem_gsm_network_get_signal_quality (gsm, simple_status_got_signal_quality, properties);
mm_modem_gsm_network_get_band (gsm, simple_status_got_band, properties);
mm_modem_gsm_network_get_registration_info (gsm, simple_status_got_reg_info, properties);
mm_modem_gsm_network_get_signal_quality (gsm, simple_status_got_signal_quality, info);
mm_modem_gsm_network_get_band (gsm, simple_status_got_band, info);
mm_modem_gsm_network_get_registration_info (gsm, simple_status_got_reg_info, info);
/* 3 calls to complete before scheduling the callback: (signal, band, reginfo) */
mm_callback_info_set_data (info, NOTDONE_TAG, GUINT_TO_POINTER (3), NULL);
if (priv->act > -1) {
/* Deprecated key */
@@ -2791,6 +2960,11 @@ finalize (GObject *object)
priv->poll_id = 0;
}
if (priv->signal_quality_id) {
g_source_remove (priv->signal_quality_id);
priv->signal_quality_id = 0;
}
mm_gsm_creg_regex_destroy (priv->reg_regex);
g_free (priv->oper_code);

View File

@@ -133,6 +133,11 @@ void mm_generic_gsm_update_allowed_mode (MMGenericGsm *modem,
void mm_generic_gsm_update_access_technology (MMGenericGsm *modem,
MMModemGsmAccessTech act);
/* Called to asynchronously update the current signal quality of the device;
* 'quality' is a 0 - 100% quality.
*/
void mm_generic_gsm_update_signal_quality (MMGenericGsm *modem, guint32 quality);
void mm_generic_gsm_check_pin (MMGenericGsm *modem,
MMModemFn callback,
gpointer user_data);

View File

@@ -205,22 +205,22 @@ mm_gsm_destroy_scan_data (gpointer data)
/*************************************************************************/
/* +CREG: <stat> (GSM 07.07 CREG=1 unsolicited) */
#define CREG1 "\\+CG?REG:\\s*(\\d{1})"
#define CREG1 "\\+(CREG|CGREG):\\s*(\\d{1})"
/* +CREG: <n>,<stat> (GSM 07.07 CREG=1 solicited) */
#define CREG2 "\\+CG?REG:\\s*(\\d{1}),\\s*(\\d{1})"
#define CREG2 "\\+(CREG|CGREG):\\s*(\\d{1}),\\s*(\\d{1})"
/* +CREG: <stat>,<lac>,<ci> (GSM 07.07 CREG=2 unsolicited) */
#define CREG3 "\\+CG?REG:\\s*(\\d{1}),\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)"
#define CREG3 "\\+(CREG|CGREG):\\s*(\\d{1}),\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)"
/* +CREG: <n>,<stat>,<lac>,<ci> (GSM 07.07 solicited and some CREG=2 unsolicited) */
#define CREG4 "\\+CG?REG:\\s*(\\d{1}),\\s*(\\d{1})\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)"
#define CREG4 "\\+(CREG|CGREG):\\s*(\\d{1}),\\s*(\\d{1})\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)"
/* +CREG: <stat>,<lac>,<ci>,<AcT> (ETSI 27.007 CREG=2 unsolicited) */
#define CREG5 "\\+CG?REG:\\s*(\\d{1})\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*(\\d{1,2})"
#define CREG5 "\\+(CREG|CGREG):\\s*(\\d{1})\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*(\\d{1,2})"
/* +CREG: <n>,<stat>,<lac>,<ci>,<AcT> (ETSI 27.007 solicited and some CREG=2 unsolicited) */
#define CREG6 "\\+CG?REG:\\s*(\\d{1}),\\s*(\\d{1})\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*(\\d{1,2})"
#define CREG6 "\\+(CREG|CGREG):\\s*(\\d{1}),\\s*(\\d{1})\\s*,\\s*([^,\\s]*)\\s*,\\s*([^,\\s]*)\\s*,\\s*(\\d{1,2})"
GPtrArray *
mm_gsm_creg_regex_get (gboolean solicited)
@@ -319,7 +319,7 @@ mm_gsm_parse_creg_response (GMatchInfo *info,
gulong *out_lac,
gulong *out_ci,
gint *out_act,
gboolean *out_greg,
gboolean *out_cgreg,
GError **error)
{
gboolean success = FALSE, foo;
@@ -327,56 +327,60 @@ mm_gsm_parse_creg_response (GMatchInfo *info,
gulong stat = 0, lac = 0, ci = 0;
guint istat = 0, ilac = 0, ici = 0, iact = 0;
char *str;
const char *orig_str;
g_return_val_if_fail (info != NULL, FALSE);
g_return_val_if_fail (out_reg_state != NULL, FALSE);
g_return_val_if_fail (out_lac != NULL, FALSE);
g_return_val_if_fail (out_ci != NULL, FALSE);
g_return_val_if_fail (out_act != NULL, FALSE);
g_return_val_if_fail (out_greg != NULL, FALSE);
g_return_val_if_fail (out_cgreg != NULL, FALSE);
str = g_match_info_fetch (info, 1);
if (str && strstr (str, "CGREG"))
*out_cgreg = TRUE;
/* Normally the number of matches could be used to determine what each
* item is, but we have overlap in one case.
*/
n_matches = g_match_info_get_match_count (info);
if (n_matches == 2) {
if (n_matches == 3) {
/* CREG=1: +CREG: <stat> */
istat = 1;
} else if (n_matches == 3) {
/* Solicited response: +CREG: <n>,<stat> */
istat = 2;
} else if (n_matches == 4) {
/* CREG=2 (GSM 07.07): +CREG: <stat>,<lac>,<ci> */
istat = 1;
ilac = 2;
ici = 3;
/* Solicited response: +CREG: <n>,<stat> */
istat = 3;
} else if (n_matches == 5) {
/* CREG=2 (GSM 07.07): +CREG: <stat>,<lac>,<ci> */
istat = 2;
ilac = 3;
ici = 4;
} else if (n_matches == 6) {
/* CREG=2 (ETSI 27.007): +CREG: <stat>,<lac>,<ci>,<AcT>
* CREG=2 (non-standard): +CREG: <n>,<stat>,<lac>,<ci>
*/
/* To distinguish, check length of the second match item. If it's
* more than one digit or has quotes in it, then we have the first format.
/* To distinguish, check length of the third match item. If it's
* more than one digit or has quotes in it then it's a LAC and we
* got the first format.
*/
str = g_match_info_fetch (info, 2);
str = g_match_info_fetch (info, 3);
if (str && (strchr (str, '"') || strlen (str) > 1)) {
g_free (str);
istat = 1;
ilac = 2;
ici = 3;
iact = 4;
} else {
istat = 2;
ilac = 3;
ici = 4;
iact = 5;
} else {
istat = 3;
ilac = 4;
ici = 5;
}
} else if (n_matches == 6) {
} else if (n_matches == 7) {
/* CREG=2 (non-standard): +CREG: <n>,<stat>,<lac>,<ci>,<AcT> */
istat = 2;
ilac = 3;
ici = 4;
iact = 5;
istat = 3;
ilac = 4;
ici = 5;
iact = 6;
}
/* Status */
@@ -416,9 +420,6 @@ mm_gsm_parse_creg_response (GMatchInfo *info,
act = -1;
}
orig_str = g_match_info_get_string (info);
*out_greg = !!strstr (orig_str, "+CGREG");
*out_reg_state = (guint32) stat;
if (stat != 4) {
/* Don't fill in lac/ci/act if the device's state is unknown */

View File

@@ -36,7 +36,7 @@ gboolean mm_gsm_parse_creg_response (GMatchInfo *info,
gulong *out_lac,
gulong *out_ci,
gint *out_act,
gboolean *out_greg,
gboolean *out_cgreg,
GError **error);
#endif /* MM_MODEM_HELPERS_H */

View File

@@ -321,8 +321,14 @@ real_config_fd (MMSerialPort *self, int fd, GError **error)
stbuf.c_cc[VTIME] = 0;
stbuf.c_cc[VEOF] = 1;
stbuf.c_cflag &= ~(CBAUD | CSIZE | CSTOPB | CLOCAL | PARENB);
stbuf.c_cflag |= (speed | bits | CREAD | 0 | parity | stopbits);
/* Use software handshaking */
stbuf.c_iflag |= (IXON | IXOFF | IXANY);
/* Set up port speed and serial attributes; also ignore modem control
* lines since most drivers don't implement RTS/CTS anyway.
*/
stbuf.c_cflag &= ~(CBAUD | CSIZE | CSTOPB | PARENB | CRTSCTS);
stbuf.c_cflag |= (speed | bits | CREAD | 0 | parity | stopbits | CLOCAL);
if (ioctl (fd, TCSETA, &stbuf) < 0) {
g_set_error (error,

View File

@@ -670,6 +670,25 @@ test_cgreg2_f3607gw_unsolicited (void *f, gpointer d)
test_creg_match ("Ericsson F3607gw CGREG=2", FALSE, reply, data, &result);
}
static void
test_creg_cgreg_multi_unsolicited (void *f, gpointer d)
{
TestData *data = (TestData *) d;
const char *reply = "\r\n+CREG: 5\r\n\r\n+CGREG: 0\r\n";
const CregResult result = { 5, 0, 0, -1, 1, FALSE};
test_creg_match ("Multi CREG/CGREG", FALSE, reply, data, &result);
}
static void
test_creg_cgreg_multi2_unsolicited (void *f, gpointer d)
{
TestData *data = (TestData *) d;
const char *reply = "\r\n+CGREG: 0\r\n\r\n+CREG: 5\r\n";
const CregResult result = { 0, 0, 0, -1, 1, TRUE};
test_creg_match ("Multi CREG/CGREG #2", FALSE, reply, data, &result);
}
static TestData *
test_data_new (void)
@@ -753,6 +772,9 @@ int main (int argc, char **argv)
g_test_suite_add (suite, TESTCASE (test_cgreg2_f3607gw_solicited, data));
g_test_suite_add (suite, TESTCASE (test_cgreg2_f3607gw_unsolicited, data));
g_test_suite_add (suite, TESTCASE (test_creg_cgreg_multi_unsolicited, data));
g_test_suite_add (suite, TESTCASE (test_creg_cgreg_multi2_unsolicited, data));
result = g_test_run ();
test_data_free (data);