aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--plugins/mm-modem-mbm.c32
-rw-r--r--src/mm-generic-gsm.c188
2 files changed, 186 insertions, 34 deletions
diff --git a/plugins/mm-modem-mbm.c b/plugins/mm-modem-mbm.c
index 763f61d2..53e98ba6 100644
--- a/plugins/mm-modem-mbm.c
+++ b/plugins/mm-modem-mbm.c
@@ -49,8 +49,6 @@ G_DEFINE_TYPE_EXTENDED (MMModemMbm, mm_modem_mbm, MM_TYPE_GENERIC_GSM, 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
@@ -353,7 +351,6 @@ 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);
@@ -477,7 +474,7 @@ disable (MMModem *modem,
g_assert (primary);
/* Turn off unsolicited responses */
- mm_at_serial_port_queue_command (primary, "+CMER=0;*ERINFO=0", 5, disable_unsolicited_done, info);
+ mm_at_serial_port_queue_command (primary, "*ERINFO=0", 5, disable_unsolicited_done, info);
}
static void
@@ -584,29 +581,6 @@ mbm_pacsp_received (MMAtSerialPort *port,
}
static void
-mbm_ciev_received (MMAtSerialPort *port,
- GMatchInfo *info,
- gpointer user_data)
-{
- int quality = 0, ind = 0;
- 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_generic_gsm_update_signal_quality (MM_GENERIC_GSM (user_data), quality * 20);
- }
- g_free (str);
- }
-}
-
-static void
mbm_do_connect_done (MMModemMbm *self, gboolean success)
{
MMModemMbmPrivate *priv = MM_MODEM_MBM_GET_PRIVATE (self);
@@ -923,10 +897,6 @@ grab_port (MMModem *modem,
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, NULL, NULL);
diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c
index faf71e56..2a4885a8 100644
--- a/src/mm-generic-gsm.c
+++ b/src/mm-generic-gsm.c
@@ -96,6 +96,11 @@ typedef struct {
MMCallbackInfo *pending_reg_info;
gboolean manual_reg;
+ gboolean cmer_enabled;
+ gint roam_ind;
+ gint signal_ind;
+ gint service_ind;
+
guint signal_quality_id;
time_t signal_quality_timestamp;
guint32 signal_quality;
@@ -157,6 +162,10 @@ static void reg_info_updated (MMGenericGsm *self,
static void update_lac_ci (MMGenericGsm *self, gulong lac, gulong ci, guint idx);
+static void ciev_received (MMAtSerialPort *port,
+ GMatchInfo *info,
+ gpointer user_data);
+
MMModem *
mm_generic_gsm_new (const char *device,
const char *driver,
@@ -804,6 +813,10 @@ mm_generic_gsm_grab_port (MMGenericGsm *self,
}
mm_gsm_creg_regex_destroy (array);
+ 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, ciev_received, self, NULL);
+ g_regex_unref (regex);
+
if (ptype == MM_PORT_TYPE_PRIMARY) {
priv->primary = MM_AT_SERIAL_PORT (port);
if (!priv->data) {
@@ -964,8 +977,8 @@ periodic_poll_cb (gpointer user_data)
mm_at_serial_port_queue_command (port, "+CGREG?", 10, reg_poll_response, self);
mm_modem_gsm_network_get_signal_quality (MM_MODEM_GSM_NETWORK (self),
- periodic_signal_quality_cb,
- NULL);
+ periodic_signal_quality_cb,
+ NULL);
if (MM_GENERIC_GSM_GET_CLASS (self)->get_access_technology)
MM_GENERIC_GSM_GET_CLASS (self)->get_access_technology (self, periodic_access_tech_cb, NULL);
@@ -1187,6 +1200,83 @@ get_allowed_mode_done (MMModem *modem,
}
}
+static void
+ciev_received (MMAtSerialPort *port,
+ GMatchInfo *info,
+ gpointer user_data)
+{
+ MMGenericGsm *self = MM_GENERIC_GSM (user_data);
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self);
+ int quality = 0, ind = 0;
+ char *str;
+
+ if (!priv->cmer_enabled)
+ return;
+
+ str = g_match_info_fetch (info, 1);
+ if (str)
+ ind = atoi (str);
+ g_free (str);
+
+ if (ind == priv->signal_ind) {
+ str = g_match_info_fetch (info, 2);
+ if (str) {
+ quality = atoi (str);
+ mm_generic_gsm_update_signal_quality (self, quality * 20);
+ }
+ g_free (str);
+ }
+
+ /* FIXME: handle roaming and service indicators */
+}
+
+static void
+cmer_cb (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ if (!error)
+ MM_GENERIC_GSM_GET_PRIVATE (user_data)->cmer_enabled = TRUE;
+}
+
+static void
+cind_cb (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMGenericGsm *self;
+ MMGenericGsmPrivate *priv;
+ GHashTable *indicators;
+
+ if (error)
+ return;
+
+ self = MM_GENERIC_GSM (user_data);
+ priv = MM_GENERIC_GSM_GET_PRIVATE (self);
+
+ indicators = mm_parse_cind_response (response->str, NULL);
+ if (indicators) {
+ CindResponse *r;
+
+ r = g_hash_table_lookup (indicators, "signal");
+ if (r)
+ priv->signal_ind = cind_response_get_index (r);
+
+ r = g_hash_table_lookup (indicators, "roam");
+ if (r)
+ priv->roam_ind = cind_response_get_index (r);
+
+ r = g_hash_table_lookup (indicators, "service");
+ if (r)
+ priv->service_ind = cind_response_get_index (r);
+
+ mm_at_serial_port_queue_command (port, "+CMER=3,0,0,1", 3, cmer_cb, self);
+ g_hash_table_destroy (indicators);
+ }
+}
+
void
mm_generic_gsm_enable_complete (MMGenericGsm *self,
GError *error,
@@ -1224,6 +1314,8 @@ 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);
+ mm_at_serial_port_queue_command (priv->primary, "+CIND=?", 3, cind_cb, self);
+
/* Try one more time to get the SIM ID */
if (!priv->simid)
MM_GENERIC_GSM_GET_CLASS (self)->get_sim_iccid (self, get_iccid_done, NULL);
@@ -1406,6 +1498,7 @@ disable_flash_done (MMSerialPort *port,
GError *error,
gpointer user_data)
{
+ MMGenericGsmPrivate *priv;
MMCallbackInfo *info = user_data;
MMModemState prev_state;
char *cmd = NULL;
@@ -1424,10 +1517,17 @@ disable_flash_done (MMSerialPort *port,
return;
}
+ priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
+
/* Disable unsolicited messages */
mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), "AT+CREG=0", 3, NULL, NULL);
mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), "AT+CGREG=0", 3, NULL, NULL);
+ if (priv->cmer_enabled) {
+ mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), "+CMER=0", 3, NULL, NULL);
+ priv->cmer_enabled = FALSE;
+ }
+
g_object_get (G_OBJECT (info->modem), MM_GENERIC_GSM_POWER_DOWN_CMD, &cmd, NULL);
if (cmd && strlen (cmd))
mm_at_serial_port_queue_command (MM_AT_SERIAL_PORT (port), cmd, 5, disable_done, user_data);
@@ -3187,6 +3287,72 @@ mm_generic_gsm_update_signal_quality (MMGenericGsm *self, guint32 quality)
}
}
+#define CIND_TAG "+CIND:"
+
+static void
+cind_signal_cb (MMAtSerialPort *port,
+ GString *response,
+ GError *error,
+ gpointer user_data)
+{
+ MMCallbackInfo *info = (MMCallbackInfo *) user_data;
+ const char *p = response->str;
+ GRegex *r = NULL;
+ GMatchInfo *match_info;
+ int i = 1, quality = -1;
+
+ info->error = mm_modem_check_removed (info->modem, error);
+ if (info->error)
+ goto done;
+
+ if (!g_str_has_prefix (p, CIND_TAG)) {
+ info->error = g_error_new_literal (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Could not parse the +CIND response");
+ goto done;
+ }
+
+ p += strlen (CIND_TAG);
+ while (isspace (*p))
+ p++;
+
+ r = g_regex_new ("(\\d+)[^0-9]+", G_REGEX_UNGREEDY, 0, NULL);
+ if (!r) {
+ info->error = g_error_new_literal (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Internal failure attempting to parse +CIND response");
+ goto done;
+ }
+
+ if (!g_regex_match_full (r, p, strlen (p), 0, 0, &match_info, NULL)) {
+ info->error = g_error_new_literal (MM_MODEM_ERROR,
+ MM_MODEM_ERROR_GENERAL,
+ "Failure parsing the +CIND response");
+ goto done;
+ }
+
+ while (g_match_info_matches (match_info)) {
+ if (MM_GENERIC_GSM_GET_PRIVATE (info->modem)->signal_ind == i++) {
+ char *str = g_match_info_fetch (match_info, 1);
+
+ if (str) {
+ quality = atoi (str);
+ mm_generic_gsm_update_signal_quality (MM_GENERIC_GSM (info->modem), quality * 20);
+ g_free (str);
+ break;
+ }
+ }
+ g_match_info_next (match_info, NULL);
+ }
+ g_match_info_free (match_info);
+
+done:
+ if (r)
+ g_regex_unref (r);
+
+ mm_callback_info_schedule (info);
+}
+
static void
get_signal_quality_done (MMAtSerialPort *port,
GString *response,
@@ -3198,8 +3364,21 @@ get_signal_quality_done (MMAtSerialPort *port,
gboolean parsed = FALSE;
info->error = mm_modem_check_removed (info->modem, error);
- if (info->error)
+ if (info->error) {
+ if (info->modem) {
+ MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem);
+
+ /* Modem won't do unsolicited reporting via +CMER/+CIEV, but still
+ * supports +CIND.
+ */
+ if (!priv->cmer_enabled && (priv->signal_ind >= 0)) {
+ g_clear_error (&info->error);
+ mm_at_serial_port_queue_command (port, "+CIND?", 3, cind_signal_cb, info);
+ return;
+ }
+ }
goto done;
+ }
if (!strncmp (reply, "+CSQ: ", 6)) {
/* Got valid reply */
@@ -4509,6 +4688,9 @@ mm_generic_gsm_init (MMGenericGsm *self)
priv->act = MM_MODEM_GSM_ACCESS_TECH_UNKNOWN;
priv->reg_regex = mm_gsm_creg_regex_get (TRUE);
priv->roam_allowed = TRUE;
+ priv->signal_ind = -1;
+ priv->roam_ind = -1;
+ priv->service_ind = -1;
mm_properties_changed_signal_register_property (G_OBJECT (self),
MM_MODEM_GSM_NETWORK_ALLOWED_MODE,