Merge remote-tracking branch 'lanedo/power-up-check-needed'

This commit is contained in:
Aleksander Morgado
2011-06-30 19:48:23 +02:00
7 changed files with 329 additions and 59 deletions
+131 -5
View File
@@ -27,9 +27,11 @@
#include "mm-serial-parsers.h"
#include "mm-log.h"
static void modem_init (MMModem *modem_class);
static void modem_gsm_network_init (MMModemGsmNetwork *gsm_network_class);
G_DEFINE_TYPE_EXTENDED (MMModemCinterionGsm, mm_modem_cinterion_gsm, 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))
/* Mask of all bands supported in 2G devices */
@@ -66,6 +68,9 @@ typedef struct {
/* Bitmask for currently active bands */
guint32 current_bands;
/* Command to go into sleep mode */
gchar *sleep_mode_cmd;
} MMModemCinterionGsmPrivate;
/* Setup relationship between the band bitmask in the modem and the bitmask
@@ -132,6 +137,37 @@ mm_modem_cinterion_gsm_new (const char *device,
NULL));
}
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 (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)) {
/* Set RTS/CTS flow control by default */
g_object_set (G_OBJECT (port),
MM_SERIAL_PORT_RTS_CTS, TRUE,
NULL);
}
return !!port;
}
static void
convert_str_from_ucs2 (gchar **str)
{
@@ -833,6 +869,55 @@ enable_complete (MMGenericGsm *gsm,
mm_generic_gsm_enable_complete (MM_GENERIC_GSM (info->modem), error, info);
}
static void
get_supported_functionality_status_cb (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
MMCallbackInfo *info = user_data;
MMModemCinterionGsmPrivate *priv;
/* If the modem has already been removed, return without
* scheduling callback */
if (mm_callback_info_check_modem_removed (info))
return;
if (error) {
enable_complete (MM_GENERIC_GSM (info->modem), error, info);
return;
}
priv = MM_MODEM_CINTERION_GSM_GET_PRIVATE (info->modem);
/* 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.
*/
g_free (priv->sleep_mode_cmd);
if (strstr (response->str, "4") != NULL) {
mm_dbg ("Device supports CFUN=4 sleep mode");
priv->sleep_mode_cmd = g_strdup ("+CFUN=4");
} else if (strstr (response->str, "7") != NULL) {
mm_dbg ("Device supports CFUN=7 sleep mode");
priv->sleep_mode_cmd = g_strdup ("+CFUN=7");
} else {
mm_warn ("Unknown functionality mode to go into sleep mode");
priv->sleep_mode_cmd = NULL;
}
/* All done without errors! */
mm_dbg ("[3/3] All done");
enable_complete (MM_GENERIC_GSM (info->modem), NULL, info);
}
static void
get_supported_networks_cb (MMAtSerialPort *port,
GString *response,
@@ -841,7 +926,6 @@ get_supported_networks_cb (MMAtSerialPort *port,
{
MMCallbackInfo *info = user_data;
MMModemCinterionGsmPrivate *priv;
GError *inner_error = NULL;
/* If the modem has already been removed, return without
* scheduling callback */
@@ -880,17 +964,22 @@ get_supported_networks_cb (MMAtSerialPort *port,
if (!priv->only_geran &&
!priv->only_utran &&
!priv->both_geran_utran) {
GError *inner_error = NULL;
mm_warn ("Invalid list of supported networks: '%s'",
response->str);
inner_error = g_error_new (MM_MODEM_ERROR,
MM_MODEM_ERROR_GENERAL,
"Invalid list of supported networks: '%s'",
response->str);
enable_complete (MM_GENERIC_GSM (info->modem), inner_error, info);
g_error_free (inner_error);
return;
}
enable_complete (MM_GENERIC_GSM (info->modem), inner_error, info);
if (inner_error)
g_error_free (inner_error);
/* Next, check which supported functionality modes are available */
mm_dbg ("[2/3] Getting list of supported functionality status...");
mm_at_serial_port_queue_command (port, "+CFUN=?", 3, get_supported_functionality_status_cb, info);
}
static void
@@ -915,7 +1004,8 @@ do_enable_power_up_done (MMGenericGsm *gsm,
return;
}
/* List supported networks */
/* First, list supported networks */
mm_dbg ("[1/3] Getting list of supported networks...");
mm_at_serial_port_queue_command (port, "+WS46=?", 3, get_supported_networks_cb, info);
}
@@ -934,7 +1024,13 @@ get_property (GObject *object,
GValue *value,
GParamSpec *pspec)
{
MMModemCinterionGsmPrivate *priv = MM_MODEM_CINTERION_GSM_GET_PRIVATE (object);
switch (prop_id) {
case MM_GENERIC_GSM_PROP_FLOW_CONTROL_CMD:
/* We need to enable RTS/CTS so that CYCLIC SLEEP mode works */
g_value_set_string (value, "\\Q3");
break;
case MM_GENERIC_GSM_PROP_SMS_INDICATION_ENABLE_CMD:
/* AT+CNMO=<mode>,[<mt>[,<bm>[,<ds>[,<bfr>]]]]
* but <bfr> should be either not set, or equal to 1;
@@ -956,13 +1052,33 @@ get_property (GObject *object,
* */
g_value_set_string (value, "+CMER=3,0,0,2");
break;
case MM_GENERIC_GSM_PROP_POWER_DOWN_CMD:
/* Use the value computed before, if any. */
g_value_set_string (value, priv->sleep_mode_cmd ? priv->sleep_mode_cmd : "");
break;
default:
break;
}
}
static void
finalize (GObject *object)
{
MMModemCinterionGsmPrivate *priv = MM_MODEM_CINTERION_GSM_GET_PRIVATE (object);
g_free (priv->sleep_mode_cmd);
G_OBJECT_CLASS (mm_modem_cinterion_gsm_parent_class)->finalize (object);
}
/*****************************************************************************/
static void
modem_init (MMModem *modem_class)
{
modem_class->grab_port = grab_port;
}
static void
modem_gsm_network_init (MMModemGsmNetwork *network_class)
{
@@ -990,11 +1106,17 @@ mm_modem_cinterion_gsm_class_init (MMModemCinterionGsmClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
MMGenericGsmClass *gsm_class = MM_GENERIC_GSM_CLASS (klass);
mm_modem_cinterion_gsm_parent_class = g_type_class_peek_parent (klass);
g_type_class_add_private (object_class, sizeof (MMModemCinterionGsmPrivate));
object_class->finalize = finalize;
object_class->get_property = get_property;
object_class->set_property = set_property;
g_object_class_override_property (object_class,
MM_GENERIC_GSM_PROP_FLOW_CONTROL_CMD,
MM_GENERIC_GSM_FLOW_CONTROL_CMD);
g_object_class_override_property (object_class,
MM_GENERIC_GSM_PROP_SMS_INDICATION_ENABLE_CMD,
MM_GENERIC_GSM_SMS_INDICATION_ENABLE_CMD);
@@ -1007,6 +1129,10 @@ mm_modem_cinterion_gsm_class_init (MMModemCinterionGsmClass *klass)
MM_GENERIC_GSM_PROP_CMER_ENABLE_CMD,
MM_GENERIC_GSM_CMER_ENABLE_CMD);
g_object_class_override_property (object_class,
MM_GENERIC_GSM_PROP_POWER_DOWN_CMD,
MM_GENERIC_GSM_POWER_DOWN_CMD);
gsm_class->do_enable_power_up_done = do_enable_power_up_done;
gsm_class->set_allowed_mode = set_allowed_mode;
gsm_class->get_allowed_mode = get_allowed_mode;
+60
View File
@@ -25,6 +25,7 @@
#include "mm-modem-simple.h"
#include "mm-callback-info.h"
#include "mm-modem-helpers.h"
#include "mm-log.h"
static void modem_init (MMModem *modem_class);
static void modem_simple_init (MMModemSimple *class);
@@ -391,6 +392,64 @@ real_do_enable_power_up_done (MMGenericGsm *gsm,
priv->enable_wait_id = g_timeout_add_seconds (10, sierra_enabled, info);
}
static void
get_current_functionality_status_cb (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
MMCallbackInfo *info = user_data;
guint needed = FALSE;
/* If the modem has already been removed, return without
* scheduling callback */
if (mm_callback_info_check_modem_removed (info))
return;
/* On error, just assume we don't need the power-up command */
if (!error) {
const gchar *p;
p = mm_strip_tag (response->str, "+CFUN:");
if (p && *p == '1') {
/* If reported functionality status is '1', then we do not need to
* issue the power-up command. Otherwise, do it. */
mm_dbg ("Already in full functionality status, skipping power-up command");
} else {
needed = TRUE;
mm_warn ("Not in full functionality status, power-up command is needed.");
}
} else
mm_warn ("Failed checking if power-up command is needed: '%s'. "
"Will assume it isn't.",
error->message);
/* Set result and schedule */
mm_callback_info_set_result (info,
GUINT_TO_POINTER (needed),
NULL);
mm_callback_info_schedule (info);
}
static void
do_enable_power_up_check_needed (MMGenericGsm *self,
MMModemUIntFn callback,
gpointer user_data)
{
MMAtSerialPort *primary;
MMCallbackInfo *info;
info = mm_callback_info_uint_new (MM_MODEM (self), callback, user_data);
/* Get port */
primary = mm_generic_gsm_get_at_port (self, MM_PORT_TYPE_PRIMARY);
g_assert (primary);
/* Get current functionality status */
mm_dbg ("Getting current functionality status...");
mm_at_serial_port_queue_command (primary, "+CFUN?", 3, get_current_functionality_status_cb, info);
}
static gboolean
grab_port (MMModem *modem,
const char *subsys,
@@ -689,6 +748,7 @@ mm_modem_sierra_gsm_class_init (MMModemSierraGsmClass *klass)
g_type_class_add_private (object_class, sizeof (MMModemSierraGsmPrivate));
object_class->dispose = dispose;
gsm_class->do_enable_power_up_check_needed = do_enable_power_up_check_needed;
gsm_class->do_enable_power_up_done = real_do_enable_power_up_done;
gsm_class->set_allowed_mode = set_allowed_mode;
gsm_class->get_allowed_mode = get_allowed_mode;
+78 -47
View File
@@ -218,15 +218,20 @@ get_property (GObject *object,
{
switch (prop_id) {
case MM_GENERIC_GSM_PROP_POWER_UP_CMD:
/* Wavecom doesn't like CFUN=1, it will reset the whole software stack,
* including the USB connection and therefore connection would get
* closed */
g_value_set_string (value, "");
/* Try to go to full functionality mode without rebooting the system.
* Works well if we previously switched off the power with CFUN=4
*/
g_value_set_string (value, "+CFUN=1,0");
break;
case MM_GENERIC_GSM_PROP_FLOW_CONTROL_CMD:
/* Wavecom doesn't have XOFF/XON flow control, so we enable RTS/CTS */
g_value_set_string (value, "+IFC=2,2");
break;
case MM_GENERIC_GSM_PROP_POWER_DOWN_CMD:
/* Use AT+CFUN=4 for power down. It will stop the RF (IMSI detach), and
* keeps access to the SIM */
g_value_set_string (value, "+CFUN=4");
break;
default:
break;
}
@@ -869,7 +874,7 @@ set_highest_ms_class_cb (MMAtSerialPort *port,
}
/* All done without errors! */
mm_dbg ("[5/5] All done");
mm_dbg ("[4/4] All done");
enable_complete (MM_GENERIC_GSM (info->modem), NULL, info);
}
@@ -975,7 +980,7 @@ get_current_ms_class_cb (MMAtSerialPort *port,
}
/* Next, set highest mobile station class possible */
mm_dbg ("[4/5] Ensuring highest MS class...");
mm_dbg ("[3/4] Ensuring highest MS class...");
set_highest_ms_class (port, info);
}
@@ -1039,47 +1044,10 @@ get_supported_ms_classes_cb (MMAtSerialPort *port,
}
/* Next, query for current MS class */
mm_dbg ("[3/5] Getting current MS class...");
mm_dbg ("[2/4] Getting current MS class...");
mm_at_serial_port_queue_command (port, "+CGCLASS?", 3, get_current_ms_class_cb, info);
}
static void
get_current_functionality_status_cb (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
MMCallbackInfo *info = user_data;
const gchar *p;
GError *inner_error;
/* If the modem has already been removed, return without
* scheduling callback */
if (mm_callback_info_check_modem_removed (info))
return;
if (error) {
enable_complete (MM_GENERIC_GSM (info->modem), error, info);
return;
}
p = mm_strip_tag (response->str, "+CFUN:");
if (!p || *p != '1') {
/* Reported functionality status MUST be '1'. Otherwise, RF is probably
* switched off. */
inner_error = g_error_new (MM_MODEM_ERROR,
MM_MODEM_ERROR_GENERAL,
"Unexpected functionality status: '%c'. ",
p ? *p :' ');
enable_complete (MM_GENERIC_GSM (info->modem), inner_error, info);
g_error_free (inner_error);
}
/* Nex, query for supported MS classes */
mm_dbg ("[2/5] Getting supported MS classes...");
mm_at_serial_port_queue_command (port, "+CGCLASS=?", 3, get_supported_ms_classes_cb, info);
}
static void
do_enable_power_up_done (MMGenericGsm *gsm,
GString *response,
@@ -1107,9 +1075,67 @@ do_enable_power_up_done (MMGenericGsm *gsm,
return;
}
/* Next, get current functionality status */
mm_dbg ("[1/5] Getting current functionality status...");
mm_at_serial_port_queue_command (port, "+CFUN?", 3, get_current_functionality_status_cb, info);
mm_dbg ("[1/4] Getting supported MS classes...");
mm_at_serial_port_queue_command (port, "+CGCLASS=?", 3, get_supported_ms_classes_cb, info);
}
static void
get_current_functionality_status_cb (MMAtSerialPort *port,
GString *response,
GError *error,
gpointer user_data)
{
MMCallbackInfo *info = user_data;
guint needed = FALSE;
/* If the modem has already been removed, return without
* scheduling callback */
if (mm_callback_info_check_modem_removed (info))
return;
/* On error, just assume we don't need the power-up command */
if (!error) {
const gchar *p;
p = mm_strip_tag (response->str, "+CFUN:");
if (p && *p == '1') {
/* If reported functionality status is '1', then we do not need to
* issue the power-up command. Otherwise, do it. */
mm_dbg ("Already in full functionality status, skipping power-up command");
} else {
needed = TRUE;
mm_warn ("Not in full functionality status, power-up command is needed. "
"Note that it may reboot the modem.");
}
} else
mm_warn ("Failed checking if power-up command is needed: '%s'. "
"Will assume it isn't.",
error->message);
/* Set result and schedule */
mm_callback_info_set_result (info,
GUINT_TO_POINTER (needed),
NULL);
mm_callback_info_schedule (info);
}
static void
do_enable_power_up_check_needed (MMGenericGsm *self,
MMModemUIntFn callback,
gpointer user_data)
{
MMAtSerialPort *primary;
MMCallbackInfo *info;
info = mm_callback_info_uint_new (MM_MODEM (self), callback, user_data);
/* Get port */
primary = mm_generic_gsm_get_at_port (self, MM_PORT_TYPE_PRIMARY);
g_assert (primary);
/* Get current functionality status */
mm_dbg ("Getting current functionality status...");
mm_at_serial_port_queue_command (primary, "+CFUN?", 3, get_current_functionality_status_cb, info);
}
/*****************************************************************************/
@@ -1158,6 +1184,11 @@ mm_modem_wavecom_gsm_class_init (MMModemWavecomGsmClass *klass)
MM_GENERIC_GSM_PROP_FLOW_CONTROL_CMD,
MM_GENERIC_GSM_FLOW_CONTROL_CMD);
g_object_class_override_property (object_class,
MM_GENERIC_GSM_PROP_POWER_DOWN_CMD,
MM_GENERIC_GSM_POWER_DOWN_CMD);
gsm_class->do_enable_power_up_check_needed = do_enable_power_up_check_needed;
gsm_class->do_enable_power_up_done = do_enable_power_up_done;
gsm_class->set_allowed_mode = set_allowed_mode;
gsm_class->get_allowed_mode = get_allowed_mode;