simtech: enable +CSQ URC support
The +AUTOCSQ setup enables automatic signal quality reporting via +CSQ URCs, which unfortunately have the same format as the +CSQ command responses. Therefore, we need to subclass load_signal_quality() explicitly in order to ignore those cases where the response to the +CSQ command is received empty (already processed as a URC).
This commit is contained in:
@@ -53,6 +53,7 @@ G_DEFINE_TYPE_EXTENDED (MMBroadbandModemSimtech, mm_broadband_modem_simtech, MM_
|
|||||||
|
|
||||||
struct _MMBroadbandModemSimtechPrivate {
|
struct _MMBroadbandModemSimtechPrivate {
|
||||||
GRegex *cnsmod_regex;
|
GRegex *cnsmod_regex;
|
||||||
|
GRegex *csq_regex;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@@ -95,6 +96,24 @@ simtech_tech_changed (MMPortSerialAt *port,
|
|||||||
g_free (str);
|
g_free (str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
simtech_signal_changed (MMPortSerialAt *port,
|
||||||
|
GMatchInfo *match_info,
|
||||||
|
MMBroadbandModemSimtech *self)
|
||||||
|
{
|
||||||
|
guint quality = 0;
|
||||||
|
|
||||||
|
if (!mm_get_uint_from_match_info (match_info, 1, &quality))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (quality != 99)
|
||||||
|
quality = CLAMP (quality, 0, 31) * 100 / 31;
|
||||||
|
else
|
||||||
|
quality = 0;
|
||||||
|
|
||||||
|
mm_iface_modem_update_signal_quality (MM_IFACE_MODEM (self), quality);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_unsolicited_events_handlers (MMBroadbandModemSimtech *self,
|
set_unsolicited_events_handlers (MMBroadbandModemSimtech *self,
|
||||||
gboolean enable)
|
gboolean enable)
|
||||||
@@ -117,6 +136,14 @@ set_unsolicited_events_handlers (MMBroadbandModemSimtech *self,
|
|||||||
enable ? (MMPortSerialAtUnsolicitedMsgFn)simtech_tech_changed : NULL,
|
enable ? (MMPortSerialAtUnsolicitedMsgFn)simtech_tech_changed : NULL,
|
||||||
enable ? self : NULL,
|
enable ? self : NULL,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
/* Signal quality related */
|
||||||
|
mm_port_serial_at_add_unsolicited_msg_handler (
|
||||||
|
ports[i],
|
||||||
|
self->priv->csq_regex,
|
||||||
|
enable ? (MMPortSerialAtUnsolicitedMsgFn)simtech_signal_changed : NULL,
|
||||||
|
enable ? self : NULL,
|
||||||
|
NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,6 +433,85 @@ load_access_technologies (MMIfaceModem *self,
|
|||||||
task);
|
task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Load signal quality (Modem interface) */
|
||||||
|
|
||||||
|
static guint
|
||||||
|
load_signal_quality_finish (MMIfaceModem *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
gssize value;
|
||||||
|
|
||||||
|
value = g_task_propagate_int (G_TASK (res), error);
|
||||||
|
return value < 0 ? 0 : value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
csq_query_ready (MMBaseModem *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GTask *task)
|
||||||
|
{
|
||||||
|
const gchar *response, *p;
|
||||||
|
GError *error = NULL;
|
||||||
|
gint quality;
|
||||||
|
gint ber;
|
||||||
|
|
||||||
|
response = mm_base_modem_at_command_finish (MM_BASE_MODEM (self), res, &error);
|
||||||
|
if (!response) {
|
||||||
|
g_task_return_error (task, error);
|
||||||
|
g_object_unref (task);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Given that we may have enabled AUTOCSQ support, it is totally possible
|
||||||
|
* to get an empty string at this point, because the +CSQ reply may have
|
||||||
|
* been processed as an URC already. If we ever see this, we should not return
|
||||||
|
* an error, because that would reset the reported signal quality to 0 :/
|
||||||
|
* So, in this case, return the last cached signal quality value. */
|
||||||
|
if (!response[0]) {
|
||||||
|
g_task_return_new_error (task, MM_CORE_ERROR, MM_CORE_ERROR_IN_PROGRESS,
|
||||||
|
"already refreshed via URCs");
|
||||||
|
g_object_unref (task);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = mm_strip_tag (response, "+CSQ:");
|
||||||
|
if (sscanf (p, "%d, %d", &quality, &ber)) {
|
||||||
|
if (quality != 99)
|
||||||
|
quality = CLAMP (quality, 0, 31) * 100 / 31;
|
||||||
|
else
|
||||||
|
quality = 0;
|
||||||
|
g_task_return_int (task, quality);
|
||||||
|
g_object_unref (task);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_task_return_new_error (task,
|
||||||
|
MM_CORE_ERROR,
|
||||||
|
MM_CORE_ERROR_FAILED,
|
||||||
|
"Could not parse signal quality results");
|
||||||
|
g_object_unref (task);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
load_signal_quality (MMIfaceModem *self,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GTask *task;
|
||||||
|
|
||||||
|
task = g_task_new (self, NULL, callback, user_data);
|
||||||
|
|
||||||
|
mm_base_modem_at_command (
|
||||||
|
MM_BASE_MODEM (self),
|
||||||
|
"+CSQ",
|
||||||
|
3,
|
||||||
|
FALSE,
|
||||||
|
(GAsyncReadyCallback)csq_query_ready,
|
||||||
|
task);
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Load supported modes (Modem interface) */
|
/* Load supported modes (Modem interface) */
|
||||||
|
|
||||||
@@ -838,6 +944,8 @@ mm_broadband_modem_simtech_init (MMBroadbandModemSimtech *self)
|
|||||||
|
|
||||||
self->priv->cnsmod_regex = g_regex_new ("\\r\\n\\+CNSMOD:\\s*(\\d)\\r\\n",
|
self->priv->cnsmod_regex = g_regex_new ("\\r\\n\\+CNSMOD:\\s*(\\d)\\r\\n",
|
||||||
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
||||||
|
self->priv->csq_regex = g_regex_new ("\\r\\n\\+CSQ:\\s*(\\d+),(\\d+)\\r\\n",
|
||||||
|
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -846,6 +954,7 @@ finalize (GObject *object)
|
|||||||
MMBroadbandModemSimtech *self = MM_BROADBAND_MODEM_SIMTECH (object);
|
MMBroadbandModemSimtech *self = MM_BROADBAND_MODEM_SIMTECH (object);
|
||||||
|
|
||||||
g_regex_unref (self->priv->cnsmod_regex);
|
g_regex_unref (self->priv->cnsmod_regex);
|
||||||
|
g_regex_unref (self->priv->csq_regex);
|
||||||
|
|
||||||
G_OBJECT_CLASS (mm_broadband_modem_simtech_parent_class)->finalize (object);
|
G_OBJECT_CLASS (mm_broadband_modem_simtech_parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
@@ -855,6 +964,8 @@ iface_modem_init (MMIfaceModem *iface)
|
|||||||
{
|
{
|
||||||
iface_modem_parent = g_type_interface_peek_parent (iface);
|
iface_modem_parent = g_type_interface_peek_parent (iface);
|
||||||
|
|
||||||
|
iface->load_signal_quality = load_signal_quality;
|
||||||
|
iface->load_signal_quality_finish = load_signal_quality_finish;
|
||||||
iface->load_access_technologies = load_access_technologies;
|
iface->load_access_technologies = load_access_technologies;
|
||||||
iface->load_access_technologies_finish = load_access_technologies_finish;
|
iface->load_access_technologies_finish = load_access_technologies_finish;
|
||||||
iface->load_supported_modes = load_supported_modes;
|
iface->load_supported_modes = load_supported_modes;
|
||||||
|
Reference in New Issue
Block a user