Merge remote-tracking branch 'lanedo/power-up-check-needed'
This commit is contained in:
@@ -27,9 +27,11 @@
|
|||||||
#include "mm-serial-parsers.h"
|
#include "mm-serial-parsers.h"
|
||||||
#include "mm-log.h"
|
#include "mm-log.h"
|
||||||
|
|
||||||
|
static void modem_init (MMModem *modem_class);
|
||||||
static void modem_gsm_network_init (MMModemGsmNetwork *gsm_network_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_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))
|
G_IMPLEMENT_INTERFACE (MM_TYPE_MODEM_GSM_NETWORK, modem_gsm_network_init))
|
||||||
|
|
||||||
/* Mask of all bands supported in 2G devices */
|
/* Mask of all bands supported in 2G devices */
|
||||||
@@ -66,6 +68,9 @@ typedef struct {
|
|||||||
|
|
||||||
/* Bitmask for currently active bands */
|
/* Bitmask for currently active bands */
|
||||||
guint32 current_bands;
|
guint32 current_bands;
|
||||||
|
|
||||||
|
/* Command to go into sleep mode */
|
||||||
|
gchar *sleep_mode_cmd;
|
||||||
} MMModemCinterionGsmPrivate;
|
} MMModemCinterionGsmPrivate;
|
||||||
|
|
||||||
/* Setup relationship between the band bitmask in the modem and the bitmask
|
/* 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));
|
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
|
static void
|
||||||
convert_str_from_ucs2 (gchar **str)
|
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);
|
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
|
static void
|
||||||
get_supported_networks_cb (MMAtSerialPort *port,
|
get_supported_networks_cb (MMAtSerialPort *port,
|
||||||
GString *response,
|
GString *response,
|
||||||
@@ -841,7 +926,6 @@ get_supported_networks_cb (MMAtSerialPort *port,
|
|||||||
{
|
{
|
||||||
MMCallbackInfo *info = user_data;
|
MMCallbackInfo *info = user_data;
|
||||||
MMModemCinterionGsmPrivate *priv;
|
MMModemCinterionGsmPrivate *priv;
|
||||||
GError *inner_error = NULL;
|
|
||||||
|
|
||||||
/* If the modem has already been removed, return without
|
/* If the modem has already been removed, return without
|
||||||
* scheduling callback */
|
* scheduling callback */
|
||||||
@@ -880,17 +964,22 @@ get_supported_networks_cb (MMAtSerialPort *port,
|
|||||||
if (!priv->only_geran &&
|
if (!priv->only_geran &&
|
||||||
!priv->only_utran &&
|
!priv->only_utran &&
|
||||||
!priv->both_geran_utran) {
|
!priv->both_geran_utran) {
|
||||||
|
GError *inner_error = NULL;
|
||||||
|
|
||||||
mm_warn ("Invalid list of supported networks: '%s'",
|
mm_warn ("Invalid list of supported networks: '%s'",
|
||||||
response->str);
|
response->str);
|
||||||
inner_error = g_error_new (MM_MODEM_ERROR,
|
inner_error = g_error_new (MM_MODEM_ERROR,
|
||||||
MM_MODEM_ERROR_GENERAL,
|
MM_MODEM_ERROR_GENERAL,
|
||||||
"Invalid list of supported networks: '%s'",
|
"Invalid list of supported networks: '%s'",
|
||||||
response->str);
|
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);
|
/* Next, check which supported functionality modes are available */
|
||||||
if (inner_error)
|
mm_dbg ("[2/3] Getting list of supported functionality status...");
|
||||||
g_error_free (inner_error);
|
mm_at_serial_port_queue_command (port, "+CFUN=?", 3, get_supported_functionality_status_cb, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -915,7 +1004,8 @@ do_enable_power_up_done (MMGenericGsm *gsm,
|
|||||||
return;
|
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);
|
mm_at_serial_port_queue_command (port, "+WS46=?", 3, get_supported_networks_cb, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -934,7 +1024,13 @@ get_property (GObject *object,
|
|||||||
GValue *value,
|
GValue *value,
|
||||||
GParamSpec *pspec)
|
GParamSpec *pspec)
|
||||||
{
|
{
|
||||||
|
MMModemCinterionGsmPrivate *priv = MM_MODEM_CINTERION_GSM_GET_PRIVATE (object);
|
||||||
|
|
||||||
switch (prop_id) {
|
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:
|
case MM_GENERIC_GSM_PROP_SMS_INDICATION_ENABLE_CMD:
|
||||||
/* AT+CNMO=<mode>,[<mt>[,<bm>[,<ds>[,<bfr>]]]]
|
/* AT+CNMO=<mode>,[<mt>[,<bm>[,<ds>[,<bfr>]]]]
|
||||||
* but <bfr> should be either not set, or equal to 1;
|
* 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");
|
g_value_set_string (value, "+CMER=3,0,0,2");
|
||||||
break;
|
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:
|
default:
|
||||||
break;
|
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
|
static void
|
||||||
modem_gsm_network_init (MMModemGsmNetwork *network_class)
|
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);
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
MMGenericGsmClass *gsm_class = MM_GENERIC_GSM_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));
|
g_type_class_add_private (object_class, sizeof (MMModemCinterionGsmPrivate));
|
||||||
|
|
||||||
|
object_class->finalize = finalize;
|
||||||
object_class->get_property = get_property;
|
object_class->get_property = get_property;
|
||||||
object_class->set_property = set_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,
|
g_object_class_override_property (object_class,
|
||||||
MM_GENERIC_GSM_PROP_SMS_INDICATION_ENABLE_CMD,
|
MM_GENERIC_GSM_PROP_SMS_INDICATION_ENABLE_CMD,
|
||||||
MM_GENERIC_GSM_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_PROP_CMER_ENABLE_CMD,
|
||||||
MM_GENERIC_GSM_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->do_enable_power_up_done = do_enable_power_up_done;
|
||||||
gsm_class->set_allowed_mode = set_allowed_mode;
|
gsm_class->set_allowed_mode = set_allowed_mode;
|
||||||
gsm_class->get_allowed_mode = get_allowed_mode;
|
gsm_class->get_allowed_mode = get_allowed_mode;
|
||||||
|
@@ -25,6 +25,7 @@
|
|||||||
#include "mm-modem-simple.h"
|
#include "mm-modem-simple.h"
|
||||||
#include "mm-callback-info.h"
|
#include "mm-callback-info.h"
|
||||||
#include "mm-modem-helpers.h"
|
#include "mm-modem-helpers.h"
|
||||||
|
#include "mm-log.h"
|
||||||
|
|
||||||
static void modem_init (MMModem *modem_class);
|
static void modem_init (MMModem *modem_class);
|
||||||
static void modem_simple_init (MMModemSimple *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);
|
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
|
static gboolean
|
||||||
grab_port (MMModem *modem,
|
grab_port (MMModem *modem,
|
||||||
const char *subsys,
|
const char *subsys,
|
||||||
@@ -689,6 +748,7 @@ mm_modem_sierra_gsm_class_init (MMModemSierraGsmClass *klass)
|
|||||||
g_type_class_add_private (object_class, sizeof (MMModemSierraGsmPrivate));
|
g_type_class_add_private (object_class, sizeof (MMModemSierraGsmPrivate));
|
||||||
|
|
||||||
object_class->dispose = dispose;
|
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->do_enable_power_up_done = real_do_enable_power_up_done;
|
||||||
gsm_class->set_allowed_mode = set_allowed_mode;
|
gsm_class->set_allowed_mode = set_allowed_mode;
|
||||||
gsm_class->get_allowed_mode = get_allowed_mode;
|
gsm_class->get_allowed_mode = get_allowed_mode;
|
||||||
|
@@ -218,15 +218,20 @@ get_property (GObject *object,
|
|||||||
{
|
{
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case MM_GENERIC_GSM_PROP_POWER_UP_CMD:
|
case MM_GENERIC_GSM_PROP_POWER_UP_CMD:
|
||||||
/* Wavecom doesn't like CFUN=1, it will reset the whole software stack,
|
/* Try to go to full functionality mode without rebooting the system.
|
||||||
* including the USB connection and therefore connection would get
|
* Works well if we previously switched off the power with CFUN=4
|
||||||
* closed */
|
*/
|
||||||
g_value_set_string (value, "");
|
g_value_set_string (value, "+CFUN=1,0");
|
||||||
break;
|
break;
|
||||||
case MM_GENERIC_GSM_PROP_FLOW_CONTROL_CMD:
|
case MM_GENERIC_GSM_PROP_FLOW_CONTROL_CMD:
|
||||||
/* Wavecom doesn't have XOFF/XON flow control, so we enable RTS/CTS */
|
/* Wavecom doesn't have XOFF/XON flow control, so we enable RTS/CTS */
|
||||||
g_value_set_string (value, "+IFC=2,2");
|
g_value_set_string (value, "+IFC=2,2");
|
||||||
break;
|
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:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -869,7 +874,7 @@ set_highest_ms_class_cb (MMAtSerialPort *port,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* All done without errors! */
|
/* 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);
|
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 */
|
/* 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);
|
set_highest_ms_class (port, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1039,47 +1044,10 @@ get_supported_ms_classes_cb (MMAtSerialPort *port,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Next, query for current MS class */
|
/* 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);
|
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
|
static void
|
||||||
do_enable_power_up_done (MMGenericGsm *gsm,
|
do_enable_power_up_done (MMGenericGsm *gsm,
|
||||||
GString *response,
|
GString *response,
|
||||||
@@ -1107,9 +1075,67 @@ do_enable_power_up_done (MMGenericGsm *gsm,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Next, get current functionality status */
|
mm_dbg ("[1/4] Getting supported MS classes...");
|
||||||
mm_dbg ("[1/5] Getting current functionality status...");
|
mm_at_serial_port_queue_command (port, "+CGCLASS=?", 3, get_supported_ms_classes_cb, info);
|
||||||
mm_at_serial_port_queue_command (port, "+CFUN?", 3, get_current_functionality_status_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_PROP_FLOW_CONTROL_CMD,
|
||||||
MM_GENERIC_GSM_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->do_enable_power_up_done = do_enable_power_up_done;
|
||||||
gsm_class->set_allowed_mode = set_allowed_mode;
|
gsm_class->set_allowed_mode = set_allowed_mode;
|
||||||
gsm_class->get_allowed_mode = get_allowed_mode;
|
gsm_class->get_allowed_mode = get_allowed_mode;
|
||||||
|
@@ -1540,6 +1540,27 @@ enable_done (MMAtSerialPort *port,
|
|||||||
info);
|
info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
enable_power_up_check_needed_done (MMModem *self,
|
||||||
|
guint32 needed,
|
||||||
|
GError *error,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
|
||||||
|
char *cmd = NULL;
|
||||||
|
|
||||||
|
if (needed)
|
||||||
|
g_object_get (G_OBJECT (self), MM_GENERIC_GSM_POWER_UP_CMD, &cmd, NULL);
|
||||||
|
else
|
||||||
|
mm_dbg ("Power-up not needed, skipping...");
|
||||||
|
|
||||||
|
if (cmd && strlen (cmd))
|
||||||
|
mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (priv->primary), cmd, 5, enable_done, user_data);
|
||||||
|
else
|
||||||
|
enable_done (MM_AT_SERIAL_PORT (priv->primary), NULL, NULL, user_data);
|
||||||
|
g_free (cmd);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
init_done (MMAtSerialPort *port,
|
init_done (MMAtSerialPort *port,
|
||||||
GString *response,
|
GString *response,
|
||||||
@@ -1573,12 +1594,13 @@ init_done (MMAtSerialPort *port,
|
|||||||
mm_at_serial_port_queue_command (port, cmd, 2, NULL, NULL);
|
mm_at_serial_port_queue_command (port, cmd, 2, NULL, NULL);
|
||||||
g_free (cmd);
|
g_free (cmd);
|
||||||
|
|
||||||
g_object_get (G_OBJECT (info->modem), MM_GENERIC_GSM_POWER_UP_CMD, &cmd, NULL);
|
/* Plugins can now check if they need the power up command or not */
|
||||||
if (cmd && strlen (cmd))
|
if (MM_GENERIC_GSM_GET_CLASS (info->modem)->do_enable_power_up_check_needed)
|
||||||
mm_at_serial_port_queue_command (port, cmd, 5, enable_done, user_data);
|
MM_GENERIC_GSM_GET_CLASS (info->modem)->do_enable_power_up_check_needed (MM_GENERIC_GSM (info->modem),
|
||||||
|
enable_power_up_check_needed_done,
|
||||||
|
info);
|
||||||
else
|
else
|
||||||
enable_done (port, NULL, NULL, user_data);
|
enable_power_up_check_needed_done (info->modem, TRUE, NULL, info);
|
||||||
g_free (cmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -4875,7 +4897,7 @@ ussd_send_done (MMAtSerialPort *port,
|
|||||||
ussd_update_state (MM_GENERIC_GSM (info->modem), MM_MODEM_GSM_USSD_STATE_IDLE);
|
ussd_update_state (MM_GENERIC_GSM (info->modem), MM_MODEM_GSM_USSD_STATE_IDLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Otherwise if no error wait for the response to show up via the
|
/* Otherwise if no error wait for the response to show up via the
|
||||||
* unsolicited response code.
|
* unsolicited response code.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
@@ -90,7 +90,15 @@ typedef struct {
|
|||||||
* encountered during the process and the MMCallbackInfo created from the
|
* encountered during the process and the MMCallbackInfo created from the
|
||||||
* callback and user_data passed in here.
|
* callback and user_data passed in here.
|
||||||
*/
|
*/
|
||||||
void (*do_enable) (MMGenericGsm *self, MMModemFn callback, gpointer user_data);
|
void (*do_enable) (MMGenericGsm *self,
|
||||||
|
MMModemFn callback,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
/* Called before issuing the power-up command, to check whether it should
|
||||||
|
* really be issued or not. */
|
||||||
|
void (*do_enable_power_up_check_needed) (MMGenericGsm *self,
|
||||||
|
MMModemUIntFn callback,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
/* Called after the generic class has attempted to power up the modem.
|
/* Called after the generic class has attempted to power up the modem.
|
||||||
* Subclasses can handle errors here if they know the device supports their
|
* Subclasses can handle errors here if they know the device supports their
|
||||||
@@ -143,6 +151,7 @@ typedef struct {
|
|||||||
void (*get_sim_iccid) (MMGenericGsm *self,
|
void (*get_sim_iccid) (MMGenericGsm *self,
|
||||||
MMModemStringFn callback,
|
MMModemStringFn callback,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
|
|
||||||
} MMGenericGsmClass;
|
} MMGenericGsmClass;
|
||||||
|
|
||||||
GType mm_generic_gsm_get_type (void);
|
GType mm_generic_gsm_get_type (void);
|
||||||
|
@@ -45,6 +45,7 @@ enum {
|
|||||||
PROP_SEND_DELAY,
|
PROP_SEND_DELAY,
|
||||||
PROP_FD,
|
PROP_FD,
|
||||||
PROP_SPEW_CONTROL,
|
PROP_SPEW_CONTROL,
|
||||||
|
PROP_RTS_CTS,
|
||||||
|
|
||||||
LAST_PROP
|
LAST_PROP
|
||||||
};
|
};
|
||||||
@@ -78,6 +79,7 @@ typedef struct {
|
|||||||
guint stopbits;
|
guint stopbits;
|
||||||
guint64 send_delay;
|
guint64 send_delay;
|
||||||
gboolean spew_control;
|
gboolean spew_control;
|
||||||
|
gboolean rts_cts;
|
||||||
|
|
||||||
guint queue_id;
|
guint queue_id;
|
||||||
guint watch_id;
|
guint watch_id;
|
||||||
@@ -1059,6 +1061,7 @@ get_speed (MMSerialPort *self, speed_t *speed, GError **error)
|
|||||||
static gboolean
|
static gboolean
|
||||||
set_speed (MMSerialPort *self, speed_t speed, GError **error)
|
set_speed (MMSerialPort *self, speed_t speed, GError **error)
|
||||||
{
|
{
|
||||||
|
MMSerialPortPrivate *priv = MM_SERIAL_PORT_GET_PRIVATE (self);
|
||||||
struct termios options;
|
struct termios options;
|
||||||
int fd, count = 4;
|
int fd, count = 4;
|
||||||
gboolean success = FALSE;
|
gboolean success = FALSE;
|
||||||
@@ -1079,6 +1082,10 @@ set_speed (MMSerialPort *self, speed_t speed, GError **error)
|
|||||||
cfsetospeed (&options, speed);
|
cfsetospeed (&options, speed);
|
||||||
options.c_cflag |= (CLOCAL | CREAD);
|
options.c_cflag |= (CLOCAL | CREAD);
|
||||||
|
|
||||||
|
/* Configure flow control as well here */
|
||||||
|
if (priv->rts_cts)
|
||||||
|
options.c_cflag |= (CRTSCTS);
|
||||||
|
|
||||||
while (count-- > 0) {
|
while (count-- > 0) {
|
||||||
if (tcsetattr (fd, TCSANOW, &options) == 0) {
|
if (tcsetattr (fd, TCSANOW, &options) == 0) {
|
||||||
success = TRUE;
|
success = TRUE;
|
||||||
@@ -1311,6 +1318,9 @@ set_property (GObject *object, guint prop_id,
|
|||||||
case PROP_SPEW_CONTROL:
|
case PROP_SPEW_CONTROL:
|
||||||
priv->spew_control = g_value_get_boolean (value);
|
priv->spew_control = g_value_get_boolean (value);
|
||||||
break;
|
break;
|
||||||
|
case PROP_RTS_CTS:
|
||||||
|
priv->rts_cts = g_value_get_boolean (value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
@@ -1345,6 +1355,9 @@ get_property (GObject *object, guint prop_id,
|
|||||||
case PROP_SPEW_CONTROL:
|
case PROP_SPEW_CONTROL:
|
||||||
g_value_set_boolean (value, priv->spew_control);
|
g_value_set_boolean (value, priv->spew_control);
|
||||||
break;
|
break;
|
||||||
|
case PROP_RTS_CTS:
|
||||||
|
g_value_set_boolean (value, priv->rts_cts);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
@@ -1455,6 +1468,14 @@ mm_serial_port_class_init (MMSerialPortClass *klass)
|
|||||||
FALSE,
|
FALSE,
|
||||||
G_PARAM_READWRITE));
|
G_PARAM_READWRITE));
|
||||||
|
|
||||||
|
g_object_class_install_property
|
||||||
|
(object_class, PROP_RTS_CTS,
|
||||||
|
g_param_spec_boolean (MM_SERIAL_PORT_RTS_CTS,
|
||||||
|
"RTSCTS",
|
||||||
|
"Enable RTS/CTS flow control",
|
||||||
|
FALSE,
|
||||||
|
G_PARAM_READWRITE));
|
||||||
|
|
||||||
/* Signals */
|
/* Signals */
|
||||||
signals[BUFFER_FULL] =
|
signals[BUFFER_FULL] =
|
||||||
g_signal_new ("buffer-full",
|
g_signal_new ("buffer-full",
|
||||||
|
@@ -35,6 +35,7 @@
|
|||||||
#define MM_SERIAL_PORT_PARITY "parity"
|
#define MM_SERIAL_PORT_PARITY "parity"
|
||||||
#define MM_SERIAL_PORT_STOPBITS "stopbits"
|
#define MM_SERIAL_PORT_STOPBITS "stopbits"
|
||||||
#define MM_SERIAL_PORT_SEND_DELAY "send-delay"
|
#define MM_SERIAL_PORT_SEND_DELAY "send-delay"
|
||||||
|
#define MM_SERIAL_PORT_RTS_CTS "rts-cts"
|
||||||
#define MM_SERIAL_PORT_FD "fd" /* Construct-only */
|
#define MM_SERIAL_PORT_FD "fd" /* Construct-only */
|
||||||
#define MM_SERIAL_PORT_SPEW_CONTROL "spew-control" /* Construct-only */
|
#define MM_SERIAL_PORT_SPEW_CONTROL "spew-control" /* Construct-only */
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user