gsm: query signal strength with +CIND if modem does not support +CSQ (lp:682282)

This commit is contained in:
Dan Williams
2010-11-28 22:46:03 -06:00
parent 6d37c9b471
commit dc95f531ad
2 changed files with 186 additions and 34 deletions
+1 -31
View File
@@ -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
@@ -583,29 +580,6 @@ mbm_pacsp_received (MMAtSerialPort *port,
return;
}
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)
{
@@ -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);
+185 -3
View File
@@ -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,