Open Source Telephony
 help / color / mirror / Atom feed
From: Sean Nyekjaer <sean@geanix.com>
To: denkenz@gmail.com, ofono@lists.linux.dev
Cc: Sean Nyekjaer <sean@geanix.com>
Subject: [PATCH v2 1/2] simcommodem: Add netmon driver for Simcom A7671E
Date: Thu, 16 Apr 2026 09:19:47 +0200	[thread overview]
Message-ID: <20260416071949.2221937-1-sean@geanix.com> (raw)

---
Changes in v2:
 - Removed unused ref counting

 Makefile.am                  |   3 +-
 drivers/simcommodem/netmon.c | 240 +++++++++++++++++++++++++++++++++++
 plugins/sim7100.c            |   2 +
 3 files changed, 244 insertions(+), 1 deletion(-)
 create mode 100644 drivers/simcommodem/netmon.c

diff --git a/Makefile.am b/Makefile.am
index cf51cdf1..6f10d396 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -541,7 +541,8 @@ builtin_sources += drivers/atmodem/atutil.h \
 			drivers/quectelmodem/radio-settings.c
 
 builtin_sources += drivers/atmodem/atutil.h \
-			drivers/simcommodem/radio-settings.c
+			drivers/simcommodem/radio-settings.c \
+			drivers/simcommodem/netmon.c
 
 if PHONESIM
 builtin_modules += phonesim
