plugins/cinterion: added Signal interface
Not all Cinterion modems support AT+CESQ. However a much larger group of them support AT^SMONI This commit uses the latter instead of the default former.
This commit is contained in:

committed by
Aleksander Morgado

parent
8b7bdea7e0
commit
f109b528d3
@@ -40,6 +40,7 @@
|
|||||||
#include "mm-modem-helpers-cinterion.h"
|
#include "mm-modem-helpers-cinterion.h"
|
||||||
#include "mm-shared-cinterion.h"
|
#include "mm-shared-cinterion.h"
|
||||||
#include "mm-broadband-bearer-cinterion.h"
|
#include "mm-broadband-bearer-cinterion.h"
|
||||||
|
#include "mm-iface-modem-signal.h"
|
||||||
|
|
||||||
static void iface_modem_init (MMIfaceModem *iface);
|
static void iface_modem_init (MMIfaceModem *iface);
|
||||||
static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface);
|
static void iface_modem_3gpp_init (MMIfaceModem3gpp *iface);
|
||||||
@@ -47,6 +48,7 @@ static void iface_modem_messaging_init (MMIfaceModemMessaging *iface);
|
|||||||
static void iface_modem_location_init (MMIfaceModemLocation *iface);
|
static void iface_modem_location_init (MMIfaceModemLocation *iface);
|
||||||
static void iface_modem_voice_init (MMIfaceModemVoice *iface);
|
static void iface_modem_voice_init (MMIfaceModemVoice *iface);
|
||||||
static void iface_modem_time_init (MMIfaceModemTime *iface);
|
static void iface_modem_time_init (MMIfaceModemTime *iface);
|
||||||
|
static void iface_modem_signal_init (MMIfaceModemSignal *iface);
|
||||||
static void shared_cinterion_init (MMSharedCinterion *iface);
|
static void shared_cinterion_init (MMSharedCinterion *iface);
|
||||||
|
|
||||||
static MMIfaceModem *iface_modem_parent;
|
static MMIfaceModem *iface_modem_parent;
|
||||||
@@ -54,6 +56,7 @@ static MMIfaceModem3gpp *iface_modem_3gpp_parent;
|
|||||||
static MMIfaceModemLocation *iface_modem_location_parent;
|
static MMIfaceModemLocation *iface_modem_location_parent;
|
||||||
static MMIfaceModemVoice *iface_modem_voice_parent;
|
static MMIfaceModemVoice *iface_modem_voice_parent;
|
||||||
static MMIfaceModemTime *iface_modem_time_parent;
|
static MMIfaceModemTime *iface_modem_time_parent;
|
||||||
|
static MMIfaceModemSignal *iface_modem_signal_parent;
|
||||||
|
|
||||||
G_DEFINE_TYPE_EXTENDED (MMBroadbandModemCinterion, mm_broadband_modem_cinterion, MM_TYPE_BROADBAND_MODEM, 0,
|
G_DEFINE_TYPE_EXTENDED (MMBroadbandModemCinterion, mm_broadband_modem_cinterion, MM_TYPE_BROADBAND_MODEM, 0,
|
||||||
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)
|
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM, iface_modem_init)
|
||||||
@@ -62,6 +65,7 @@ G_DEFINE_TYPE_EXTENDED (MMBroadbandModemCinterion, mm_broadband_modem_cinterion,
|
|||||||
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_VOICE, iface_modem_voice_init)
|
G_IMPLEMENT_INTERFACE (MM_TYPE_IFACE_MODEM_VOICE, iface_modem_voice_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_SIGNAL, iface_modem_signal_init)
|
||||||
G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_CINTERION, shared_cinterion_init))
|
G_IMPLEMENT_INTERFACE (MM_TYPE_SHARED_CINTERION, shared_cinterion_init))
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -90,6 +94,7 @@ struct _MMBroadbandModemCinterionPrivate {
|
|||||||
/* Flags for feature support checks */
|
/* Flags for feature support checks */
|
||||||
FeatureSupport swwan_support;
|
FeatureSupport swwan_support;
|
||||||
FeatureSupport sind_psinfo_support;
|
FeatureSupport sind_psinfo_support;
|
||||||
|
FeatureSupport smoni_support;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@@ -1793,6 +1798,7 @@ mm_broadband_modem_cinterion_init (MMBroadbandModemCinterion *self)
|
|||||||
/* Initialize private variables */
|
/* Initialize private variables */
|
||||||
self->priv->sind_psinfo_support = FEATURE_SUPPORT_UNKNOWN;
|
self->priv->sind_psinfo_support = FEATURE_SUPPORT_UNKNOWN;
|
||||||
self->priv->swwan_support = FEATURE_SUPPORT_UNKNOWN;
|
self->priv->swwan_support = FEATURE_SUPPORT_UNKNOWN;
|
||||||
|
self->priv->smoni_support = FEATURE_SUPPORT_UNKNOWN;
|
||||||
|
|
||||||
self->priv->ciev_regex = g_regex_new ("\\r\\n\\+CIEV:\\s*([a-z]+),(\\d+)\\r\\n",
|
self->priv->ciev_regex = g_regex_new ("\\r\\n\\+CIEV:\\s*([a-z]+),(\\d+)\\r\\n",
|
||||||
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
||||||
@@ -1958,3 +1964,133 @@ mm_broadband_modem_cinterion_class_init (MMBroadbandModemCinterionClass *klass)
|
|||||||
/* Virtual methods */
|
/* Virtual methods */
|
||||||
object_class->finalize = finalize;
|
object_class->finalize = finalize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Check support (Signal interface) */
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
signal_check_support_finish (MMIfaceModemSignal *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
return g_task_propagate_boolean (G_TASK (res), error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
parent_signal_check_support_ready (MMIfaceModemSignal *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GTask *task)
|
||||||
|
{
|
||||||
|
gboolean parent_supported;
|
||||||
|
|
||||||
|
parent_supported = iface_modem_signal_parent->check_support_finish (self, res, NULL);
|
||||||
|
g_task_return_boolean (task, parent_supported);
|
||||||
|
g_object_unref (task);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
check_smoni_support (MMBaseModem *_self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GTask *task)
|
||||||
|
{
|
||||||
|
MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self);
|
||||||
|
|
||||||
|
/* Fetch the result to the SMONI test. If no response given (error triggered), assume unsupported */
|
||||||
|
if (mm_base_modem_at_command_finish (_self, res, NULL)) {
|
||||||
|
mm_obj_dbg (self, "SMONI supported");
|
||||||
|
self->priv->smoni_support = FEATURE_SUPPORTED;
|
||||||
|
g_task_return_boolean (task, TRUE); // otherwise the whole interface is not available
|
||||||
|
g_object_unref (task);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mm_obj_dbg (self, "SMONI unsupported");
|
||||||
|
self->priv->smoni_support = FEATURE_NOT_SUPPORTED;
|
||||||
|
|
||||||
|
/* Otherwise, check if the parent CESQ-based implementation works */
|
||||||
|
g_assert (iface_modem_signal_parent->check_support && iface_modem_signal_parent->check_support_finish);
|
||||||
|
iface_modem_signal_parent->check_support (g_task_get_task_data (task),
|
||||||
|
(GAsyncReadyCallback)parent_signal_check_support_ready,
|
||||||
|
task);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
signal_check_support (MMIfaceModemSignal *_self,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self);
|
||||||
|
|
||||||
|
GTask *task = g_task_new (self, NULL, callback, user_data);
|
||||||
|
g_task_set_task_data (task, _self, NULL);
|
||||||
|
|
||||||
|
mm_base_modem_at_command (MM_BASE_MODEM (self),
|
||||||
|
"^SMONI=?",
|
||||||
|
3,
|
||||||
|
FALSE,
|
||||||
|
(GAsyncReadyCallback) check_smoni_support,
|
||||||
|
task);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Load extended signal information (Signal interface) */
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
signal_load_values_finish (MMIfaceModemSignal *_self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
MMSignal **cdma,
|
||||||
|
MMSignal **evdo,
|
||||||
|
MMSignal **gsm,
|
||||||
|
MMSignal **umts,
|
||||||
|
MMSignal **lte,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self);
|
||||||
|
const gchar *response;
|
||||||
|
|
||||||
|
if (self->priv->smoni_support == FEATURE_NOT_SUPPORTED)
|
||||||
|
return iface_modem_signal_parent->load_values_finish (_self, res, cdma, evdo, gsm, umts, lte, error);
|
||||||
|
|
||||||
|
response = mm_base_modem_at_command_finish (MM_BASE_MODEM (_self), res, error);
|
||||||
|
if (!response || !mm_cinterion_smoni_response_to_signal_info (response, gsm, umts, lte, error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (cdma)
|
||||||
|
*cdma = NULL;
|
||||||
|
if (evdo)
|
||||||
|
*evdo = NULL;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
signal_load_values (MMIfaceModemSignal *_self,
|
||||||
|
GCancellable *cancellable,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
MMBroadbandModemCinterion *self = MM_BROADBAND_MODEM_CINTERION (_self);
|
||||||
|
if (self->priv->smoni_support == FEATURE_SUPPORTED) {
|
||||||
|
mm_base_modem_at_command (MM_BASE_MODEM (_self),
|
||||||
|
"^SMONI",
|
||||||
|
3,
|
||||||
|
FALSE,
|
||||||
|
callback,
|
||||||
|
user_data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ^SMONI not supported, fallback to the parent */
|
||||||
|
iface_modem_signal_parent->load_values (_self, cancellable, callback, user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
iface_modem_signal_init (MMIfaceModemSignal *iface)
|
||||||
|
{
|
||||||
|
iface_modem_signal_parent = g_type_interface_peek_parent (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;
|
||||||
|
}
|
||||||
|
@@ -869,3 +869,247 @@ mm_cinterion_parse_ctzu_urc (GMatchInfo *match_info,
|
|||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* ^SMONI response parser */
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
mm_cinterion_parse_smoni_query_response (const gchar *response,
|
||||||
|
MMCinterionSmoniTech *out_tech,
|
||||||
|
gdouble *out_rssi,
|
||||||
|
gdouble *out_ecn0,
|
||||||
|
gdouble *out_rscp,
|
||||||
|
gdouble *out_rsrp,
|
||||||
|
gdouble *out_rsrq,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
g_autoptr(GRegex) r = NULL;
|
||||||
|
g_autoptr(GRegex) pre = NULL;
|
||||||
|
g_autoptr(GMatchInfo) match_info = NULL;
|
||||||
|
g_autoptr(GMatchInfo) match_info_pre = NULL;
|
||||||
|
GError *inner_error = NULL;
|
||||||
|
MMCinterionSmoniTech tech = MM_CINTERION_SMONI_NO_TECH;
|
||||||
|
gdouble rssi = -G_MAXDOUBLE;
|
||||||
|
gdouble ecn0 = -G_MAXDOUBLE;
|
||||||
|
gdouble rscp = -G_MAXDOUBLE;
|
||||||
|
gdouble rsrq = -G_MAXDOUBLE;
|
||||||
|
gdouble rsrp = -G_MAXDOUBLE;
|
||||||
|
gboolean success = FALSE;
|
||||||
|
|
||||||
|
g_assert(out_tech);
|
||||||
|
g_assert(out_rssi);
|
||||||
|
g_assert(out_ecn0);
|
||||||
|
g_assert(out_rscp);
|
||||||
|
g_assert(out_rsrp);
|
||||||
|
g_assert(out_rsrq);
|
||||||
|
g_assert(out_rssi);
|
||||||
|
|
||||||
|
/* Possible Responses:
|
||||||
|
* 2G
|
||||||
|
* ^SMONI: 2G,ARFCN,BCCH,MCC,MNC,LAC,cell,C1,C2,NCC,BCC,GPRS,Conn_state // registered
|
||||||
|
* ^SMONI: 2G,ARFCN,BCCH,MCC,MNC,LAC,cell,C1,C2,NCC,BCC,GPRS,ARFCN,TS,timAdv,dBm,Q,ChMod // searching
|
||||||
|
* ^SMONI: 2G,ARFCN,BCCH,MCC,MNC,LAC,cell,C1,C2,NCC,BCC,GPRS,PWR,RXLev,ARFCN,TS,timAdv,dBm,Q,ChMod // limsrv
|
||||||
|
* ^SMONI: 2G,ARFCN,BCCH,MCC,MNC,LAC,cell,C1,C2,NCC,BCC,GPRS,ARFCN,TS,timAdv,dBm,Q,ChMod // dedicated channel
|
||||||
|
*
|
||||||
|
* ^SMONI: 2G,71,-61,262,02,0143,83BA,33,33,3,6,G,NOCONN
|
||||||
|
* ^^^
|
||||||
|
* ^SMONI: 2G,SEARCH,SEARCH
|
||||||
|
* ^SMONI: 2G,673,-89,262,07,4EED,A500,16,16,7,4,G,5,-107,LIMSRV
|
||||||
|
* ^^^ ^^^^ RXLev dBm
|
||||||
|
* ^SMONI: 2G,673,-80,262,07,4EED,A500,35,35,7,4,G,643,4,0,-80,0,S_FR
|
||||||
|
* ^^^ ^^^ dBm: Receiving level of the traffic channel carrier in dBm
|
||||||
|
* BCCH: Receiving level of the BCCH carrier in dBm (level is limited from -110dBm to -47dBm)
|
||||||
|
* -> rssi for 2G, directly without mm_3gpp_rxlev_to_rssi
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 3G
|
||||||
|
* ^SMONI: 3G,UARFCN,PSC,EC/n0,RSCP,MCC,MNC,LAC,cell,SQual,SRxLev,,Conn_state",
|
||||||
|
* ^SMONI: 3G,UARFCN,PSC,EC/n0,RSCP,MCC,MNC,LAC,cell,SQual,SRxLev,PhysCh, SF,Slot,EC/n0,RSCP,ComMod,HSUPA,HSDPA",
|
||||||
|
* ^SMONI: 3G,UARFCN,PSC,EC/n0,RSCP,MCC,MNC,LAC,cell,SQual,SRxLev,PhysCh, SF,Slot,EC/n0,RSCP,ComMod,HSUPA,HSDPA",
|
||||||
|
* ^SMONI: 3G,UARFCN,PSC,EC/n0,RSCP,MCC,MNC,LAC,cell,SQual,SRxLev,PhysCh, SF,Slot,EC/n0,RSCP,ComMod,HSUPA,HSDPA",
|
||||||
|
*
|
||||||
|
* ^SMONI: 3G,10564,296,-7.5,-79,262,02,0143,00228FF,-92,-78,NOCONN
|
||||||
|
* ^^^^ ^^^
|
||||||
|
* ^SMONI: 3G,SEARCH,SEARCH
|
||||||
|
* ^SMONI: 3G,10564,96,-7.5,-79,262,02,0143,00228FF,-92,-78,LIMSRV
|
||||||
|
* ^^^^ ^^^
|
||||||
|
* ^SMONI: 3G,10737,131,-5,-93,260,01,7D3D,C80BC9A,--,--,----,---,-,-5,-93,0,01,06
|
||||||
|
* ^^ ^^^
|
||||||
|
* RSCP: Received Signal Code Power in dBm -> no need for mm_3gpp_rscp_level_to_rscp
|
||||||
|
* EC/n0: EC/n0 Carrier to noise ratio in dB = measured Ec/Io value in dB. Please refer to 3GPP 25.133, section 9.1.2.3, Table 9.9 for details on the mapping from EC/n0 to EC/Io.
|
||||||
|
* -> direct value, without need for mm_3gpp_ecn0_level_to_ecio
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* 4G
|
||||||
|
* ^SMONI: 4G,EARFCN,Band,DL bandwidth,UL bandwidth,Mode,MCC,MNC,TAC,Global Cell ID,Physical Cell ID,Srxlev,RSRP,RSRQ,Conn_state
|
||||||
|
* ^SMONI: 4G,EARFCN,Band,DL bandwidth,UL bandwidth,Mode,MCC,MNC,TAC,Global Cell ID,Physical Cell ID,Srxlev,RSRP,RSRQ,Conn_state
|
||||||
|
* ^SMONI: 4G,EARFCN,Band,DL bandwidth,UL bandwidth,Mode,MCC,MNC,TAC,Global Cell ID,Physical Cell ID,Srxlev,RSRP,RSRQ,Conn_state
|
||||||
|
* ^SMONI: 4G,EARFCN,Band,DL bandwidth,UL bandwidth,Mode,MCC,MNC,TAC,Global Cell ID,Physical Cell ID,TX_power,RSRP,RSRQ,Conn_state
|
||||||
|
*
|
||||||
|
* ^SMONI: 4G,6300,20,10,10,FDD,262,02,BF75,0345103,350,33,-94,-7,NOCONN
|
||||||
|
* ^^^ ^^
|
||||||
|
* ^SMONI: 4G,SEARCH
|
||||||
|
* ^SMONI: 4G,6300,20,10,10,FDD,262,02,BF75,0345103,350,33,-94,-7,LIMSRV
|
||||||
|
* ^^^ ^^
|
||||||
|
* ^SMONI: 4G,6300,20,10,10,FDD,262,02,BF75,0345103,350,90,-94,-7,CONN
|
||||||
|
* ^^^ ^^
|
||||||
|
* RSRP Reference Signal Received Power (see 3GPP 36.214 Section 5.1.1.) -> directly the value without mm_3gpp_rsrq_level_to_rsrp
|
||||||
|
* RSRQ Reference Signal Received Quality (see 3GPP 36.214 Section 5.1.2.) -> directly the value without mm_3gpp_rsrq_level_to_rsrq
|
||||||
|
*/
|
||||||
|
if (g_regex_match_simple ("\\^SMONI:\\s*[234]G,SEARCH", response, 0, 0)) {
|
||||||
|
success = TRUE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
pre = g_regex_new ("\\^SMONI:\\s*([234])", 0, 0, NULL);
|
||||||
|
g_assert (pre != NULL);
|
||||||
|
g_regex_match_full (pre, response, strlen (response), 0, 0, &match_info_pre, &inner_error);
|
||||||
|
if (!inner_error && g_match_info_matches (match_info_pre)) {
|
||||||
|
if (!mm_get_uint_from_match_info (match_info_pre, 1, &tech)) {
|
||||||
|
inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't read tech");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
#define FLOAT "([-+]?[0-9]+\\.?[0-9]*)"
|
||||||
|
switch (tech) {
|
||||||
|
case MM_CINTERION_SMONI_2G:
|
||||||
|
r = g_regex_new ("\\^SMONI:\\s*2G,(\\d+),"FLOAT, 0, 0, NULL);
|
||||||
|
g_assert (r != NULL);
|
||||||
|
g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error);
|
||||||
|
if (!inner_error && g_match_info_matches (match_info)) {
|
||||||
|
/* skip ARFCN */
|
||||||
|
if (!mm_get_double_from_match_info (match_info, 2, &rssi)) {
|
||||||
|
inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't read BCCH=rssi");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MM_CINTERION_SMONI_3G:
|
||||||
|
r = g_regex_new ("\\^SMONI:\\s*3G,(\\d+),(\\d+),"FLOAT","FLOAT, 0, 0, NULL);
|
||||||
|
g_assert (r != NULL);
|
||||||
|
g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error);
|
||||||
|
if (!inner_error && g_match_info_matches (match_info)) {
|
||||||
|
/* skip UARFCN */
|
||||||
|
/* skip PSC (Primary scrambling code) */
|
||||||
|
if (!mm_get_double_from_match_info (match_info, 3, &ecn0)) {
|
||||||
|
inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't read EcN0");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (!mm_get_double_from_match_info (match_info, 4, &rscp)) {
|
||||||
|
inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't read RSCP");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MM_CINTERION_SMONI_4G:
|
||||||
|
r = g_regex_new ("\\^SMONI:\\s*4G,(\\d+),(\\d+),(\\d+),(\\d+),(\\w+),(\\d+),(\\d+),(\\w+),(\\w+),(\\d+),([^,]*),"FLOAT","FLOAT, 0, 0, NULL);
|
||||||
|
g_assert (r != NULL);
|
||||||
|
g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error);
|
||||||
|
if (!inner_error && g_match_info_matches (match_info)) {
|
||||||
|
/* skip EARFCN */
|
||||||
|
/* skip Band */
|
||||||
|
/* skip DL bandwidth */
|
||||||
|
/* skip UL bandwidth */
|
||||||
|
/* skip Mode */
|
||||||
|
/* skip MCC */
|
||||||
|
/* skip MNC */
|
||||||
|
/* skip TAC */
|
||||||
|
/* skip Global Cell ID */
|
||||||
|
/* skip Physical Cell ID */
|
||||||
|
/* skip Srxlev/TX_power */
|
||||||
|
if (!mm_get_double_from_match_info (match_info, 12, &rsrp)) {
|
||||||
|
inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't read RSRQ");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
if (!mm_get_double_from_match_info (match_info, 13, &rsrq)) {
|
||||||
|
inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED, "Couldn't read RSRP");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MM_CINTERION_SMONI_NO_TECH:
|
||||||
|
default:
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
#undef FLOAT
|
||||||
|
success = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (inner_error) {
|
||||||
|
g_propagate_error (error, inner_error);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||||
|
"Couldn't parse ^SMONI response: %s", response);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_tech = tech;
|
||||||
|
*out_rssi = rssi;
|
||||||
|
*out_rscp = rscp;
|
||||||
|
*out_ecn0 = ecn0;
|
||||||
|
*out_rsrq = rsrq;
|
||||||
|
*out_rsrp = rsrp;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Get extended signal information */
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
mm_cinterion_smoni_response_to_signal_info (const gchar *response,
|
||||||
|
MMSignal **out_gsm,
|
||||||
|
MMSignal **out_umts,
|
||||||
|
MMSignal **out_lte,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
MMCinterionSmoniTech tech = MM_CINTERION_SMONI_NO_TECH;
|
||||||
|
gdouble rssi = MM_SIGNAL_UNKNOWN;
|
||||||
|
gdouble ecn0 = MM_SIGNAL_UNKNOWN;
|
||||||
|
gdouble rscp = MM_SIGNAL_UNKNOWN;
|
||||||
|
gdouble rsrq = MM_SIGNAL_UNKNOWN;
|
||||||
|
gdouble rsrp = MM_SIGNAL_UNKNOWN;
|
||||||
|
MMSignal *gsm = NULL;
|
||||||
|
MMSignal *umts = NULL;
|
||||||
|
MMSignal *lte = NULL;
|
||||||
|
|
||||||
|
if (!mm_cinterion_parse_smoni_query_response (response,
|
||||||
|
&tech, &rssi,
|
||||||
|
&ecn0, &rscp,
|
||||||
|
&rsrp, &rsrq,
|
||||||
|
error))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
switch (tech) {
|
||||||
|
case MM_CINTERION_SMONI_2G:
|
||||||
|
gsm = mm_signal_new ();
|
||||||
|
mm_signal_set_rssi (gsm, rssi);
|
||||||
|
break;
|
||||||
|
case MM_CINTERION_SMONI_3G:
|
||||||
|
umts = mm_signal_new ();
|
||||||
|
mm_signal_set_rscp (umts, rscp);
|
||||||
|
mm_signal_set_ecio (umts, ecn0); /* UMTS EcIo (assumed EcN0) */
|
||||||
|
break;
|
||||||
|
case MM_CINTERION_SMONI_4G:
|
||||||
|
lte = mm_signal_new ();
|
||||||
|
mm_signal_set_rsrp (lte, rsrp);
|
||||||
|
mm_signal_set_rsrq (lte, rsrq);
|
||||||
|
break;
|
||||||
|
case MM_CINTERION_SMONI_NO_TECH: /* not registered, searching */
|
||||||
|
break; /* no error case */
|
||||||
|
default: /* should not happen, so if it does, error */
|
||||||
|
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||||
|
"Couldn't build detailed signal info");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_gsm)
|
||||||
|
*out_gsm = gsm;
|
||||||
|
if (out_umts)
|
||||||
|
*out_umts = umts;
|
||||||
|
if (out_lte)
|
||||||
|
*out_lte = lte;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
@@ -113,4 +113,29 @@ gboolean mm_cinterion_parse_ctzu_urc (GMatchInfo *match_info,
|
|||||||
MMNetworkTimezone **tzp,
|
MMNetworkTimezone **tzp,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* ^SMONI helper */
|
||||||
|
|
||||||
|
typedef enum { /*< underscore_name=mm_modem_port_type >*/
|
||||||
|
MM_CINTERION_SMONI_NO_TECH = 0,
|
||||||
|
MM_CINTERION_SMONI_2G = 2,
|
||||||
|
MM_CINTERION_SMONI_3G = 3,
|
||||||
|
MM_CINTERION_SMONI_4G = 4,
|
||||||
|
} MMCinterionSmoniTech;
|
||||||
|
|
||||||
|
gboolean mm_cinterion_parse_smoni_query_response (const gchar *response,
|
||||||
|
MMCinterionSmoniTech *out_tech,
|
||||||
|
gdouble *out_rssi,
|
||||||
|
gdouble *out_ecn0,
|
||||||
|
gdouble *out_rscp,
|
||||||
|
gdouble *out_rsrp,
|
||||||
|
gdouble *out_rsrq,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
gboolean mm_cinterion_smoni_response_to_signal_info (const gchar *response,
|
||||||
|
MMSignal **out_gsm,
|
||||||
|
MMSignal **out_umts,
|
||||||
|
MMSignal **out_lte,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
#endif /* MM_MODEM_HELPERS_CINTERION_H */
|
#endif /* MM_MODEM_HELPERS_CINTERION_H */
|
||||||
|
@@ -20,11 +20,15 @@
|
|||||||
#include <ModemManager.h>
|
#include <ModemManager.h>
|
||||||
#define _LIBMM_INSIDE_MM
|
#define _LIBMM_INSIDE_MM
|
||||||
#include <libmm-glib.h>
|
#include <libmm-glib.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#include "mm-log-test.h"
|
#include "mm-log-test.h"
|
||||||
#include "mm-modem-helpers.h"
|
#include "mm-modem-helpers.h"
|
||||||
#include "mm-modem-helpers-cinterion.h"
|
#include "mm-modem-helpers-cinterion.h"
|
||||||
|
|
||||||
|
#define g_assert_cmpfloat_tolerance(val1, val2, tolerance) \
|
||||||
|
g_assert_cmpfloat (fabs (val1 - val2), <, tolerance)
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Test ^SCFG test responses */
|
/* Test ^SCFG test responses */
|
||||||
|
|
||||||
@@ -856,6 +860,244 @@ test_ctzu_urc_full (void)
|
|||||||
common_test_ctzu_urc (urc, expected_iso8601, expected_offset, expected_dst_offset);
|
common_test_ctzu_urc (urc, expected_iso8601, expected_offset, expected_dst_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Test ^SMONI responses */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const gchar *str;
|
||||||
|
MMCinterionSmoniTech tech;
|
||||||
|
gdouble rssi;
|
||||||
|
gdouble ecn0;
|
||||||
|
gdouble rscp;
|
||||||
|
gdouble rsrp;
|
||||||
|
gdouble rsrq;
|
||||||
|
} SMoniResponseTest;
|
||||||
|
|
||||||
|
static const SMoniResponseTest smoni_response_tests[] = {
|
||||||
|
{
|
||||||
|
.str = "^SMONI: 2G,71,-61,262,02,0143,83BA,33,33,3,6,G,NOCONN",
|
||||||
|
.tech = MM_CINTERION_SMONI_2G,
|
||||||
|
.rssi = -61.0,
|
||||||
|
.ecn0 = 0.0,
|
||||||
|
.rscp = 0.0,
|
||||||
|
.rsrp = 0.0,
|
||||||
|
.rsrq = 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.str = "^SMONI: 2G,SEARCH,SEARCH",
|
||||||
|
.tech = MM_CINTERION_SMONI_NO_TECH,
|
||||||
|
.rssi = 0.0,
|
||||||
|
.ecn0 = 0.0,
|
||||||
|
.rscp = 0.0,
|
||||||
|
.rsrp = 0.0,
|
||||||
|
.rsrq = 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.str = "^SMONI: 2G,673,-89,262,07,4EED,A500,16,16,7,4,G,5,-107,LIMSRV",
|
||||||
|
.tech = MM_CINTERION_SMONI_2G,
|
||||||
|
.rssi = -89.0,
|
||||||
|
.ecn0 = 0.0,
|
||||||
|
.rscp = 0.0,
|
||||||
|
.rsrp = 0.0,
|
||||||
|
.rsrq = 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.str = "^SMONI: 2G,673,-80,262,07,4EED,A500,35,35,7,4,G,643,4,0,-80,0,S_FR",
|
||||||
|
.tech = MM_CINTERION_SMONI_2G,
|
||||||
|
.rssi = -80.0,
|
||||||
|
.ecn0 = 0.0,
|
||||||
|
.rscp = 0.0,
|
||||||
|
.rsrp = 0.0,
|
||||||
|
.rsrq = 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.str = "^SMONI: 3G,10564,296,-7.5,-79,262,02,0143,00228FF,-92,-78,NOCONN",
|
||||||
|
.tech = MM_CINTERION_SMONI_3G,
|
||||||
|
.rssi = 0.0,
|
||||||
|
.ecn0 = -7.5,
|
||||||
|
.rscp = -79.0,
|
||||||
|
.rsrp = 0.0,
|
||||||
|
.rsrq = 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.str = "^SMONI: 3G,SEARCH,SEARCH",
|
||||||
|
.tech = MM_CINTERION_SMONI_NO_TECH,
|
||||||
|
.rssi = 0.0,
|
||||||
|
.ecn0 = 0,
|
||||||
|
.rscp = 0,
|
||||||
|
.rsrp = 0.0,
|
||||||
|
.rsrq = 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.str = "^SMONI: 3G,10564,96,-6.5,-77,262,02,0143,00228FF,-92,-78,LIMSRV",
|
||||||
|
.tech = MM_CINTERION_SMONI_3G,
|
||||||
|
.rssi = 0.0,
|
||||||
|
.ecn0 = -6.5,
|
||||||
|
.rscp = -77.0,
|
||||||
|
.rsrp = 0.0,
|
||||||
|
.rsrq = 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.str = "^SMONI: 3G,10737,131,-5,-93,260,01,7D3D,C80BC9A,--,--,----,---,-,-5,-93,0,01,06",
|
||||||
|
.tech = MM_CINTERION_SMONI_3G,
|
||||||
|
.rssi = 0.0,
|
||||||
|
.ecn0 = -5.0,
|
||||||
|
.rscp = -93.0,
|
||||||
|
.rsrp = 0.0,
|
||||||
|
.rsrq = 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.str = "^SMONI: 4G,6300,20,10,10,FDD,262,02,BF75,0345103,350,33,-94,-7,NOCONN",
|
||||||
|
.tech = MM_CINTERION_SMONI_4G,
|
||||||
|
.rssi = 0.0,
|
||||||
|
.ecn0 = 0.0,
|
||||||
|
.rscp = 0.0,
|
||||||
|
.rsrp = -94.0,
|
||||||
|
.rsrq = -7.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.str = "^SMONI: 4G,SEARCH",
|
||||||
|
.tech = MM_CINTERION_SMONI_NO_TECH,
|
||||||
|
.rssi = 0.0,
|
||||||
|
.ecn0 = 0.0,
|
||||||
|
.rscp = 0.0,
|
||||||
|
.rsrp = 0.0,
|
||||||
|
.rsrq = 0.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.str = "^SMONI: 4G,6300,20,10,10,FDD,262,02,BF75,0345103,350,33,-90,-6,LIMSRV",
|
||||||
|
.tech = MM_CINTERION_SMONI_4G,
|
||||||
|
.rssi = 0.0,
|
||||||
|
.ecn0 = 0.0,
|
||||||
|
.rscp = 0.0,
|
||||||
|
.rsrp = -90.0,
|
||||||
|
.rsrq = -6.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.str = "^SMONI: 4G,6300,20,10,10,FDD,262,02,BF75,0345103,350,90,-101,-7,CONN",
|
||||||
|
.tech = MM_CINTERION_SMONI_4G,
|
||||||
|
.rssi = 0.0,
|
||||||
|
.ecn0 = 0.0,
|
||||||
|
.rscp = 0.0,
|
||||||
|
.rsrp = -101.0,
|
||||||
|
.rsrq = -7.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.str = "^SMONI: 4G,2850,7,20,20,FDD,262,02,C096,027430F,275,11,-114,-9,NOCONN",
|
||||||
|
.tech = MM_CINTERION_SMONI_4G,
|
||||||
|
.rssi = 0.0,
|
||||||
|
.ecn0 = 0.0,
|
||||||
|
.rscp = 0.0,
|
||||||
|
.rsrp = -114.0,
|
||||||
|
.rsrq = -9.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.str = "^SMONI: 4G,2850,7,20,20,FDD,262,02,C096,027430F,275,-,-113,-8,CONN",
|
||||||
|
.tech = MM_CINTERION_SMONI_4G,
|
||||||
|
.rssi = 0.0,
|
||||||
|
.ecn0 = 0.0,
|
||||||
|
.rscp = 0.0,
|
||||||
|
.rsrp = -113.0,
|
||||||
|
.rsrq = -8.0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_smoni_response (void)
|
||||||
|
{
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS (smoni_response_tests); i++) {
|
||||||
|
GError *error = NULL;
|
||||||
|
gboolean success;
|
||||||
|
MMCinterionSmoniTech tech = MM_CINTERION_SMONI_NO_TECH;
|
||||||
|
gdouble rssi = MM_SIGNAL_UNKNOWN;
|
||||||
|
gdouble ecn0 = MM_SIGNAL_UNKNOWN;
|
||||||
|
gdouble rscp = MM_SIGNAL_UNKNOWN;
|
||||||
|
gdouble rsrp = MM_SIGNAL_UNKNOWN;
|
||||||
|
gdouble rsrq = MM_SIGNAL_UNKNOWN;
|
||||||
|
|
||||||
|
success = mm_cinterion_parse_smoni_query_response (smoni_response_tests[i].str,
|
||||||
|
&tech, &rssi,
|
||||||
|
&ecn0, &rscp,
|
||||||
|
&rsrp, &rsrq,
|
||||||
|
&error);
|
||||||
|
g_assert_no_error (error);
|
||||||
|
g_assert (success);
|
||||||
|
|
||||||
|
g_assert_cmpuint (smoni_response_tests[i].tech, ==, tech);
|
||||||
|
switch (smoni_response_tests[i].tech) {
|
||||||
|
case MM_CINTERION_SMONI_2G:
|
||||||
|
g_assert_cmpfloat_tolerance (rssi, smoni_response_tests[i].rssi, 0.1);
|
||||||
|
break;
|
||||||
|
case MM_CINTERION_SMONI_3G:
|
||||||
|
g_assert_cmpfloat_tolerance (ecn0, smoni_response_tests[i].ecn0, 0.1);
|
||||||
|
g_assert_cmpfloat_tolerance (rscp, smoni_response_tests[i].rscp, 0.1);
|
||||||
|
break;
|
||||||
|
case MM_CINTERION_SMONI_4G:
|
||||||
|
g_assert_cmpfloat_tolerance (rsrp, smoni_response_tests[i].rsrp, 0.1);
|
||||||
|
g_assert_cmpfloat_tolerance (rsrq, smoni_response_tests[i].rsrq, 0.1);
|
||||||
|
break;
|
||||||
|
case MM_CINTERION_SMONI_NO_TECH:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_smoni_response_to_signal (void)
|
||||||
|
{
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
for (i = 0; i < G_N_ELEMENTS (smoni_response_tests); i++) {
|
||||||
|
GError *error = NULL;
|
||||||
|
gboolean success;
|
||||||
|
MMSignal *gsm = NULL;
|
||||||
|
MMSignal *umts = NULL;
|
||||||
|
MMSignal *lte = NULL;
|
||||||
|
|
||||||
|
success = mm_cinterion_smoni_response_to_signal_info (smoni_response_tests[i].str,
|
||||||
|
&gsm, &umts, <e,
|
||||||
|
&error);
|
||||||
|
g_assert_no_error (error);
|
||||||
|
g_assert (success);
|
||||||
|
|
||||||
|
switch (smoni_response_tests[i].tech) {
|
||||||
|
case MM_CINTERION_SMONI_2G:
|
||||||
|
g_assert (gsm);
|
||||||
|
g_assert_cmpfloat_tolerance (mm_signal_get_rssi (gsm), smoni_response_tests[i].rssi, 0.1);
|
||||||
|
g_object_unref (gsm);
|
||||||
|
g_assert (!umts);
|
||||||
|
g_assert (!lte);
|
||||||
|
break;
|
||||||
|
case MM_CINTERION_SMONI_3G:
|
||||||
|
g_assert (umts);
|
||||||
|
g_assert_cmpfloat_tolerance (mm_signal_get_rscp (umts), smoni_response_tests[i].rscp, 0.1);
|
||||||
|
g_assert_cmpfloat_tolerance (mm_signal_get_ecio (umts), smoni_response_tests[i].ecn0, 0.1);
|
||||||
|
g_object_unref (umts);
|
||||||
|
g_assert (!gsm);
|
||||||
|
g_assert (!lte);
|
||||||
|
break;
|
||||||
|
case MM_CINTERION_SMONI_4G:
|
||||||
|
g_assert (lte);
|
||||||
|
g_assert_cmpfloat_tolerance (mm_signal_get_rsrp (lte), smoni_response_tests[i].rsrp, 0.1);
|
||||||
|
g_assert_cmpfloat_tolerance (mm_signal_get_rsrq (lte), smoni_response_tests[i].rsrq, 0.1);
|
||||||
|
g_object_unref (lte);
|
||||||
|
g_assert (!gsm);
|
||||||
|
g_assert (!umts);
|
||||||
|
break;
|
||||||
|
case MM_CINTERION_SMONI_NO_TECH:
|
||||||
|
default:
|
||||||
|
g_assert (!gsm);
|
||||||
|
g_assert (!umts);
|
||||||
|
g_assert (!lte);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
int main (int argc, char **argv)
|
int main (int argc, char **argv)
|
||||||
@@ -881,6 +1123,8 @@ int main (int argc, char **argv)
|
|||||||
g_test_add_func ("/MM/cinterion/slcc/urc/complex", test_slcc_urc_complex);
|
g_test_add_func ("/MM/cinterion/slcc/urc/complex", test_slcc_urc_complex);
|
||||||
g_test_add_func ("/MM/cinterion/ctzu/urc/simple", test_ctzu_urc_simple);
|
g_test_add_func ("/MM/cinterion/ctzu/urc/simple", test_ctzu_urc_simple);
|
||||||
g_test_add_func ("/MM/cinterion/ctzu/urc/full", test_ctzu_urc_full);
|
g_test_add_func ("/MM/cinterion/ctzu/urc/full", test_ctzu_urc_full);
|
||||||
|
g_test_add_func ("/MM/cinterion/smoni/query_response", test_smoni_response);
|
||||||
|
g_test_add_func ("/MM/cinterion/smoni/query_response_to_signal", test_smoni_response_to_signal);
|
||||||
|
|
||||||
return g_test_run ();
|
return g_test_run ();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user