aboutsummaryrefslogtreecommitdiff
path: root/src/mm-modem-helpers.c
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 /src/mm-modem-helpers.c
parentdf6f6d1f37dfeb27c27cf54e6181df9eaf162322 (diff)
modem-helpers: new helper to parse +CESQ response into MMSignal objects
Diffstat (limited to 'src/mm-modem-helpers.c')
-rw-r--r--src/mm-modem-helpers.c217
1 files changed, 183 insertions, 34 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;
}