aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@aleksander.es>2016-10-05 13:51:35 +0200
committerAleksander Morgado <aleksander@aleksander.es>2016-10-12 13:24:08 +0200
commit7ab3d3e727cdc03fa7e058416e57c7d6c83aeab7 (patch)
tree4e42c79577bb1419eb1e2030d5bce295fe50993a
parentdf6f6d1f37dfeb27c27cf54e6181df9eaf162322 (diff)
modem-helpers: new helper to parse +CESQ response into MMSignal objects
-rw-r--r--src/mm-modem-helpers.c217
-rw-r--r--src/mm-modem-helpers.h6
-rw-r--r--src/tests/test-modem-helpers.c123
3 files changed, 276 insertions, 70 deletions
diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c
index c34f6878..eecdc5e5 100644
--- a/src/mm-modem-helpers.c
+++ b/src/mm-modem-helpers.c
@@ -1856,6 +1856,58 @@ out:
return TRUE;
}
+/*************************************************************************/
+
+gboolean
+mm_3gpp_parse_cfun_query_response (const gchar *response,
+ guint *out_state,
+ GError **error)
+{
+ GRegex *r;
+ GMatchInfo *match_info;
+ GError *inner_error = NULL;
+ guint state = G_MAXUINT;
+
+ g_assert (out_state != NULL);
+
+ /* Response may be e.g.:
+ * +CFUN: 1,0
+ * ..but we don't care about the second number
+ */
+ r = g_regex_new ("\\+CFUN: (\\d+)(?:,(?:\\d+))?(?:\\r\\n)?", 0, 0, NULL);
+ g_assert (r != NULL);
+
+ g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error);
+ if (inner_error)
+ goto out;
+
+ if (!g_match_info_matches (match_info)) {
+ inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Couldn't parse +CFUN response: %s", response);
+ goto out;
+ }
+
+ if (!mm_get_uint_from_match_info (match_info, 1, &state)) {
+ inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Couldn't read power state value");
+ goto out;
+ }
+
+ *out_state = state;
+
+out:
+ if (match_info)
+ g_match_info_free (match_info);
+ g_regex_unref (r);
+
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
/*****************************************************************************/
/* +CESQ response parser */
@@ -1948,55 +2000,152 @@ out:
return TRUE;
}
-/*************************************************************************/
+static gboolean
+rxlev_to_rssi (guint rxlev,
+ gdouble *out_rssi)
+{
+ if (rxlev <= 63) {
+ *out_rssi = -111.0 + rxlev;
+ return TRUE;
+ }
-gboolean
-mm_3gpp_parse_cfun_query_response (const gchar *response,
- guint *out_state,
- GError **error)
+ if (rxlev != 99)
+ mm_warn ("unexpected rxlev: %u", rxlev);
+ return FALSE;
+}
+
+static gboolean
+rscp_level_to_rscp (guint rscp_level,
+ gdouble *out_rscp)
{
- GRegex *r;
- GMatchInfo *match_info;
- GError *inner_error = NULL;
- guint state = G_MAXUINT;
+ if (rscp_level <= 96) {
+ *out_rscp = -121.0 + rscp_level;
+ return TRUE;
+ }
- g_assert (out_state != NULL);
+ if (rscp_level != 255)
+ mm_warn ("unexpected rscp level: %u", rscp_level);
+ return FALSE;
+}
- /* Response may be e.g.:
- * +CFUN: 1,0
- * ..but we don't care about the second number
- */
- r = g_regex_new ("\\+CFUN: (\\d+)(?:,(?:\\d+))?(?:\\r\\n)?", 0, 0, NULL);
- g_assert (r != NULL);
+static gboolean
+ecn0_level_to_ecio (guint ecn0_level,
+ gdouble *out_ecio)
+{
+ if (ecn0_level <= 49) {
+ *out_ecio = -24.5 + (((gdouble) ecn0_level) * 0.5);
+ return TRUE;
+ }
- g_regex_match_full (r, response, strlen (response), 0, 0, &match_info, &inner_error);
- if (inner_error)
- goto out;
+ if (ecn0_level != 255)
+ mm_warn ("unexpected Ec/N0 level: %u", ecn0_level);
+ return FALSE;
+}
- if (!g_match_info_matches (match_info)) {
- inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
- "Couldn't parse +CFUN response: %s", response);
- goto out;
+static gboolean
+rsrq_level_to_rsrq (guint rsrq_level,
+ gdouble *out_rsrq)
+{
+ if (rsrq_level <= 34) {
+ *out_rsrq = -20.0 + (((gdouble) rsrq_level) * 0.5);
+ return TRUE;
}
- if (!mm_get_uint_from_match_info (match_info, 1, &state)) {
- inner_error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
- "Couldn't read power state value");
- goto out;
+ if (rsrq_level != 255)
+ mm_warn ("unexpected RSRQ level: %u", rsrq_level);
+ return FALSE;
+}
+
+static gboolean
+rsrp_level_to_rsrp (guint rsrp_level,
+ gdouble *out_rsrp)
+{
+ if (rsrp_level <= 97) {
+ *out_rsrp = -141.0 + rsrp_level;
+ return TRUE;
}
- *out_state = state;
+ if (rsrp_level != 255)
+ mm_warn ("unexpected RSRP level: %u", rsrp_level);
+ return FALSE;
+}
-out:
- if (match_info)
- g_match_info_free (match_info);
- g_regex_unref (r);
+gboolean
+mm_3gpp_cesq_response_to_signal_info (const gchar *response,
+ MMSignal **out_gsm,
+ MMSignal **out_umts,
+ MMSignal **out_lte,
+ GError **error)
+{
+ guint rxlev = 0;
+ guint ber = 0;
+ guint rscp_level = 0;
+ guint ecn0_level = 0;
+ guint rsrq_level = 0;
+ guint rsrp_level = 0;
+ gdouble rssi = -G_MAXDOUBLE;
+ gdouble rscp = -G_MAXDOUBLE;
+ gdouble ecio = -G_MAXDOUBLE;
+ gdouble rsrq = -G_MAXDOUBLE;
+ gdouble rsrp = -G_MAXDOUBLE;
+ MMSignal *gsm = NULL;
+ MMSignal *umts = NULL;
+ MMSignal *lte = NULL;
+
+ if (!mm_3gpp_parse_cesq_response (response,
+ &rxlev, &ber,
+ &rscp_level, &ecn0_level,
+ &rsrq_level, &rsrp_level,
+ error))
+ return FALSE;
- if (inner_error) {
- g_propagate_error (error, inner_error);
+ /* GERAN RSSI */
+ if (rxlev_to_rssi (rxlev, &rssi)) {
+ gsm = mm_signal_new ();
+ mm_signal_set_rssi (gsm, rssi);
+ }
+
+ /* ignore BER */
+
+ /* UMTS RSCP */
+ if (rscp_level_to_rscp (rscp_level, &rscp)) {
+ umts = mm_signal_new ();
+ mm_signal_set_rscp (umts, rscp);
+ }
+
+ /* UMTS EcIo (assumed EcN0) */
+ if (ecn0_level_to_ecio (ecn0_level, &ecio)) {
+ if (!umts)
+ umts = mm_signal_new ();
+ mm_signal_set_ecio (umts, ecio);
+ }
+
+ /* LTE RSRQ */
+ if (rsrq_level_to_rsrq (rsrq_level, &rsrq)) {
+ lte = mm_signal_new ();
+ mm_signal_set_rsrq (lte, rsrq);
+ }
+
+ /* LTE RSRP */
+ if (rsrp_level_to_rsrp (rsrp_level, &rsrp)) {
+ if (!lte)
+ lte = mm_signal_new ();
+ mm_signal_set_rsrp (lte, rsrp);
+ }
+
+ if (!gsm && !umts && !lte) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
+ "Couldn't build detailed signal info");
return FALSE;
}
+ if (gsm)
+ *out_gsm = gsm;
+ if (umts)
+ *out_umts = umts;
+ if (lte)
+ *out_lte = lte;
+
return TRUE;
}
diff --git a/src/mm-modem-helpers.h b/src/mm-modem-helpers.h
index 1145320d..6565c583 100644
--- a/src/mm-modem-helpers.h
+++ b/src/mm-modem-helpers.h
@@ -274,6 +274,12 @@ gboolean mm_3gpp_parse_cesq_response (const gchar *response,
guint *out_rsrp,
GError **error);
+gboolean mm_3gpp_cesq_response_to_signal_info (const gchar *response,
+ MMSignal **out_gsm,
+ MMSignal **out_umts,
+ MMSignal **out_lte,
+ GError **error);
+
/* Additional 3GPP-specific helpers */
MMModem3gppFacility mm_3gpp_acronym_to_facility (const gchar *str);
diff --git a/src/tests/test-modem-helpers.c b/src/tests/test-modem-helpers.c
index da5416d1..f02a0862 100644
--- a/src/tests/test-modem-helpers.c
+++ b/src/tests/test-modem-helpers.c
@@ -17,6 +17,7 @@
#include <glib-object.h>
#include <string.h>
#include <stdlib.h>
+#include <math.h>
#include <libmm-glib.h>
#include "mm-modem-helpers.h"
@@ -28,6 +29,9 @@
#define trace(...)
#endif
+#define g_assert_cmpfloat_tolerance(val1, val2, tolerance) \
+ g_assert_cmpfloat (fabs (val1 - val2), <, tolerance)
+
/*****************************************************************************/
/* Test CMGL responses */
@@ -3081,7 +3085,6 @@ test_cgcontrdp_response (void)
}
/*****************************************************************************/
-<<<<<<< HEAD
/* Test CFUN? response */
typedef struct {
@@ -3112,46 +3115,51 @@ test_cfun_response (void)
g_assert_no_error (error);
g_assert (success);
g_assert_cmpuint (cfun_query_tests[i].state, ==, state);
-=======
+ }
+}
+
+/*****************************************************************************/
/* Test +CESQ responses */
typedef struct {
const gchar *str;
- guint rxlev;
- guint ber;
- guint rscp;
- guint ecn0;
- guint rsrq;
- guint rsrp;
+
+ gboolean gsm_info;
+ guint rxlev;
+ gdouble rssi;
+ guint ber;
+
+ gboolean umts_info;
+ guint rscp_level;
+ gdouble rscp;
+ guint ecn0_level;
+ gdouble ecio;
+
+ gboolean lte_info;
+ guint rsrq_level;
+ gdouble rsrq;
+ guint rsrp_level;
+ gdouble rsrp;
} CesqResponseTest;
static const CesqResponseTest cesq_response_tests[] = {
{
- .str = "+CESQ: 99,99,255,255,20,80",
- .rxlev = 99,
- .ber = 99,
- .rscp = 255,
- .ecn0 = 255,
- .rsrq = 20,
- .rsrp = 80
+ .str = "+CESQ: 99,99,255,255,20,80",
+ .gsm_info = FALSE, .rxlev = 99, .ber = 99,
+ .umts_info = FALSE, .rscp_level = 255, .ecn0_level = 255,
+ .lte_info = TRUE, .rsrq_level = 20, .rsrq = -10.0, .rsrp_level = 80, .rsrp = -61.0,
},
{
- .str = "+CESQ: 99,99,95,40,255,255",
- .rxlev = 99,
- .ber = 99,
- .rscp = 95,
- .ecn0 = 40,
- .rsrq = 255,
- .rsrp = 255
+ .str = "+CESQ: 99,99,95,40,255,255",
+ .gsm_info = FALSE, .rxlev = 99, .ber = 99,
+ .umts_info = TRUE, .rscp_level = 95, .rscp = -26.0, .ecn0_level = 40, .ecio = -4.5,
+ .lte_info = FALSE, .rsrq_level = 255, .rsrp_level = 255,
},
{
- .str = "+CESQ: 10,6,255,255,255,255",
- .rxlev = 10,
- .ber = 6,
- .rscp = 255,
- .ecn0 = 255,
- .rsrq = 255,
- .rsrp = 255
+ .str = "+CESQ: 10,6,255,255,255,255",
+ .gsm_info = TRUE, .rxlev = 10, .rssi = -101.0, .ber = 6,
+ .umts_info = FALSE, .rscp_level = 255, .ecn0_level = 255,
+ .lte_info = FALSE, .rsrq_level = 255, .rsrp_level = 255,
}
};
@@ -3178,13 +3186,55 @@ test_cesq_response (void)
g_assert_no_error (error);
g_assert (success);
- g_assert_cmpuint (cesq_response_tests[i].rxlev, ==, rxlev);
- g_assert_cmpuint (cesq_response_tests[i].ber, ==, ber);
- g_assert_cmpuint (cesq_response_tests[i].rscp, ==, rscp);
- g_assert_cmpuint (cesq_response_tests[i].ecn0, ==, ecn0);
- g_assert_cmpuint (cesq_response_tests[i].rsrq, ==, rsrq);
- g_assert_cmpuint (cesq_response_tests[i].rsrp, ==, rsrp);
->>>>>>> fa0bc3bc... modem-helpers: new +CESQ response parser
+ g_assert_cmpuint (cesq_response_tests[i].rxlev, ==, rxlev);
+ g_assert_cmpuint (cesq_response_tests[i].ber, ==, ber);
+ g_assert_cmpuint (cesq_response_tests[i].rscp_level, ==, rscp);
+ g_assert_cmpuint (cesq_response_tests[i].ecn0_level, ==, ecn0);
+ g_assert_cmpuint (cesq_response_tests[i].rsrq_level, ==, rsrq);
+ g_assert_cmpuint (cesq_response_tests[i].rsrp_level, ==, rsrp);
+ }
+}
+
+static void
+test_cesq_response_to_signal (void)
+{
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS (cesq_response_tests); i++) {
+ GError *error = NULL;
+ gboolean success;
+ MMSignal *gsm = NULL;
+ MMSignal *umts = NULL;
+ MMSignal *lte = NULL;
+
+ success = mm_3gpp_cesq_response_to_signal_info (cesq_response_tests[i].str,
+ &gsm, &umts, &lte,
+ &error);
+ g_assert_no_error (error);
+ g_assert (success);
+
+ if (cesq_response_tests[i].gsm_info) {
+ g_assert (gsm);
+ g_assert_cmpfloat_tolerance (mm_signal_get_rssi (gsm), cesq_response_tests[i].rssi, 0.1);
+ g_object_unref (gsm);
+ } else
+ g_assert (!gsm);
+
+ if (cesq_response_tests[i].umts_info) {
+ g_assert (umts);
+ g_assert_cmpfloat_tolerance (mm_signal_get_rscp (umts), cesq_response_tests[i].rscp, 0.1);
+ g_assert_cmpfloat_tolerance (mm_signal_get_ecio (umts), cesq_response_tests[i].ecio, 0.1);
+ g_object_unref (umts);
+ } else
+ g_assert (!umts);
+
+ if (cesq_response_tests[i].lte_info) {
+ g_assert (lte);
+ g_assert_cmpfloat_tolerance (mm_signal_get_rsrq (lte), cesq_response_tests[i].rsrq, 0.1);
+ g_assert_cmpfloat_tolerance (mm_signal_get_rsrp (lte), cesq_response_tests[i].rsrp, 0.1);
+ g_object_unref (lte);
+ } else
+ g_assert (!lte);
}
}
@@ -3455,6 +3505,7 @@ int main (int argc, char **argv)
g_test_suite_add (suite, TESTCASE (test_cfun_generic_response, NULL));
g_test_suite_add (suite, TESTCASE (test_cesq_response, NULL));
+ g_test_suite_add (suite, TESTCASE (test_cesq_response_to_signal, NULL));
g_test_suite_add (suite, TESTCASE (test_parse_uint_list, NULL));