ofono.lists.linux.dev archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/3]  gemalto: netmon driver
@ 2021-01-15 16:25 Sergey Matyukevich
  2021-01-15 16:25 ` [PATCH v2 1/3] gemalto: add " Sergey Matyukevich
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Sergey Matyukevich @ 2021-01-15 16:25 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 900 bytes --]

Hello Denis and all,

This patch series implements netmon driver for gemalto modems that are
able to provide basic measurements using AT+CQS and AT^SMONI commands.
For now netmon driver is enabled for ELS81x modems.

Regards,
Sergey

v1 -> v2

- use g_new0 instead of g_try_new0
- remove rssi scaling: keep using 27.007 range
- scale modem measurement reports to ranges recommended by 27.007

Sergey Matyukevich (3):
  gemalto: add netmon driver
  plugin: gemalto: enable netmon
  gemalto: netmon measurements scaling

 Makefile.am                         |   3 +-
 drivers/gemaltomodem/gemaltomodem.c |   2 +
 drivers/gemaltomodem/gemaltomodem.h |   3 +
 drivers/gemaltomodem/netmon.c       | 649 ++++++++++++++++++++++++++++
 plugins/gemalto.c                   |   6 +
 5 files changed, 662 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gemaltomodem/netmon.c

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2 1/3] gemalto: add netmon driver
  2021-01-15 16:25 [PATCH v2 0/3] gemalto: netmon driver Sergey Matyukevich
@ 2021-01-15 16:25 ` Sergey Matyukevich
  2021-01-15 16:25 ` [PATCH v2 2/3] plugin: gemalto: enable netmon Sergey Matyukevich
  2021-01-15 16:25 ` [PATCH v2 3/3] gemalto: netmon measurements scaling Sergey Matyukevich
  2 siblings, 0 replies; 6+ messages in thread
From: Sergey Matyukevich @ 2021-01-15 16:25 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 19930 bytes --]

Implement network monitoring driver for gemalto modems that
are able to provide serving cell information and basic
measurements using AT+CQS and AT^SMONI commands.
---
 Makefile.am                         |   3 +-
 drivers/gemaltomodem/gemaltomodem.c |   2 +
 drivers/gemaltomodem/gemaltomodem.h |   3 +
 drivers/gemaltomodem/netmon.c       | 605 ++++++++++++++++++++++++++++
 4 files changed, 612 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gemaltomodem/netmon.c

diff --git a/Makefile.am b/Makefile.am
index c0631081..5e7614c1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -483,7 +483,8 @@ builtin_sources += drivers/atmodem/atutil.h \
 			drivers/gemaltomodem/gemaltomodem.c \
 			drivers/gemaltomodem/location-reporting.c \
 			drivers/gemaltomodem/voicecall.c \
-			drivers/gemaltomodem/gprs-context.c
+			drivers/gemaltomodem/gprs-context.c \
+			drivers/gemaltomodem/netmon.c
 
 builtin_modules += xmm7modem
 builtin_sources += drivers/atmodem/atutil.h \
diff --git a/drivers/gemaltomodem/gemaltomodem.c b/drivers/gemaltomodem/gemaltomodem.c
index 4b20dd1b..f7e4ff3e 100644
--- a/drivers/gemaltomodem/gemaltomodem.c
+++ b/drivers/gemaltomodem/gemaltomodem.c
@@ -38,6 +38,7 @@ static int gemaltomodem_init(void)
 	gemalto_location_reporting_init();
 	gemalto_gprs_context_init();
 	gemalto_voicecall_init();
+	gemalto_netmon_init();
 
 	return 0;
 }
@@ -47,6 +48,7 @@ static void gemaltomodem_exit(void)
 	gemalto_location_reporting_exit();
 	gemalto_gprs_context_exit();
 	gemalto_voicecall_exit();
