broadband-modem-huawei: implement Modem.Signal extended signal info interface
Implement the detailed signal info interface for some Huawei 3GPP modems including those based on HiSilicon chipsets like the E3276. Known not to work on many Qualcomm-based Huawei modems like E392, E397, and E367 as they don't support the ^HCSQ command, but they do support QMI and so have access to the extended signal interface via QMI.
This commit is contained in:
@@ -43,6 +43,7 @@
|
|||||||
#include "mm-iface-modem-location.h"
|
#include "mm-iface-modem-location.h"
|
||||||
#include "mm-iface-modem-time.h"
|
#include "mm-iface-modem-time.h"
|
||||||
#include "mm-iface-modem-cdma.h"
|
#include "mm-iface-modem-cdma.h"
|
||||||
|
#include "mm-iface-modem-signal.h"
|
||||||
#include "mm-iface-modem-voice.h"
|
#include "mm-iface-modem-voice.h"
|
||||||
#include "mm-broadband-modem-huawei.h"
|
#include "mm-broadband-modem-huawei.h"
|
||||||
#include "mm-broadband-bearer-huawei.h"
|
#include "mm-broadband-bearer-huawei.h"
|
||||||
@@ -58,6 +59,7 @@ static void iface_modem_location_init (MMIfaceModemLocation *iface);
|
|||||||
static void iface_modem_cdma_init (MMIfaceModemCdma *iface);
|
static void iface_modem_cdma_init (MMIfaceModemCdma *iface);
|
||||||
static void iface_modem_time_init (MMIfaceModemTime *iface);
|
static void iface_modem_time_init (MMIfaceModemTime *iface);
|
||||||
static void iface_modem_voice_init (MMIfaceModemVoice *iface);
|
static void iface_modem_voice_init (MMIfaceModemVoice *iface);
|
||||||
|
static void iface_modem_signal_init (MMIfaceModemSignal *iface);
|
||||||
|
|
||||||
static MMIfaceModem *iface_modem_parent;
|
static MMIfaceModem *iface_modem_parent;
|
||||||
static MMIfaceModem3gpp *iface_modem_3gpp_parent;
|
static MMIfaceModem3gpp *iface_modem_3gpp_parent;
|
||||||
@@ -72,7 +74,8 @@ G_DEFINE_TYPE_EXTENDED (MMBroadbandModemHuawei, mm_broadband_modem_huawei, MM_TY
|
|||||||
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_CDMA, iface_modem_cdma_init)
|
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_CDMA, iface_modem_cdma_init)
|
||||||
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init)
|
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_LOCATION, iface_modem_location_init)
|
||||||
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_TIME, iface_modem_time_init)
|
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_TIME, iface_modem_time_init)
|
||||||
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_VOICE, iface_modem_voice_init));
|
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_VOICE, iface_modem_voice_init)
|
||||||
|
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_SIGNAL, iface_modem_signal_init))
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
FEATURE_SUPPORT_UNKNOWN,
|
FEATURE_SUPPORT_UNKNOWN,
|
||||||
@@ -80,6 +83,14 @@ typedef enum {
|
|||||||
FEATURE_SUPPORTED
|
FEATURE_SUPPORTED
|
||||||
} FeatureSupport;
|
} FeatureSupport;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
MMSignal *cdma;
|
||||||
|
MMSignal *evdo;
|
||||||
|
MMSignal *gsm;
|
||||||
|
MMSignal *umts;
|
||||||
|
MMSignal *lte;
|
||||||
|
} DetailedSignal;
|
||||||
|
|
||||||
struct _MMBroadbandModemHuaweiPrivate {
|
struct _MMBroadbandModemHuaweiPrivate {
|
||||||
/* Regex for signal quality related notifications */
|
/* Regex for signal quality related notifications */
|
||||||
GRegex *rssi_regex;
|
GRegex *rssi_regex;
|
||||||
@@ -134,6 +145,8 @@ struct _MMBroadbandModemHuaweiPrivate {
|
|||||||
GArray *syscfg_supported_modes;
|
GArray *syscfg_supported_modes;
|
||||||
GArray *syscfgex_supported_modes;
|
GArray *syscfgex_supported_modes;
|
||||||
GArray *prefmode_supported_modes;
|
GArray *prefmode_supported_modes;
|
||||||
|
|
||||||
|
DetailedSignal detailed_signal;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@@ -1739,6 +1752,136 @@ huawei_ndisstat_changed (MMPortSerialAt *port,
|
|||||||
g_object_unref (list);
|
g_object_unref (list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
detailed_signal_clear (DetailedSignal *signal)
|
||||||
|
{
|
||||||
|
g_clear_object (&signal->cdma);
|
||||||
|
g_clear_object (&signal->evdo);
|
||||||
|
g_clear_object (&signal->gsm);
|
||||||
|
g_clear_object (&signal->umts);
|
||||||
|
g_clear_object (&signal->lte);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
get_rssi_dbm (guint rssi, gdouble *out_val)
|
||||||
|
{
|
||||||
|
if (rssi <= 96) {
|
||||||
|
*out_val = (double) (-121.0 + rssi);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
get_ecio_db (guint ecio, gdouble *out_val)
|
||||||
|
{
|
||||||
|
if (ecio <= 65) {
|
||||||
|
*out_val = -32.5 + ((double) ecio / 2.0);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
get_rsrp_dbm (guint rsrp, gdouble *out_val)
|
||||||
|
{
|
||||||
|
if (rsrp <= 97) {
|
||||||
|
*out_val = (double) (-141.0 + rsrp);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
get_sinr_db (guint sinr, gdouble *out_val)
|
||||||
|
{
|
||||||
|
if (sinr <= 251) {
|
||||||
|
*out_val = -20.2 + (double) (sinr / 5.0);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
get_rsrq_db (guint rsrq, gdouble *out_val)
|
||||||
|
{
|
||||||
|
if (rsrq <= 34) {
|
||||||
|
*out_val = -20 + (double) (rsrq / 2.0);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
huawei_hcsq_changed (MMPortSerialAt *port,
|
||||||
|
GMatchInfo *match_info,
|
||||||
|
MMBroadbandModemHuawei *self)
|
||||||
|
{
|
||||||
|
gchar *str;
|
||||||
|
MMModemAccessTechnology act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
|
||||||
|
guint value1 = 0;
|
||||||
|
guint value2 = 0;
|
||||||
|
guint value3 = 0;
|
||||||
|
guint value4 = 0;
|
||||||
|
guint value5 = 0;
|
||||||
|
gdouble v;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
str = g_match_info_fetch (match_info, 1);
|
||||||
|
if (!mm_huawei_parse_hcsq_response (str,
|
||||||
|
&act,
|
||||||
|
&value1,
|
||||||
|
&value2,
|
||||||
|
&value3,
|
||||||
|
&value4,
|
||||||
|
&value5,
|
||||||
|
&error)) {
|
||||||
|
mm_dbg ("Ignored invalid ^HCSQ message: %s (error %s)", str, error->message);
|
||||||
|
g_error_free (error);
|
||||||
|
g_free (str);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
detailed_signal_clear (&self->priv->detailed_signal);
|
||||||
|
|
||||||
|
switch (act) {
|
||||||
|
case MM_MODEM_ACCESS_TECHNOLOGY_GSM:
|
||||||
|
self->priv->detailed_signal.gsm = mm_signal_new ();
|
||||||
|
/* value1: gsm_rssi */
|
||||||
|
if (get_rssi_dbm (value1, &v))
|
||||||
|
mm_signal_set_rssi (self->priv->detailed_signal.gsm, v);
|
||||||
|
break;
|
||||||
|
case MM_MODEM_ACCESS_TECHNOLOGY_UMTS:
|
||||||
|
self->priv->detailed_signal.umts = mm_signal_new ();
|
||||||
|
/* value1: wcdma_rssi */
|
||||||
|
if (get_rssi_dbm (value1, &v))
|
||||||
|
mm_signal_set_rssi (self->priv->detailed_signal.umts, v);
|
||||||
|
/* value2: wcdma_rscp; unused */
|
||||||
|
/* value3: wcdma_ecio */
|
||||||
|
if (get_ecio_db (value3, &v))
|
||||||
|
mm_signal_set_ecio (self->priv->detailed_signal.umts, v);
|
||||||
|
break;
|
||||||
|
case MM_MODEM_ACCESS_TECHNOLOGY_LTE:
|
||||||
|
self->priv->detailed_signal.lte = mm_signal_new ();
|
||||||
|
/* value1: lte_rssi */
|
||||||
|
if (get_rssi_dbm (value1, &v))
|
||||||
|
mm_signal_set_rssi (self->priv->detailed_signal.lte, v);
|
||||||
|
/* value2: lte_rsrp */
|
||||||
|
if (get_rsrp_dbm (value2, &v))
|
||||||
|
mm_signal_set_rsrp (self->priv->detailed_signal.lte, v);
|
||||||
|
/* value3: lte_sinr -> SNR? */
|
||||||
|
if (get_sinr_db (value3, &v))
|
||||||
|
mm_signal_set_snr (self->priv->detailed_signal.lte, v);
|
||||||
|
/* value4: lte_rsrq */
|
||||||
|
if (get_rsrq_db (value4, &v))
|
||||||
|
mm_signal_set_rsrq (self->priv->detailed_signal.lte, v);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* CDMA and EVDO not yet supported */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_3gpp_unsolicited_events_handlers (MMBroadbandModemHuawei *self,
|
set_3gpp_unsolicited_events_handlers (MMBroadbandModemHuawei *self,
|
||||||
gboolean enable)
|
gboolean enable)
|
||||||
@@ -1781,6 +1924,13 @@ set_3gpp_unsolicited_events_handlers (MMBroadbandModemHuawei *self,
|
|||||||
enable ? (MMPortSerialAtUnsolicitedMsgFn)huawei_ndisstat_changed : NULL,
|
enable ? (MMPortSerialAtUnsolicitedMsgFn)huawei_ndisstat_changed : NULL,
|
||||||
enable ? self : NULL,
|
enable ? self : NULL,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
mm_port_serial_at_add_unsolicited_msg_handler (
|
||||||
|
port,
|
||||||
|
self->priv->hcsq_regex,
|
||||||
|
enable ? (MMPortSerialAtUnsolicitedMsgFn)huawei_hcsq_changed : NULL,
|
||||||
|
enable ? self : NULL,
|
||||||
|
NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_list_free_full (ports, (GDestroyNotify)g_object_unref);
|
g_list_free_full (ports, (GDestroyNotify)g_object_unref);
|
||||||
@@ -3966,6 +4116,142 @@ modem_time_check_support (MMIfaceModemTime *self,
|
|||||||
result);
|
result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Check support (Signal interface) */
|
||||||
|
|
||||||
|
static void
|
||||||
|
hcsq_check_ready (MMBaseModem *_self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GTask *task)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
const gchar *response;
|
||||||
|
|
||||||
|
response = mm_base_modem_at_command_finish (_self, res, &error);
|
||||||
|
if (response)
|
||||||
|
g_task_return_boolean (task, TRUE);
|
||||||
|
else
|
||||||
|
g_task_return_error (task, error);
|
||||||
|
|
||||||
|
g_object_unref (task);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
signal_check_support_finish (MMIfaceModemSignal *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
return g_task_propagate_boolean (G_TASK (res), error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
signal_check_support (MMIfaceModemSignal *_self,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
MMBroadbandModemHuawei *self = MM_BROADBAND_MODEM_HUAWEI (_self);
|
||||||
|
GTask *task;
|
||||||
|
|
||||||
|
task = g_task_new (self, NULL, callback, user_data);
|
||||||
|
mm_base_modem_at_command (MM_BASE_MODEM (self),
|
||||||
|
"^HCSQ?",
|
||||||
|
3,
|
||||||
|
FALSE,
|
||||||
|
(GAsyncReadyCallback)hcsq_check_ready,
|
||||||
|
task);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Load extended signal information */
|
||||||
|
|
||||||
|
static void
|
||||||
|
detailed_signal_free (DetailedSignal *signal)
|
||||||
|
{
|
||||||
|
detailed_signal_clear (signal);
|
||||||
|
g_slice_free (DetailedSignal, signal);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
signal_load_values_finish (MMIfaceModemSignal *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
MMSignal **cdma,
|
||||||
|
MMSignal **evdo,
|
||||||
|
MMSignal **gsm,
|
||||||
|
MMSignal **umts,
|
||||||
|
MMSignal **lte,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
DetailedSignal *signals;
|
||||||
|
|
||||||
|
signals = g_task_propagate_pointer (G_TASK (res), error);
|
||||||
|
if (!signals)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
*cdma = signals->cdma ? g_object_ref (signals->cdma) : NULL;
|
||||||
|
*evdo = signals->evdo ? g_object_ref (signals->evdo) : NULL;
|
||||||
|
*gsm = signals->gsm ? g_object_ref (signals->gsm) : NULL;
|
||||||
|
*umts = signals->umts ? g_object_ref (signals->umts) : NULL;
|
||||||
|
*lte = signals->lte ? g_object_ref (signals->lte) : NULL;
|
||||||
|
|
||||||
|
detailed_signal_free (signals);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
hcsq_get_ready (MMBaseModem *_self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GTask *task)
|
||||||
|
{
|
||||||
|
MMBroadbandModemHuawei *self = MM_BROADBAND_MODEM_HUAWEI (_self);
|
||||||
|
DetailedSignal *signals;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
/* Don't care about the response; it will have been parsed by the HCSQ
|
||||||
|
* unsolicited event handler and self->priv->detailed_signal will already
|
||||||
|
* be updated.
|
||||||
|
*/
|
||||||
|
if (!mm_base_modem_at_command_finish (_self, res, &error)) {
|
||||||
|
mm_dbg ("^HCSQ failed: %s", error->message);
|
||||||
|
g_task_return_error (task, error);
|
||||||
|
g_object_unref (task);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
signals = g_slice_new0 (DetailedSignal);
|
||||||
|
signals->cdma = self->priv->detailed_signal.cdma ? g_object_ref (self->priv->detailed_signal.cdma) : NULL;
|
||||||
|
signals->evdo = self->priv->detailed_signal.evdo ? g_object_ref (self->priv->detailed_signal.evdo) : NULL;
|
||||||
|
signals->gsm = self->priv->detailed_signal.gsm ? g_object_ref (self->priv->detailed_signal.gsm) : NULL;
|
||||||
|
signals->umts = self->priv->detailed_signal.umts ? g_object_ref (self->priv->detailed_signal.umts) : NULL;
|
||||||
|
signals->lte = self->priv->detailed_signal.lte ? g_object_ref (self->priv->detailed_signal.lte) : NULL;
|
||||||
|
|
||||||
|
g_task_return_pointer (task, signals, (GDestroyNotify)detailed_signal_free);
|
||||||
|
g_object_unref (task);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
signal_load_values (MMIfaceModemSignal *_self,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
MMBroadbandModemHuawei *self = MM_BROADBAND_MODEM_HUAWEI (_self);
|
||||||
|
GTask *task;
|
||||||
|
|
||||||
|
mm_dbg ("loading extended signal information...");
|
||||||
|
|
||||||
|
task = g_task_new (self, cancellable, callback, user_data);
|
||||||
|
|
||||||
|
/* Clear any previous detailed signal values to get new ones */
|
||||||
|
detailed_signal_clear (&self->priv->detailed_signal);
|
||||||
|
|
||||||
|
mm_base_modem_at_command (MM_BASE_MODEM (self),
|
||||||
|
"^HCSQ?",
|
||||||
|
3,
|
||||||
|
FALSE,
|
||||||
|
(GAsyncReadyCallback)hcsq_get_ready,
|
||||||
|
task);
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Setup ports (Broadband modem class) */
|
/* Setup ports (Broadband modem class) */
|
||||||
|
|
||||||
@@ -4016,10 +4302,6 @@ set_ignored_unsolicited_events_handlers (MMBroadbandModemHuawei *self)
|
|||||||
port,
|
port,
|
||||||
self->priv->stin_regex,
|
self->priv->stin_regex,
|
||||||
NULL, NULL, NULL);
|
NULL, NULL, NULL);
|
||||||
mm_port_serial_at_add_unsolicited_msg_handler (
|
|
||||||
port,
|
|
||||||
self->priv->hcsq_regex,
|
|
||||||
NULL, NULL, NULL);
|
|
||||||
mm_port_serial_at_add_unsolicited_msg_handler (
|
mm_port_serial_at_add_unsolicited_msg_handler (
|
||||||
port,
|
port,
|
||||||
self->priv->pdpdeact_regex,
|
self->priv->pdpdeact_regex,
|
||||||
@@ -4152,7 +4434,7 @@ mm_broadband_modem_huawei_init (MMBroadbandModemHuawei *self)
|
|||||||
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
||||||
self->priv->stin_regex = g_regex_new ("\\r\\n\\^STIN:.+\\r\\n",
|
self->priv->stin_regex = g_regex_new ("\\r\\n\\^STIN:.+\\r\\n",
|
||||||
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
||||||
self->priv->hcsq_regex = g_regex_new ("\\r\\n\\^HCSQ:.+\\r+\\n",
|
self->priv->hcsq_regex = g_regex_new ("\\r\\n(\\^HCSQ:.+)\\r+\\n",
|
||||||
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
||||||
self->priv->pdpdeact_regex = g_regex_new ("\\r\\n\\^PDPDEACT:.+\\r+\\n",
|
self->priv->pdpdeact_regex = g_regex_new ("\\r\\n\\^PDPDEACT:.+\\r+\\n",
|
||||||
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
||||||
@@ -4209,6 +4491,16 @@ mm_broadband_modem_huawei_init (MMBroadbandModemHuawei *self)
|
|||||||
self->priv->time_support = FEATURE_SUPPORT_UNKNOWN;
|
self->priv->time_support = FEATURE_SUPPORT_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dispose (GObject *object)
|
||||||
|
{
|
||||||
|
MMBroadbandModemHuawei *self = MM_BROADBAND_MODEM_HUAWEI (object);
|
||||||
|
|
||||||
|
detailed_signal_clear (&self->priv->detailed_signal);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (mm_broadband_modem_huawei_parent_class)->dispose (object);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
finalize (GObject *object)
|
finalize (GObject *object)
|
||||||
{
|
{
|
||||||
@@ -4371,6 +4663,15 @@ iface_modem_voice_init (MMIfaceModemVoice *iface)
|
|||||||
iface->create_call = create_call;
|
iface->create_call = create_call;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
iface_modem_signal_init (MMIfaceModemSignal *iface)
|
||||||
|
{
|
||||||
|
iface->check_support = signal_check_support;
|
||||||
|
iface->check_support_finish = signal_check_support_finish;
|
||||||
|
iface->load_values = signal_load_values;
|
||||||
|
iface->load_values_finish = signal_load_values_finish;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mm_broadband_modem_huawei_class_init (MMBroadbandModemHuaweiClass *klass)
|
mm_broadband_modem_huawei_class_init (MMBroadbandModemHuaweiClass *klass)
|
||||||
{
|
{
|
||||||
@@ -4379,6 +4680,7 @@ mm_broadband_modem_huawei_class_init (MMBroadbandModemHuaweiClass *klass)
|
|||||||
|
|
||||||
g_type_class_add_private (object_class, sizeof (MMBroadbandModemHuaweiPrivate));
|
g_type_class_add_private (object_class, sizeof (MMBroadbandModemHuaweiPrivate));
|
||||||
|
|
||||||
|
object_class->dispose = dispose;
|
||||||
object_class->finalize = finalize;
|
object_class->finalize = finalize;
|
||||||
|
|
||||||
broadband_modem_class->setup_ports = setup_ports;
|
broadband_modem_class->setup_ports = setup_ports;
|
||||||
|
@@ -1329,3 +1329,74 @@ gboolean mm_huawei_parse_time_response (const gchar *response,
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* ^HCSQ response parser */
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
mm_huawei_parse_hcsq_response (const gchar *response,
|
||||||
|
MMModemAccessTechnology *out_act,
|
||||||
|
guint *out_value1,
|
||||||
|
guint *out_value2,
|
||||||
|
guint *out_value3,
|
||||||
|
guint *out_value4,
|
||||||
|
guint *out_value5,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
GRegex *r;
|
||||||
|
GMatchInfo *match_info = NULL;
|
||||||
|
GError *match_error = NULL;
|
||||||
|
gboolean ret = FALSE;
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
r = g_regex_new ("\\^HCSQ:\\s*\"([a-zA-Z]*)\",(\\d+),?(\\d+)?,?(\\d+)?,?(\\d+)?,?(\\d+)?$", 0, 0, NULL);
|
||||||
|
g_assert (r != NULL);
|
||||||
|
|
||||||
|
if (!g_regex_match_full (r, response, -1, 0, 0, &match_info, &match_error)) {
|
||||||
|
if (match_error) {
|
||||||
|
g_propagate_error (error, match_error);
|
||||||
|
g_prefix_error (error, "Could not parse ^HCSQ results: ");
|
||||||
|
} else {
|
||||||
|
g_set_error_literal (error,
|
||||||
|
MM_CORE_ERROR,
|
||||||
|
MM_CORE_ERROR_FAILED,
|
||||||
|
"Couldn't match ^HCSQ reply");
|
||||||
|
}
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remember that g_match_info_get_match_count() includes match #0 */
|
||||||
|
if (g_match_info_get_match_count (match_info) < 3) {
|
||||||
|
g_set_error_literal (error,
|
||||||
|
MM_CORE_ERROR,
|
||||||
|
MM_CORE_ERROR_FAILED,
|
||||||
|
"Not enough elements in ^HCSQ reply");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_act) {
|
||||||
|
s = g_match_info_fetch (match_info, 1);
|
||||||
|
*out_act = mm_string_to_access_tech (s);
|
||||||
|
g_free (s);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_value1)
|
||||||
|
mm_get_uint_from_match_info (match_info, 2, out_value1);
|
||||||
|
if (out_value2)
|
||||||
|
mm_get_uint_from_match_info (match_info, 3, out_value2);
|
||||||
|
if (out_value3)
|
||||||
|
mm_get_uint_from_match_info (match_info, 4, out_value3);
|
||||||
|
if (out_value4)
|
||||||
|
mm_get_uint_from_match_info (match_info, 5, out_value4);
|
||||||
|
if (out_value5)
|
||||||
|
mm_get_uint_from_match_info (match_info, 6, out_value5);
|
||||||
|
|
||||||
|
ret = TRUE;
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (match_info)
|
||||||
|
g_match_info_free (match_info);
|
||||||
|
g_regex_unref (r);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
@@ -139,4 +139,16 @@ gboolean mm_huawei_parse_time_response (const gchar *response,
|
|||||||
MMNetworkTimezone **tzp,
|
MMNetworkTimezone **tzp,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* ^HCSQ response parser */
|
||||||
|
|
||||||
|
gboolean mm_huawei_parse_hcsq_response (const gchar *response,
|
||||||
|
MMModemAccessTechnology *out_act,
|
||||||
|
guint *out_value1,
|
||||||
|
guint *out_value2,
|
||||||
|
guint *out_value3,
|
||||||
|
guint *out_value4,
|
||||||
|
guint *out_value5,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
#endif /* MM_MODEM_HELPERS_HUAWEI_H */
|
#endif /* MM_MODEM_HELPERS_HUAWEI_H */
|
||||||
|
@@ -1191,6 +1191,66 @@ test_time (void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Test ^HCSQ responses */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const gchar *str;
|
||||||
|
gboolean ret;
|
||||||
|
MMModemAccessTechnology act;
|
||||||
|
guint value1;
|
||||||
|
guint value2;
|
||||||
|
guint value3;
|
||||||
|
guint value4;
|
||||||
|
guint value5;
|
||||||
|
} HcsqTest;
|
||||||
|
|
||||||
|
static const HcsqTest hcsq_tests[] = {
|
||||||
|
{ "^HCSQ:\"LTE\",30,19,66,0\r\n", TRUE, MM_MODEM_ACCESS_TECHNOLOGY_LTE, 30, 19, 66, 0, 0 },
|
||||||
|
{ "^HCSQ: \"WCDMA\",30,30,58\r\n", TRUE, MM_MODEM_ACCESS_TECHNOLOGY_UMTS, 30, 30, 58, 0, 0 },
|
||||||
|
{ "^HCSQ: \"GSM\",36,255\r\n", TRUE, MM_MODEM_ACCESS_TECHNOLOGY_GSM, 36, 255, 0, 0, 0 },
|
||||||
|
{ "^HCSQ: \"NOSERVICE\"\r\n", FALSE, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 0, 0, 0, 0, 0 },
|
||||||
|
{ NULL, FALSE, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN, 0, 0, 0, 0, 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_hcsq (void)
|
||||||
|
{
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
for (i = 0; hcsq_tests[i].str; i++) {
|
||||||
|
GError *error = NULL;
|
||||||
|
MMModemAccessTechnology act;
|
||||||
|
guint value1 = 0;
|
||||||
|
guint value2 = 0;
|
||||||
|
guint value3 = 0;
|
||||||
|
guint value4 = 0;
|
||||||
|
guint value5 = 0;
|
||||||
|
gboolean ret;
|
||||||
|
|
||||||
|
ret = mm_huawei_parse_hcsq_response (hcsq_tests[i].str,
|
||||||
|
&act,
|
||||||
|
&value1,
|
||||||
|
&value2,
|
||||||
|
&value3,
|
||||||
|
&value4,
|
||||||
|
&value5,
|
||||||
|
&error);
|
||||||
|
g_assert (ret == hcsq_tests[i].ret);
|
||||||
|
if (ret) {
|
||||||
|
g_assert_no_error (error);
|
||||||
|
g_assert_cmpint (hcsq_tests[i].act, ==, act);
|
||||||
|
g_assert_cmpint (hcsq_tests[i].value1, ==, value1);
|
||||||
|
g_assert_cmpint (hcsq_tests[i].value2, ==, value2);
|
||||||
|
g_assert_cmpint (hcsq_tests[i].value3, ==, value3);
|
||||||
|
g_assert_cmpint (hcsq_tests[i].value4, ==, value4);
|
||||||
|
g_assert_cmpint (hcsq_tests[i].value5, ==, value5);
|
||||||
|
} else
|
||||||
|
g_assert (error);
|
||||||
|
g_clear_error (&error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -1232,6 +1292,7 @@ int main (int argc, char **argv)
|
|||||||
g_test_add_func ("/MM/huawei/syscfgex/response", test_syscfgex_response);
|
g_test_add_func ("/MM/huawei/syscfgex/response", test_syscfgex_response);
|
||||||
g_test_add_func ("/MM/huawei/nwtime", test_nwtime);
|
g_test_add_func ("/MM/huawei/nwtime", test_nwtime);
|
||||||
g_test_add_func ("/MM/huawei/time", test_time);
|
g_test_add_func ("/MM/huawei/time", test_time);
|
||||||
|
g_test_add_func ("/MM/huawei/hcsq", test_hcsq);
|
||||||
|
|
||||||
return g_test_run ();
|
return g_test_run ();
|
||||||
}
|
}
|
||||||
|
@@ -2089,6 +2089,7 @@ MMModemAccessTechnology
|
|||||||
mm_string_to_access_tech (const gchar *string)
|
mm_string_to_access_tech (const gchar *string)
|
||||||
{
|
{
|
||||||
MMModemAccessTechnology act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
|
MMModemAccessTechnology act = MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN;
|
||||||
|
gsize len;
|
||||||
|
|
||||||
g_return_val_if_fail (string != NULL, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN);
|
g_return_val_if_fail (string != NULL, MM_MODEM_ACCESS_TECHNOLOGY_UNKNOWN);
|
||||||
|
|
||||||
@@ -2102,14 +2103,15 @@ mm_string_to_access_tech (const gchar *string)
|
|||||||
else if (strcasestr (string, "HSPA"))
|
else if (strcasestr (string, "HSPA"))
|
||||||
act |= MM_MODEM_ACCESS_TECHNOLOGY_HSPA;
|
act |= MM_MODEM_ACCESS_TECHNOLOGY_HSPA;
|
||||||
|
|
||||||
|
|
||||||
if (strcasestr (string, "HSUPA"))
|
if (strcasestr (string, "HSUPA"))
|
||||||
act |= MM_MODEM_ACCESS_TECHNOLOGY_HSUPA;
|
act |= MM_MODEM_ACCESS_TECHNOLOGY_HSUPA;
|
||||||
|
|
||||||
if (strcasestr (string, "HSDPA"))
|
if (strcasestr (string, "HSDPA"))
|
||||||
act |= MM_MODEM_ACCESS_TECHNOLOGY_HSDPA;
|
act |= MM_MODEM_ACCESS_TECHNOLOGY_HSDPA;
|
||||||
|
|
||||||
if (strcasestr (string, "UMTS") || strcasestr (string, "3G"))
|
if (strcasestr (string, "UMTS") ||
|
||||||
|
strcasestr (string, "3G") ||
|
||||||
|
strcasestr (string, "WCDMA"))
|
||||||
act |= MM_MODEM_ACCESS_TECHNOLOGY_UMTS;
|
act |= MM_MODEM_ACCESS_TECHNOLOGY_UMTS;
|
||||||
|
|
||||||
if (strcasestr (string, "EDGE"))
|
if (strcasestr (string, "EDGE"))
|
||||||
@@ -2133,6 +2135,17 @@ mm_string_to_access_tech (const gchar *string)
|
|||||||
if (strcasestr (string, "1xRTT") || strcasestr (string, "CDMA2000 1X"))
|
if (strcasestr (string, "1xRTT") || strcasestr (string, "CDMA2000 1X"))
|
||||||
act |= MM_MODEM_ACCESS_TECHNOLOGY_1XRTT;
|
act |= MM_MODEM_ACCESS_TECHNOLOGY_1XRTT;
|
||||||
|
|
||||||
|
/* Check "EVDO" and "CDMA" as standalone strings since their characters
|
||||||
|
* are included in other strings too.
|
||||||
|
*/
|
||||||
|
len = strlen (string);
|
||||||
|
if (strncmp (string, "EVDO", 4) && (len >= 4 && !isalnum (string[4])))
|
||||||
|
act |= MM_MODEM_ACCESS_TECHNOLOGY_EVDO0;
|
||||||
|
if (strncmp (string, "CDMA", 4) && (len >= 4 && !isalnum (string[4])))
|
||||||
|
act |= MM_MODEM_ACCESS_TECHNOLOGY_1XRTT;
|
||||||
|
if (strncmp (string, "CDMA-EVDO", 9) && (len >= 9 && !isalnum (string[9])))
|
||||||
|
act |= MM_MODEM_ACCESS_TECHNOLOGY_1XRTT | MM_MODEM_ACCESS_TECHNOLOGY_EVDO0;
|
||||||
|
|
||||||
return act;
|
return act;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user