diff --git a/drivers/simcommodem/netmon.c b/drivers/simcommodem/netmon.c
new file mode 100644
index 00000000..8981ea51
--- /dev/null
+++ b/drivers/simcommodem/netmon.c
@@ -0,0 +1,240 @@
+/*
+ * oFono - Open Source Telephony
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ */
+
+#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 <drivers/atmodem/atutil.h>
+
+#include "gatchat.h"
+#include "gatresult.h"
+
+#include "common.h"
+
+#include "drivers/atmodem/vendor.h"
+
+static const char *cpsi_prefix[] = { "+CPSI:", NULL };
+
+struct netmon_driver_data {
+	GAtChat *chat;
+};
+
+struct req_cb_data {
+	struct ofono_netmon *netmon;
+	ofono_netmon_cb_t cb;
+	void *data;
+
+	struct ofono_network_operator op;
+
+	int rssi;	/* CSQ: received signal strength indicator (RSSI) */
+
+	struct {
+		int tac;	/* CPSI: Tracing Area Code */
+		int pcell;	/* CPSI: Physical Cell ID */
+		int earfcn;	/* CPSI: E-UTRA Absolute Radio Frequency Channel Number */
+		int rsrp;	/* CPSI: Reference Signal Received Power */
+		int rsrq;	/* CPSI: Reference Signal Received Quality */
+	} lte;
+};
+
+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->netmon = user;
+	ret->data = data;
+	ret->cb = cb;
+
+	return ret;
+}
+
+static int simcom_parse_cpsi_lte(GAtResultIter *iter, struct req_cb_data *cbd) {
+	/*
+	 * +CPSI: <System Mode>,<Operation Mode>[,<MCC>-<MNC>,<TAC>,<SCellID>,<PCellID>,<Frequency Band>,<earfcn>,<dlbw>,<ulbw>,<RSRQ>,<RSRP>,<RSSI>,<RSSNR>]
+	 * +CPSI: LTE,Online,460-01,0x230A,175499523,318,EUTRAN-BAND3,1650,5,0,21,67,255,19
+	 */
+
+	struct ofono_netmon *nm = cbd->netmon;
+	int number;
+	const char *field = NULL;
+	char *mcc = NULL;
+	char *mnc = NULL;
+
+	cbd->lte.earfcn = -1;
+	cbd->lte.rsrp = -1;
+	cbd->lte.rsrq = -1;
+
+	g_at_result_iter_skip_next(iter);
+
+	if (g_at_result_iter_next_unquoted_string(iter, &field)) {
+		mcc = strdup(field);
+		mnc = strchr(mcc, '-');
+		if(mnc != NULL) {
+			*mnc++ = 0;
+			snprintf(cbd->op.mcc, 4, "%s", mcc);
+			snprintf(cbd->op.mnc, 4, "%s", mnc);
+		}
+		free(mcc);
+	}
+
+	if (g_at_result_iter_next_unquoted_string(iter, &field))
+		cbd->lte.tac = strtol(field, NULL, 16);
+
+	g_at_result_iter_skip_next(iter);
+
+	if (g_at_result_iter_next_number(iter, &number))
+		cbd->lte.pcell = number;
+
+	g_at_result_iter_skip_next(iter);
+
+	if (g_at_result_iter_next_number(iter, &number))
+		cbd->lte.earfcn = number;
+
+	g_at_result_iter_skip_next(iter);
+	g_at_result_iter_skip_next(iter);
+
+	if (g_at_result_iter_next_number(iter, &number))
+		cbd->lte.rsrq = number;
+
+	if (g_at_result_iter_next_number(iter, &number))
+		cbd->lte.rsrp = number;
+
+	if (g_at_result_iter_next_number(iter, &number))
+		cbd->rssi = number;
+
+	DBG(" %-15s %s", "LTE.MCC", cbd->op.mcc);
+	DBG(" %-15s %s", "LTE.MNC", cbd->op.mnc);
+	DBG(" %-15s %d", "LTE.TAC", cbd->lte.tac);
+	DBG(" %-15s %d", "LTE.PCI", cbd->lte.pcell);
+	DBG(" %-15s %d", "LTE.EUARFCN", cbd->lte.earfcn);
+	DBG(" %-15s %d", "LTE.RSRP", cbd->lte.rsrp);
+	DBG(" %-15s %d", "LTE.RSRQ", cbd->lte.rsrq);
+
+	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_TAC, cbd->lte.tac,
+		OFONO_NETMON_INFO_PCI, cbd->lte.pcell,
+		OFONO_NETMON_INFO_RSSI, cbd->rssi,
+		OFONO_NETMON_INFO_EARFCN, cbd->lte.earfcn,
+		OFONO_NETMON_INFO_RSRP, cbd->lte.rsrp,
+		OFONO_NETMON_INFO_RSRQ, cbd->lte.rsrq,
+		OFONO_NETMON_INFO_INVALID);
+}
+
+static void cpsi_cb(gboolean ok, GAtResult *result, gpointer user_data) {
+	struct req_cb_data *cbd = user_data;
+	struct ofono_error error;
+	const char *technology;
+	GAtResultIter iter;
+
+	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, "+CPSI: ")) {
+		ofono_warn("Failed to find iterate +CPSI response");
+		CALLBACK_WITH_SUCCESS(cbd->cb, cbd->data);
+		return;
+	}
+
+	if (!g_at_result_iter_next_unquoted_string(&iter, &technology)) {
+		ofono_warn("+CPSI: failed to parse technology");
+		CALLBACK_WITH_SUCCESS(cbd->cb, cbd->data);
+		return;
+	}
+
+	if (strcmp(technology, "LTE") == 0) {
+		cbd->op.tech = OFONO_NETMON_CELL_TYPE_LTE;
+		simcom_parse_cpsi_lte(&iter, cbd);
+	} else if (strcmp(technology, "NO SERVICE") == 0 ) {
+		cbd->op.tech = -1;
+	} else {
+		ofono_warn("Unknown technology in +CPSI response: %s", technology);
+		cbd->op.tech = -1;
+	}
+
+	CALLBACK_WITH_SUCCESS(cbd->cb, cbd->data);
+}
+
+static void simcom_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("simcom netmon request update");
+
+	cbd = req_cb_data_new0(cb, data, netmon);
+
+	if (g_at_chat_send(nmd->chat, "AT+CPSI?", cpsi_prefix, cpsi_cb, cbd,
+				g_free) == 0) {
+		CALLBACK_WITH_FAILURE(cbd->cb, cbd->data);
+		g_free(cbd);
+	}
+
+}
+
+static int simcom_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("simcom netmon probe");
+
+	nmd->chat = g_at_chat_clone(chat);
+
+	ofono_netmon_set_data(netmon, nmd);
+
+	ofono_netmon_register(netmon);
+
+	return 0;
+}
+
+static void simcom_netmon_remove(struct ofono_netmon *netmon)
+{
+	struct netmon_driver_data *nmd = ofono_netmon_get_data(netmon);
+
+	DBG("simcom netmon remove");
+
+	g_at_chat_unref(nmd->chat);
+
+	ofono_netmon_set_data(netmon, NULL);
+
+	g_free(nmd);
+}
+
+static const struct ofono_netmon_driver driver = {
+	.probe			= simcom_netmon_probe,
+	.remove			= simcom_netmon_remove,
+	.request_update		= simcom_netmon_request_update,
+};
+
+OFONO_ATOM_DRIVER_BUILTIN(netmon, simcommodem, &driver);
diff --git a/plugins/sim7100.c b/plugins/sim7100.c
index c4fc5798..0d937868 100644
--- a/plugins/sim7100.c
+++ b/plugins/sim7100.c
@@ -34,6 +34,7 @@
 #include <ofono/call-settings.h>
 #include <ofono/devinfo.h>
 #include <ofono/message-waiting.h>
+#include <ofono/netmon.h>
 #include <ofono/netreg.h>
 #include <ofono/phonebook.h>
 #include <ofono/radio-settings.h>
@@ -357,6 +358,7 @@ static void sim7100_post_sim(struct ofono_modem *modem)
 		ofono_sms_create(modem, OFONO_VENDOR_SIMCOM_A76XX,
 							"atmodem", data->at);
 		ofono_radio_settings_create(modem, 0, "simcommodem", data->at);
+		ofono_netmon_create(modem, 0, "simcommodem", data->at);
 		gprs = ofono_gprs_create(modem, OFONO_VENDOR_SIMCOM_A76XX,
 							"atmodem", data->at);
 		break;
-- 
2.52.0


             reply	other threads:[~2026-04-16  7:20 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-16  7:19 Sean Nyekjaer [this message]
2026-04-16  7:19 ` [PATCH v2 2/2] doc: netmon: fix indentation Sean Nyekjaer

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260416071949.2221937-1-sean@geanix.com \
    --to=sean@geanix.com \
    --cc=denkenz@gmail.com \
    --cc=ofono@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox