gsm: let generic class handle signal quality caching and updates
This commit is contained in:
@@ -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 (MMSerialPort *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
|
||||
|
@@ -561,7 +561,7 @@ mbm_ciev_received (MMSerialPort *port,
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -790,17 +790,19 @@ grab_port (MMModem *modem,
|
||||
}
|
||||
|
||||
port = mm_generic_gsm_grab_port (gsm, subsys, name, ptype, error);
|
||||
if (port && MM_IS_SERIAL_PORT (port) && (ptype == MM_PORT_TYPE_PRIMARY)) {
|
||||
if (port && MM_IS_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_serial_port_add_unsolicited_msg_handler (MM_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_serial_port_add_unsolicited_msg_handler (MM_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_serial_port_add_unsolicited_msg_handler (MM_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_serial_port_add_unsolicited_msg_handler (MM_SERIAL_PORT (port), regex, mbm_pacsp_received, modem, NULL);
|
||||
g_regex_unref (regex);
|
||||
|
@@ -78,6 +78,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;
|
||||
|
||||
@@ -144,14 +146,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;
|
||||
@@ -905,6 +899,11 @@ 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;
|
||||
@@ -1361,6 +1360,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)
|
||||
@@ -2138,26 +2146,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 (MMSerialPort *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,
|
||||
@@ -2167,15 +2240,19 @@ get_signal_quality_done (MMSerialPort *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);
|
||||
}
|
||||
|
||||
@@ -2190,7 +2267,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;
|
||||
}
|
||||
@@ -2824,6 +2900,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);
|
||||
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user