diff options
author | Giacinto Cifelli <gciofono@gmail.com> | 2020-05-14 05:38:33 +0200 |
---|---|---|
committer | Aleksander Morgado <aleksander@aleksander.es> | 2020-05-15 13:49:18 +0200 |
commit | f109b528d3edb21fa08be3da6e2ad7280a15707f (patch) | |
tree | 7cfdb150b4fa1e54e751022a5dd51091297059df | |
parent | 8b7bdea7e07ca12f787ede809471f413ba988697 (diff) |
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.
-rw-r--r-- | plugins/cinterion/mm-broadband-modem-cinterion.c | 136 | ||||
-rw-r--r-- | plugins/cinterion/mm-modem-helpers-cinterion.c | 244 | ||||
-rw-r--r-- | plugins/cinterion/mm-modem-helpers-cinterion.h | 25 | ||||
-rw-r--r-- | plugins/cinterion/tests/test-modem-helpers-cinterion.c | 244 |
4 files changed, 649 insertions, 0 deletions
diff --git a/plugins/cinterion/mm-broadband-modem-cinterion.c b/plugins/cinterion/mm-broadband-modem-cinterion.c index 09b4e13c..6e526ad3 100644 --- a/plugins/cinterion/mm-broadband-modem-cinterion.c +++ b/plugins/cinterion/mm-broadband-modem-cinterion.c @@ -40,6 +40,7 @@ #include "mm-modem-helpers-cinterion.h" #include "mm-shared-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_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_voice_init (MMIfaceModemVoice *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 MMIfaceModem *iface_modem_parent; @@ -54,6 +56,7 @@ static MMIfaceModem3gpp *iface_modem_3gpp_parent; static MMIfaceModemLocation *iface_modem_location_parent; static MMIfaceModemVoice *iface_modem_voice_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_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_VOICE, iface_modem_voice_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)) typedef enum { @@ -90,6 +94,7 @@ struct _MMBroadbandModemCinterionPrivate { /* Flags for feature support checks */ FeatureSupport swwan_support; FeatureSupport sind_psinfo_support; + FeatureSupport smoni_support; }; /*****************************************************************************/ @@ -1793,6 +1798,7 @@ mm_broadband_modem_cinterion_init (MMBroadbandModemCinterion *self) /* Initialize private variables */ self->priv->sind_psinfo_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", G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); @@ -1958,3 +1964,133 @@ mm_broadband_modem_cinterion_class_init (MMBroadbandModemCinterionClass *klass) /* Virtual methods */ 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; +} diff --git a/plugins/cinterion/mm-modem-helpers-cinterion.c b/plugins/cinterion/mm-modem-helpers-cinterion.c index da2dd643..5303a609 100644 --- a/plugins/cinterion/mm-modem-helpers-cinterion.c +++ b/plugins/cinterion/mm-modem-helpers-cinterion.c @@ -869,3 +869,247 @@ mm_cinterion_parse_ctzu_urc (GMatchInfo *match_info, 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; +} diff --git a/plugins/cinterion/mm-modem-helpers-cinterion.h b/plugins/cinterion/mm-modem-helpers-cinterion.h index ad6a5fa1..a939e499 100644 --- a/plugins/cinterion/mm-modem-helpers-cinterion.h +++ b/plugins/cinterion/mm-modem-helpers-cinterion.h @@ -113,4 +113,29 @@ gboolean mm_cinterion_parse_ctzu_urc (GMatchInfo *match_info, MMNetworkTimezone **tzp, 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 */ diff --git a/plugins/cinterion/tests/test-modem-helpers-cinterion.c b/plugins/cinterion/tests/test-modem-helpers-cinterion.c index 0baeec30..654368f9 100644 --- a/plugins/cinterion/tests/test-modem-helpers-cinterion.c +++ b/plugins/cinterion/tests/test-modem-helpers-cinterion.c @@ -20,11 +20,15 @@ #include <ModemManager.h> #define _LIBMM_INSIDE_MM #include <libmm-glib.h> +#include <math.h> #include "mm-log-test.h" #include "mm-modem-helpers.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 */ @@ -857,6 +861,244 @@ test_ctzu_urc_full (void) } /*****************************************************************************/ +/* 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) { @@ -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/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/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 (); } |