+	gemalto_netmon_exit();
 }
 
 OFONO_PLUGIN_DEFINE(gemaltomodem, "Gemalto modem driver", VERSION,
diff --git a/drivers/gemaltomodem/gemaltomodem.h b/drivers/gemaltomodem/gemaltomodem.h
index dc0d346b..ae8f2141 100644
--- a/drivers/gemaltomodem/gemaltomodem.h
+++ b/drivers/gemaltomodem/gemaltomodem.h
@@ -30,3 +30,6 @@ extern void gemalto_voicecall_exit();
 
 extern void gemalto_gprs_context_init();
 extern void gemalto_gprs_context_exit();
+
+extern void gemalto_netmon_init(void);
+extern void gemalto_netmon_exit(void);
diff --git a/drivers/gemaltomodem/netmon.c b/drivers/gemaltomodem/netmon.c
new file mode 100644
index 00000000..ddaebf1a
--- /dev/null
+++ b/drivers/gemaltomodem/netmon.c
@@ -0,0 +1,605 @@
+/*
+ *
+ *  oFono - Open Source Telephony
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include <ofono/log.h>
+#include <ofono/modem.h>
+#include <ofono/netreg.h>
+#include <ofono/netmon.h>
+
+#include "gatchat.h"
+#include "gatresult.h"
+
+#include "common.h"
+#include "gemaltomodem.h"
+#include "drivers/atmodem/vendor.h"
+
+static const char *smoni_prefix[] = { "^SMONI:", NULL };
+static const char *csq_prefix[] = { "+CSQ:", NULL };
+
+struct netmon_driver_data {
+	GAtChat *chat;
+};
+
+struct req_cb_data {
+	gint ref_count; /* Ref count */
+
+	struct ofono_netmon *netmon;
+	ofono_netmon_cb_t cb;
+	void *data;
+
+	struct ofono_network_operator op;
+
+	int rssi;	/* CSQ: received signal strength indicator (RSSI) */
+
+	union {
+		struct {
+			int arfcn;	/* SMONI: Absolute Radio Frequency Channel Number */
+			int bcch;	/* SMONI: Receiving level of the BCCH carrier in dBm */
+			int lac;	/* SMONI: Location Area Code */
+			int ci;		/* SMONI: Cell ID */
+		} gsm;
+		struct {
+			int uarfcn;	/* SMONI: UTRAN Absolute Radio Frequency Channel Number */
+			int psc;	/* SMONI: Primary Scrambling Code */
+			int ecno;	/* SMONI: Carrier to noise ratio in dB */
+			int rscp;	/* SMONI: Received Signal Code Power in dBm */
+			int lac;	/* SMONI: Location Area Code */
+			int ci;		/* SMONI: Cell ID */
+		} umts;
+		struct {
+			int euarfcn;	/* SMONI: E-UTRA Absolute Radio Frequency Channel Number */
+			int rsrp;	/* SMONI: Reference Signal Received Power */
+			int rsrq;	/* SMONI: Reference Signal Received Quality */
+		} lte;
+	} t;
+};
+
+static inline struct req_cb_data *req_cb_data_new0(void *cb, void *data,
+							void *user)
+{
+	struct req_cb_data *ret = g_new0(struct req_cb_data, 1);
+
+	ret->ref_count = 1;
+	ret->netmon = user;
+	ret->data = data;
+	ret->cb = cb;
+
+	return ret;
+}
+
+static inline struct req_cb_data *req_cb_data_ref(struct req_cb_data *cbd)
+{
+	if (cbd == NULL)
+		return NULL;
+
+	g_atomic_int_inc(&cbd->ref_count);
+
+	return cbd;
+}
+
+static void req_cb_data_unref(gpointer user_data)
+{
+	struct req_cb_data *cbd = user_data;
+	gboolean is_zero;
+
+	if (cbd == NULL)
+		return;
+
+	is_zero = g_atomic_int_dec_and_test(&cbd->ref_count);
+
+	if (is_zero == TRUE)
+		g_free(cbd);
+}
+
+static gboolean gemalto_delayed_register(gpointer user_data)
+{
+	struct ofono_netmon *netmon = user_data;
+
+	ofono_netmon_register(netmon);
+
+	return FALSE;
+}
+
+static int gemalto_parse_smoni_gsm(GAtResultIter *iter,
+					struct req_cb_data *cbd)
+{
+	/*
+	 * ME is camping on a GSM (2G) cell:
+	 * ^SMONI: ACT,ARFCN,BCCH,MCC,MNC,LAC,cell,C1,C2,NCC,BCC,GPRS,Conn_state
+	 * ^SMONI: 2G,71,-61,262,02,0143,83BA,33,33,3,6,G,NOCONN
+	 *
+	 * ME is searching and could not (yet) find a suitable GSM (2G) cell:
+	 * ^SMONI: ACT,ARFCN,BCCH,MCC,MNC,LAC,cell,C1,C2,NCC,BCC,GPRS,ARFCN,TS,timAdv,dBm,Q,ChMod
+	 * ^SMONI: 2G,SEARCH,SEARCH
+	 *
+	 * ME is camping on a GSM cell but not registered to the network (only emergency call allowed):
+	 * ^SMONI: ACT,ARFCN,BCCH,MCC,MNC,LAC,cell,C1,C2,NCC,BCC,GPRS,PWR,RXLev,ARFCN,TS,timAdv,dBm,Q,ChMod
+	 * ^SMONI: 2G,673,-89,262,07,4EED,A500,16,16,7,4,G,5,-107,LIMSRV
+	 *
+	 * ME has a dedicated channel (for example call in progress):
+	 * ^SMONI: ACT,ARFCN,BCCH,MCC,MNC,LAC,cell,C1,C2,NCC,BCC,GPRS,ARFCN,TS,timAdv,dBm,Q,ChMod
+	 * ^SMONI: 2G,673,-80,262,07,4EED,A500,35,35,7,4,G,643,4,0,-80,0,S_FR
+	 */
+
+	enum smoni_gsm_field {
+		SMONI_GSM_ARFCN,
+		SMONI_GSM_BCCH,
+		SMONI_GSM_MCC,
+		SMONI_GSM_MNC,
+		SMONI_GSM_LAC,
+		SMONI_GSM_CI,
+		SMONI_GSM_MAX,
+	};
+
+	const char *str;
+	int number;
+	int idx;
+
+	cbd->t.gsm.arfcn = -1;
+	cbd->t.gsm.bcch = -1;
+	cbd->t.gsm.lac = -1;
+	cbd->t.gsm.ci = -1;
+
+	for (idx = 0; idx < SMONI_GSM_MAX; idx++) {
+		switch (idx) {
+		case SMONI_GSM_ARFCN:
+			if (g_at_result_iter_next_number(iter, &number))
+				cbd->t.gsm.arfcn = number;
+			break;
+		case SMONI_GSM_BCCH:
+			if (g_at_result_iter_next_unquoted_string(iter, &str)) {
+				if (sscanf(str, "%d", &number) == 1)
+					cbd->t.gsm.bcch = number;
+			}
+			break;
+		case SMONI_GSM_MCC:
+			if (g_at_result_iter_next_number(iter, &number))
+				snprintf(cbd->op.mcc, 4, "%d", number);
+			break;
+		case SMONI_GSM_MNC:
+			if (g_at_result_iter_next_number(iter, &number))
+				snprintf(cbd->op.mnc, 4, "%d", number);
+			break;
+		case SMONI_GSM_LAC:
+			if (g_at_result_iter_next_unquoted_string(iter, &str)) {
+				if (sscanf(str, "%x", &number) == 1)
+					cbd->t.gsm.lac = number;
+			}
+			break;
+		case SMONI_GSM_CI:
+			if (g_at_result_iter_next_unquoted_string(iter, &str)) {
+				if (sscanf(str, "%x", &number) == 1)
+					cbd->t.gsm.ci = number;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	DBG(" %-15s %s", "GSM.MCC", cbd->op.mcc);
+	DBG(" %-15s %s", "GSM.MNC", cbd->op.mnc);
+	DBG(" %-15s %d", "GSM.ARFCN", cbd->t.gsm.arfcn);
+	DBG(" %-15s %d", "GSM.BCCH", cbd->t.gsm.bcch);
+	DBG(" %-15s %d", "GSM.LAC", cbd->t.gsm.lac);
+	DBG(" %-15s %d", "GSM.CELL", cbd->t.gsm.ci);
+
+	return 0;
+}
+
+static int gemalto_parse_smoni_umts(GAtResultIter *iter,
+					struct req_cb_data *cbd)
+{
+	/*
+	 * ME is camping on a UMTS (3G) cell:
+	 * ^SMONI: ACT,UARFCN,PSC,EC/n0,RSCP,MCC,MNC,LAC,cell,SQual,SRxLev,,Conn_state
+	 * ^SMONI: 3G,10564,296,-7.5,-79,262,02,0143,00228FF,-92,-78,NOCONN
+	 *
+	 * ME is searching and could not (yet) find a suitable UMTS (3G) cell:
+	 * ^SMONI: ACT,UARFCN,PSC,EC/n0,RSCP,MCC,MNC,LAC,cell,SQual,SRxLev,PhysCh, SF,Slot,EC/n0,RSCP,ComMod,HSUPA,HSDPA
+	 * ^SMONI: 3G,SEARCH,SEARCH
+	 *
+	 * ME is camping on a UMTS cell but not registered to the network (only emergency call allowed):
+	 * ^SMONI: ACT,UARFCN,PSC,EC/n0,RSCP,MCC,MNC,LAC,cell,SQual,SRxLev,PhysCh, SF,Slot,EC/n0,RSCP,ComMod,HSUPA,HSDPA
+	 * ^SMONI: 3G,10564,96,-7.5,-79,262,02,0143,00228FF,-92,-78,LIMSRV
+	 *
+	 * ME has a dedicated channel (for example call in progress):
+	 * ^SMONI: ACT,UARFCN,PSC,EC/n0,RSCP,MCC,MNC,LAC,cell,SQual,SRxLev,PhysCh, SF,Slot,EC/n0,RSCP,ComMod,HSUPA,HSDPA
+	 * ^SMONI: 3G,10737,131,-5,-93,260,01,7D3D,C80BC9A,--,--,----,---,-,-5,-93,0,01,06
+	 */
+
+	enum smoni_umts_field {
+		SMONI_UMTS_UARFCN,
+		SMONI_UMTS_PSC,
+		SMONI_UMTS_ECN0,
+		SMONI_UMTS_RSCP,
+		SMONI_UMTS_MCC,
+		SMONI_UMTS_MNC,
+		SMONI_UMTS_LAC,
+		SMONI_UMTS_CI,
+		SMONI_UMTS_MAX,
+	};
+
+	const char *str;
+	float fnumber;
+	int number;
+	int idx;
+
+	cbd->t.umts.uarfcn = -1;
+	cbd->t.umts.psc = -1;
+	cbd->t.umts.ecno = -1;
+	cbd->t.umts.rscp = -1;
+	cbd->t.umts.lac = -1;
+	cbd->t.umts.ci = -1;
+
+	for (idx = 0; idx < SMONI_UMTS_MAX; idx++) {
+		switch (idx) {
+		case SMONI_UMTS_UARFCN:
+			if (g_at_result_iter_next_number(iter, &number))
+				cbd->t.umts.uarfcn = number;
+			break;
+		case SMONI_UMTS_PSC:
+			if (g_at_result_iter_next_number(iter, &number))
+				cbd->t.umts.psc = number;
+			break;
+		case SMONI_UMTS_ECN0:
+			if (g_at_result_iter_next_unquoted_string(iter, &str)) {
+				if (sscanf(str, "%f", &fnumber) == 1)
+					cbd->t.umts.ecno = (int)fnumber;
+			}
+			break;
+		case SMONI_UMTS_RSCP:
+			if (g_at_result_iter_next_unquoted_string(iter, &str)) {
+				if (sscanf(str, "%d", &number) == 1)
+					cbd->t.umts.rscp = number;
+			}
+			break;
+		case SMONI_UMTS_MCC:
+			if (g_at_result_iter_next_number(iter, &number))
+				snprintf(cbd->op.mcc, 4, "%d", number);
+			break;
+		case SMONI_UMTS_MNC:
+			if (g_at_result_iter_next_number(iter, &number))
+				snprintf(cbd->op.mnc, 4, "%d", number);
+			break;
+		case SMONI_UMTS_LAC:
+			if (g_at_result_iter_next_unquoted_string(iter, &str)) {
+				if (sscanf(str, "%x", &number) == 1)
+					cbd->t.umts.lac = number;
+			}
+			break;
+		case SMONI_UMTS_CI:
+			if (g_at_result_iter_next_unquoted_string(iter, &str)) {
+				if (sscanf(str, "%x", &number) == 1)
+					cbd->t.umts.ci = number;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+
+	DBG(" %-15s %s", "UMTS.MCC", cbd->op.mcc);
+	DBG(" %-15s %s", "UMTS.MNC", cbd->op.mnc);
+	DBG(" %-15s %d", "UMTS.UARFCN", cbd->t.umts.uarfcn);
+	DBG(" %-15s %d", "UMTS.PSC", cbd->t.umts.psc);
+	DBG(" %-15s %d", "UMTS.ECN0", cbd->t.umts.ecno);
+	DBG(" %-15s %d", "UMTS.RSCP", cbd->t.umts.rscp);
+	DBG(" %-15s %d", "UMTS.LAC", cbd->t.umts.lac);
+	DBG(" %-15s %d", "UMTS.CELL", cbd->t.umts.ci);
+
+	return 0;
+}
+
+static int gemalto_parse_smoni_lte(GAtResultIter *iter,
+					struct req_cb_data *cbd)
+{
+	/*
+	 * ME is camping on a LTE (4G) cell:
+	 * ^SMONI: ACT,EARFCN,Band,DL bandwidth,UL bandwidth,Mode,MCC,MNC,TAC,Global Cell ID,Phys-ical Cell ID,Srxlev,RSRP,RSRQ,Conn_state
+	 * ^SMONI: 4G,6300,20,10,10,FDD,262,02,BF75,0345103,350,33,-94,-7,NOCONN
+	 *
+	 * ME is searching and could not (yet) find a suitable LTE (4G) cell:
+	 * ^SMONI: ACT,EARFCN,Band,DL bandwidth,UL bandwidth,Mode,MCC,MNC,TAC,Global Cell ID,Phys-ical Cell ID,Srxlev,RSRP,RSRQ,Conn_state
+	 * ^SMONI: 4G,SEARCH
+	 *
+	 * ME is camping on a LTE (4G) cell but not registered to the network (only emergency call allowed):
+	 * ^SMONI: ACT,EARFCN,Band,DL bandwidth,UL bandwidth,Mode,MCC,MNC,TAC,Global Cell ID,Phys-ical Cell ID,Srxlev,RSRP,RSRQ,Conn_state
+	 * ^SMONI: 4G,6300,20,10,10,FDD,262,02,BF75,0345103,350,33,-94,-7,LIMSRV
+	 *
+	 * ME has a dedicated channel (for example call in progress):
+	 * ^SMONI: ACT,EARFCN,Band,DL bandwidth,UL bandwidth,Mode,MCC,MNC,TAC,Global Cell ID,Phys-ical Cell ID,TX_power,RSRP,RSRQ,Conn_state
+	 * ^SMONI: 4G,6300,20,10,10,FDD,262,02,BF75,0345103,350,90,-94,-7,CONN
+	 */
+
+	const char *str;
+	int number;
+
+	cbd->t.lte.euarfcn = -1;
+	cbd->t.lte.rsrp = -1;
+	cbd->t.lte.rsrq = -1;
+
+	if (g_at_result_iter_next_number(iter, &number))
+		cbd->t.lte.euarfcn = number;
+
+	g_at_result_iter_skip_next(iter);
+	g_at_result_iter_skip_next(iter);
+	g_at_result_iter_skip_next(iter);
+	g_at_result_iter_skip_next(iter);
+
+	if (g_at_result_iter_next_number(iter, &number))
+		snprintf(cbd->op.mcc, 4, "%d", number);
+
+	if (g_at_result_iter_next_number(iter, &number))
+		snprintf(cbd->op.mnc, 4, "%d", number);
+
+	g_at_result_iter_skip_next(iter);
+	g_at_result_iter_skip_next(iter);
+	g_at_result_iter_skip_next(iter);
+	g_at_result_iter_skip_next(iter);
+
+	if (g_at_result_iter_next_unquoted_string(iter, &str)) {
+		if (sscanf(str, "%d", &number) == 1)
+			cbd->t.lte.rsrp = number;
+	}
+
+	if (g_at_result_iter_next_unquoted_string(iter, &str)) {
+		if (sscanf(str, "%d", &number) == 1)
+			cbd->t.lte.rsrq = number;
+	}
+
+	DBG(" %-15s %s", "LTE.MCC", cbd->op.mcc);
+	DBG(" %-15s %s", "LTE.MNC", cbd->op.mnc);
+	DBG(" %-15s %d", "LTE.EUARFCN", cbd->t.lte.euarfcn);
+	DBG(" %-15s %d", "LTE.RSRP", cbd->t.lte.rsrp);
+	DBG(" %-15s %d", "LTE.RSRQ", cbd->t.lte.rsrq);
+
+	return 0;
+}
+
+static void gemalto_netmon_finish_success(struct req_cb_data *cbd)
+{
+	struct ofono_netmon *nm = cbd->netmon;
+
+	switch (cbd->op.tech) {
+	case OFONO_NETMON_CELL_TYPE_LTE:
+		ofono_netmon_serving_cell_notify(nm, cbd->op.tech,
+					OFONO_NETMON_INFO_MCC, cbd->op.mcc,
+					OFONO_NETMON_INFO_MNC, cbd->op.mnc,
+					OFONO_NETMON_INFO_RSSI, cbd->rssi,
+					OFONO_NETMON_INFO_EARFCN, cbd->t.lte.euarfcn,
+					OFONO_NETMON_INFO_RSRP, cbd->t.lte.rsrp,
+					OFONO_NETMON_INFO_RSRQ, cbd->t.lte.rsrq,
+					OFONO_NETMON_INFO_INVALID);
+		break;
+	case OFONO_NETMON_CELL_TYPE_UMTS:
+		ofono_netmon_serving_cell_notify(nm, cbd->op.tech,
+					OFONO_NETMON_INFO_MCC, cbd->op.mcc,
+					OFONO_NETMON_INFO_MNC, cbd->op.mnc,
+					OFONO_NETMON_INFO_RSSI, cbd->rssi,
+					OFONO_NETMON_INFO_ARFCN, cbd->t.umts.uarfcn,
+					OFONO_NETMON_INFO_PSC, cbd->t.umts.psc,
+					OFONO_NETMON_INFO_ECN0, cbd->t.umts.ecno,
+					OFONO_NETMON_INFO_RSCP, cbd->t.umts.rscp,
+					OFONO_NETMON_INFO_LAC, cbd->t.umts.lac,
+					OFONO_NETMON_INFO_CI, cbd->t.umts.ci,
+					OFONO_NETMON_INFO_INVALID);
+		break;
+	case OFONO_NETMON_CELL_TYPE_GSM:
+		ofono_netmon_serving_cell_notify(nm, cbd->op.tech,
+					OFONO_NETMON_INFO_MCC, cbd->op.mcc,
+					OFONO_NETMON_INFO_MNC, cbd->op.mnc,
+					OFONO_NETMON_INFO_RSSI, cbd->rssi,
+					OFONO_NETMON_INFO_ARFCN, cbd->t.gsm.arfcn,
+					OFONO_NETMON_INFO_LAC, cbd->t.gsm.lac,
+					OFONO_NETMON_INFO_CI, cbd->t.gsm.ci,
+					OFONO_NETMON_INFO_INVALID);
+		break;
+	default:
+		break;
+	}
+
+	CALLBACK_WITH_SUCCESS(cbd->cb, cbd->data);
+}
+
+static void csq_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+	struct req_cb_data *cbd = user_data;
+	struct ofono_error error;
+	GAtResultIter iter;
+	int rssi;
+
+	DBG("ok %d", ok);
+
+	decode_at_error(&error, g_at_result_final_response(result));
+
+	if (!ok) {
+		CALLBACK_WITH_FAILURE(cbd->cb, cbd->data);
+		return;
+	}
+
+	g_at_result_iter_init(&iter, result);
+
+	if (!g_at_result_iter_next(&iter, "+CSQ: ")) {
+		cbd->rssi = -1;
+		goto out;
+	}
+
+	if (!g_at_result_iter_next_number(&iter, &rssi) || rssi == 99)
+		cbd->rssi = -1;
+	else
+		cbd->rssi = rssi;
+
+	DBG(" RSSI %d ", cbd->rssi);
+
+out:
+	gemalto_netmon_finish_success(cbd);
+}
+
+static void smoni_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+	struct req_cb_data *cbd = user_data;
+	struct ofono_netmon *nm = cbd->netmon;
+	struct netmon_driver_data *nmd = ofono_netmon_get_data(nm);
+	struct ofono_error error;
+	const char *technology;
+	GAtResultIter iter;
+	int ret;
+
+	DBG("ok %d", ok);
+
+	decode_at_error(&error, g_at_result_final_response(result));
+
+	if (!ok) {
+		CALLBACK_WITH_FAILURE(cbd->cb, cbd->data);
+		return;
+	}
+
+	g_at_result_iter_init(&iter, result);
+
+	/* do not fail */
+
+	if (!g_at_result_iter_next(&iter, "^SMONI: ")) {
+		CALLBACK_WITH_SUCCESS(cbd->cb, cbd->data);
+		return;
+	}
+
+	if (!g_at_result_iter_next_unquoted_string(&iter, &technology)) {
+		DBG("^SMONI: failed to parse technology");
+		CALLBACK_WITH_SUCCESS(cbd->cb, cbd->data);
+		return;
+	}
+
+	if (strcmp(technology, "2G") == 0) {
+		cbd->op.tech = OFONO_NETMON_CELL_TYPE_GSM;
+	} else if (strcmp(technology, "3G") == 0) {
+		cbd->op.tech = OFONO_NETMON_CELL_TYPE_UMTS;
+	} else if (strcmp(technology, "4G") == 0) {
+		cbd->op.tech = OFONO_NETMON_CELL_TYPE_LTE;
+	} else {
+		/* fall-back to GSM by default */
+		DBG("^SMONI: unexpected technology: %s", technology);
+		cbd->op.tech = OFONO_NETMON_CELL_TYPE_GSM;
+	}
+
+	switch (cbd->op.tech) {
+	case OFONO_NETMON_CELL_TYPE_LTE:
+		ret = gemalto_parse_smoni_lte(&iter, cbd);
+		break;
+	case OFONO_NETMON_CELL_TYPE_UMTS:
+		ret = gemalto_parse_smoni_umts(&iter, cbd);
+		break;
+	case OFONO_NETMON_CELL_TYPE_GSM:
+		ret = gemalto_parse_smoni_gsm(&iter, cbd);
+		break;
+	default:
+		break;
+	}
+
+	if (ret) {
+		CALLBACK_WITH_SUCCESS(cbd->cb, cbd->data);
+		return;
+	}
+
+	cbd = req_cb_data_ref(cbd);
+	if (g_at_chat_send(nmd->chat, "AT+CSQ", csq_prefix,
+				csq_cb, cbd, req_cb_data_unref))
+		return;
+
+	req_cb_data_unref(cbd);
+	CALLBACK_WITH_FAILURE(cbd->cb, cbd->data);
+}
+
+static void gemalto_netmon_request_update(struct ofono_netmon *netmon,
+						ofono_netmon_cb_t cb,
+						void *data)
+{
+	struct netmon_driver_data *nmd = ofono_netmon_get_data(netmon);
+	struct req_cb_data *cbd;
+
+	DBG("gemalto netmon request update");
+
+	cbd = req_cb_data_new0(cb, data, netmon);
+
+	if (g_at_chat_send(nmd->chat, "AT^SMONI", smoni_prefix,
+				smoni_cb, cbd, req_cb_data_unref))
+		return;
+
+	req_cb_data_unref(cbd);
+	CALLBACK_WITH_FAILURE(cbd->cb, cbd->data);
+}
+
+static int gemalto_netmon_probe(struct ofono_netmon *netmon,
+					unsigned int vendor, void *user)
+{
+	struct netmon_driver_data *nmd = g_new0(struct netmon_driver_data, 1);
+	GAtChat *chat = user;
+
+	DBG("gemalto netmon probe");
+
+	nmd->chat = g_at_chat_clone(chat);
+
+	ofono_netmon_set_data(netmon, nmd);
+
+	g_idle_add(gemalto_delayed_register, netmon);
+
+	return 0;
+}
+
+static void gemalto_netmon_remove(struct ofono_netmon *netmon)
+{
+	struct netmon_driver_data *nmd = ofono_netmon_get_data(netmon);
+
+	DBG("gemalto netmon remove");
+
+	g_at_chat_unref(nmd->chat);
+
+	ofono_netmon_set_data(netmon, NULL);
+
+	g_free(nmd);
+}
+
+static const struct ofono_netmon_driver driver = {
+	.name			= "gemaltomodem",
+	.probe			= gemalto_netmon_probe,
+	.remove			= gemalto_netmon_remove,
+	.request_update		= gemalto_netmon_request_update,
+};
+
+void gemalto_netmon_init(void)
+{
+	ofono_netmon_driver_register(&driver);
+}
+
+void gemalto_netmon_exit(void)
+{
+	ofono_netmon_driver_unregister(&driver);
+}

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v2 2/3] plugin: gemalto: enable netmon
  2021-01-15 16:25 [PATCH v2 0/3] gemalto: netmon driver Sergey Matyukevich
  2021-01-15 16:25 ` [PATCH v2 1/3] gemalto: add " Sergey Matyukevich
@ 2021-01-15 16:25 ` Sergey Matyukevich
  2021-01-15 16:25 ` [PATCH v2 3/3] gemalto: netmon measurements scaling Sergey Matyukevich
  2 siblings, 0 replies; 6+ messages in thread
From: Sergey Matyukevich @ 2021-01-15 16:25 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 1245 bytes --]

Enable netmon functionality for Gemalto ELS81x modems.
---
 plugins/gemalto.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/plugins/gemalto.c b/plugins/gemalto.c
index 28ee3aff..135e2d26 100644
--- a/plugins/gemalto.c
+++ b/plugins/gemalto.c
@@ -48,6 +48,7 @@
 #include <ofono/gprs.h>
 #include <ofono/gprs-context.h>
 #include <ofono/location-reporting.h>
+#include <ofono/netmon.h>
 
 #include <drivers/atmodem/atutil.h>
 #include <drivers/atmodem/vendor.h>
@@ -622,6 +623,7 @@ static void gemalto_post_sim(struct ofono_modem *modem)
 static void gemalto_post_online(struct ofono_modem *modem)
 {
 	struct gemalto_data *data = ofono_modem_get_data(modem);
+	const char *model = ofono_modem_get_string(modem, "Model");
 
 	DBG("%p", modem);
 
@@ -634,6 +636,10 @@ static void gemalto_post_online(struct ofono_modem *modem)
 	ofono_call_settings_create(modem, 0, "atmodem", data->app);
 	ofono_call_meter_create(modem, 0, "atmodem", data->app);
 	ofono_call_barring_create(modem, 0, "atmodem", data->app);
+
+	if (!g_strcmp0(model, GEMALTO_MODEL_ELS81x))
+		ofono_netmon_create(modem, OFONO_VENDOR_GEMALTO,
+					"gemaltomodem", data->app);
 }
 
 static struct ofono_modem_driver gemalto_driver = {

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH v2 3/3] gemalto: netmon measurements scaling
  2021-01-15 16:25 [PATCH v2 0/3] gemalto: netmon driver Sergey Matyukevich
  2021-01-15 16:25 ` [PATCH v2 1/3] gemalto: add " Sergey Matyukevich
  2021-01-15 16:25 ` [PATCH v2 2/3] plugin: gemalto: enable netmon Sergey Matyukevich
@ 2021-01-15 16:25 ` Sergey Matyukevich
  2021-01-15 17:46   ` Denis Kenzior
  2 siblings, 1 reply; 6+ messages in thread
From: Sergey Matyukevich @ 2021-01-15 16:25 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 2623 bytes --]

Gemalto modem reports raw measurements in dBm. Reported values may
include negative numbers. Meanwhile oFono follows ETSI TS 27.007,
so negative numbers do not really exist at the API level.

Modify gemalto netmon driver to report measurements according to
27.007. For this purpose re-scale from what Gemalto firmware
reports into something that 27.007 recommends.
---
 drivers/gemaltomodem/netmon.c | 52 ++++++++++++++++++++++++++++++++---
 1 file changed, 48 insertions(+), 4 deletions(-)

diff --git a/drivers/gemaltomodem/netmon.c b/drivers/gemaltomodem/netmon.c
index ddaebf1a..c3a0498d 100644
--- a/drivers/gemaltomodem/netmon.c
+++ b/drivers/gemaltomodem/netmon.c
@@ -128,6 +128,50 @@ static gboolean gemalto_delayed_register(gpointer user_data)
 	return FALSE;
 }
 
+static int gemalto_ecno_scale(int value)
+{
+	if (value < -24)
+		return 0;
+
+	if (value > 0)
+		return 49;
+
+	return 49 * (value + 24) / 24;
+}
+
+static int gemalto_rscp_scale(int value)
+{
+	if (value < -120)
+		return 0;
+
+	if (value > -24)
+		return 96;
+
+	return (value + 120);
+}
+
+static int gemalto_rsrp_scale(int value)
+{
+	if (value < -140)
+		return 0;
+
+	if (value > -43)
+		return 97;
+
+	return (value + 140);
+}
+
+static int gemalto_rsrq_scale(int value)
+{
+	if (2 * value < -39)
+		return 0;
+
+	if (2 * value > -5)
+		return 34;
+
+	return (2 * value + 39);
+}
+
 static int gemalto_parse_smoni_gsm(GAtResultIter *iter,
 					struct req_cb_data *cbd)
 {
@@ -273,13 +317,13 @@ static int gemalto_parse_smoni_umts(GAtResultIter *iter,
 		case SMONI_UMTS_ECN0:
 			if (g_at_result_iter_next_unquoted_string(iter, &str)) {
 				if (sscanf(str, "%f", &fnumber) == 1)
-					cbd->t.umts.ecno = (int)fnumber;
+					cbd->t.umts.ecno = gemalto_ecno_scale((int)fnumber);
 			}
 			break;
 		case SMONI_UMTS_RSCP:
 			if (g_at_result_iter_next_unquoted_string(iter, &str)) {
 				if (sscanf(str, "%d", &number) == 1)
-					cbd->t.umts.rscp = number;
+					cbd->t.umts.rscp = gemalto_rscp_scale(number);
 			}
 			break;
 		case SMONI_UMTS_MCC:
@@ -368,12 +412,12 @@ static int gemalto_parse_smoni_lte(GAtResultIter *iter,
 
 	if (g_at_result_iter_next_unquoted_string(iter, &str)) {
 		if (sscanf(str, "%d", &number) == 1)
-			cbd->t.lte.rsrp = number;
+			cbd->t.lte.rsrp = gemalto_rsrp_scale(number);
 	}
 
 	if (g_at_result_iter_next_unquoted_string(iter, &str)) {
 		if (sscanf(str, "%d", &number) == 1)
-			cbd->t.lte.rsrq = number;
+			cbd->t.lte.rsrq = gemalto_rsrq_scale(number);
 	}
 
 	DBG(" %-15s %s", "LTE.MCC", cbd->op.mcc);

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v2 3/3] gemalto: netmon measurements scaling
  2021-01-15 16:25 ` [PATCH v2 3/3] gemalto: netmon measurements scaling Sergey Matyukevich
@ 2021-01-15 17:46   ` Denis Kenzior
  2021-01-15 19:11     ` Sergey Matyukevich
  0 siblings, 1 reply; 6+ messages in thread
From: Denis Kenzior @ 2021-01-15 17:46 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 2122 bytes --]

Hi Sergey,

On 1/15/21 10:25 AM, Sergey Matyukevich wrote:
> Gemalto modem reports raw measurements in dBm. Reported values may
> include negative numbers. Meanwhile oFono follows ETSI TS 27.007,
> so negative numbers do not really exist at the API level.
> 
> Modify gemalto netmon driver to report measurements according to
> 27.007. For this purpose re-scale from what Gemalto firmware
> reports into something that 27.007 recommends.
> ---
>   drivers/gemaltomodem/netmon.c | 52 ++++++++++++++++++++++++++++++++---
>   1 file changed, 48 insertions(+), 4 deletions(-)
> 

I went ahead and applied all three patches after making minor tweaks in this one:

> +static int gemalto_rscp_scale(int value)
> +{
> +	if (value < -120)
> +		return 0;
> +
> +	if (value > -24)
> +		return 96;
> +
> +	return (value + 120);

The ()s weren't needed here..

> +}
> +
> +static int gemalto_rsrp_scale(int value)
> +{
> +	if (value < -140)
> +		return 0;
> +
> +	if (value > -43)
> +		return 97;
> +
> +	return (value + 140);

here and ...

> +}
> +
> +static int gemalto_rsrq_scale(int value)
> +{
> +	if (2 * value < -39)
> +		return 0;
> +
> +	if (2 * value > -5)
> +		return 34;
> +
> +	return (2 * value + 39);

here

> +}
> +
>   static int gemalto_parse_smoni_gsm(GAtResultIter *iter,
>   					struct req_cb_data *cbd)
>   {
> @@ -273,13 +317,13 @@ static int gemalto_parse_smoni_umts(GAtResultIter *iter,
>   		case SMONI_UMTS_ECN0:
>   			if (g_at_result_iter_next_unquoted_string(iter, &str)) {
>   				if (sscanf(str, "%f", &fnumber) == 1)
> -					cbd->t.umts.ecno = (int)fnumber;
> +					cbd->t.umts.ecno = gemalto_ecno_scale((int)fnumber);

Also added a line break to better wrap to 80 char columns here...

>   			}
>   			break;
>   		case SMONI_UMTS_RSCP:
>   			if (g_at_result_iter_next_unquoted_string(iter, &str)) {
>   				if (sscanf(str, "%d", &number) == 1)
> -					cbd->t.umts.rscp = number;
> +					cbd->t.umts.rscp = gemalto_rscp_scale(number);

and here

>   			}
>   			break;
>   		case SMONI_UMTS_MCC:

Regards,
-Denis

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2 3/3] gemalto: netmon measurements scaling
  2021-01-15 17:46   ` Denis Kenzior
@ 2021-01-15 19:11     ` Sergey Matyukevich
  0 siblings, 0 replies; 6+ messages in thread
From: Sergey Matyukevich @ 2021-01-15 19:11 UTC (permalink / raw)
  To: ofono

[-- Attachment #1: Type: text/plain, Size: 1073 bytes --]

Hello Denis,

> > Gemalto modem reports raw measurements in dBm. Reported values may
> > include negative numbers. Meanwhile oFono follows ETSI TS 27.007,
> > so negative numbers do not really exist at the API level.
> > 
> > Modify gemalto netmon driver to report measurements according to
> > 27.007. For this purpose re-scale from what Gemalto firmware
> > reports into something that 27.007 recommends.
> > ---
> >   drivers/gemaltomodem/netmon.c | 52 ++++++++++++++++++++++++++++++++---
> >   1 file changed, 48 insertions(+), 4 deletions(-)
> > 
> 
> I went ahead and applied all three patches after making minor tweaks in this one:

Thanks!

> > +static int gemalto_rscp_scale(int value)
> > +{
> > +	if (value < -120)
> > +		return 0;
> > +
> > +	if (value > -24)
> > +		return 96;
> > +
> > +	return (value + 120);
> 
> The ()s weren't needed here..

Well, I did check coding style document for arithmetic expressions,
but I did not find anything other than spaces around operators. 
So I made a wrong guess...

Regards,
Sergey

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2021-01-15 19:11 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-15 16:25 [PATCH v2 0/3] gemalto: netmon driver Sergey Matyukevich
2021-01-15 16:25 ` [PATCH v2 1/3] gemalto: add " Sergey Matyukevich
2021-01-15 16:25 ` [PATCH v2 2/3] plugin: gemalto: enable netmon Sergey Matyukevich
2021-01-15 16:25 ` [PATCH v2 3/3] gemalto: netmon measurements scaling Sergey Matyukevich
2021-01-15 17:46   ` Denis Kenzior
2021-01-15 19:11     ` Sergey Matyukevich

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).