All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/7] gatresult: strip trailing spaces from unquoted strings
@ 2019-07-16 19:10 Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
  2019-07-16 19:10 ` [PATCH 2/7] atmodem: rename OFONO_VENDOR_QUECTEL_M95 to OFONO_VENDOR_QUECTEL_SERIAL Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
                   ` (6 more replies)
  0 siblings, 7 replies; 10+ messages in thread
From: Martin =?unknown-8bit?q?Hundeb=C3=B8ll?= @ 2019-07-16 19:10 UTC (permalink / raw)
  To: ofono

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

Some vendors might print trailing spaces after unsolicited result codes.
Avoid duplicating and stripping the string after calling
g_at_result_iter_next_unquoted_string() by stripping the spaces in
gatresult instead.
---
 gatchat/gatresult.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/gatchat/gatresult.c b/gatchat/gatresult.c
index 2659db28..883b4105 100644
--- a/gatchat/gatresult.c
+++ b/gatchat/gatresult.c
@@ -111,6 +111,7 @@ gboolean g_at_result_iter_next_unquoted_string(GAtResultIter *iter,
 	unsigned int pos;
 	unsigned int end;
 	unsigned int len;
+	unsigned int stripped;
 	char *line;
 
 	if (iter == NULL)
@@ -139,7 +140,12 @@ gboolean g_at_result_iter_next_unquoted_string(GAtResultIter *iter,
 	while (end < len && line[end] != ',' && line[end] != ')')
 		end += 1;
 
-	iter->buf[end] = '\0';
+	stripped = end;
+
+	while (line[stripped - 1] == ' ')
+		stripped -= 1;
+
+	iter->buf[stripped] = '\0';
 
 out:
 	iter->line_pos = skip_to_next_field(line, end, len);
-- 
2.22.0


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

* [PATCH 2/7] atmodem: rename OFONO_VENDOR_QUECTEL_M95 to OFONO_VENDOR_QUECTEL_SERIAL
  2019-07-16 19:10 [PATCH 1/7] gatresult: strip trailing spaces from unquoted strings Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
@ 2019-07-16 19:10 ` Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
  2019-07-16 19:10 ` [PATCH 3/7] quectel: enable call volume settings Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Martin =?unknown-8bit?q?Hundeb=C3=B8ll?= @ 2019-07-16 19:10 UTC (permalink / raw)
  To: ofono

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

Other serial connected modems (i.e the MC60 model) from is AT-compatible
with the M95 model, so rename the M95 vendor id to be common for both.
---
 drivers/atmodem/sim.c    | 4 ++--
 drivers/atmodem/sms.c    | 4 ++--
 drivers/atmodem/vendor.h | 2 +-
 plugins/quectel.c        | 2 +-
 4 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/atmodem/sim.c b/drivers/atmodem/sim.c
index 520b3dbf..dd42cac4 100644
--- a/drivers/atmodem/sim.c
+++ b/drivers/atmodem/sim.c
@@ -1217,7 +1217,7 @@ static void at_pin_retries_query(struct ofono_sim *sim,
 					at_qpinc_cb, cbd, g_free) > 0)
 			return;
 		break;
-	case OFONO_VENDOR_QUECTEL_M95:
+	case OFONO_VENDOR_QUECTEL_SERIAL:
 		if (g_at_chat_send(sd->chat, "AT+QTRPIN", qtrpin_prefix,
 					at_qtrpin_cb, cbd, g_free) > 0)
 			return;
@@ -1354,7 +1354,7 @@ static void at_pin_send_cb(gboolean ok, GAtResult *result,
 	case OFONO_VENDOR_HUAWEI:
 	case OFONO_VENDOR_SIMCOM:
 	case OFONO_VENDOR_SIERRA:
-	case OFONO_VENDOR_QUECTEL_M95:
+	case OFONO_VENDOR_QUECTEL_SERIAL:
 		/*
 		 * On ZTE modems, after pin is entered, SIM state is checked
 		 * by polling CPIN as their modem doesn't provide unsolicited
diff --git a/drivers/atmodem/sms.c b/drivers/atmodem/sms.c
index c3c82afb..442cfc58 100644
--- a/drivers/atmodem/sms.c
+++ b/drivers/atmodem/sms.c
@@ -339,7 +339,7 @@ static inline void at_ack_delivery(struct ofono_sms *sms)
 		case OFONO_VENDOR_GEMALTO:
 			snprintf(buf, sizeof(buf), "AT+CNMA=1");
 			break;
-		case OFONO_VENDOR_QUECTEL_M95:
+		case OFONO_VENDOR_QUECTEL_SERIAL:
 			snprintf(buf, sizeof(buf), "AT+CNMA");
 			break;
 		default:
@@ -1289,7 +1289,7 @@ static void at_csms_query_cb(gboolean ok, GAtResult *result,
 		goto out;
 
 	switch (data->vendor) {
-	case OFONO_VENDOR_QUECTEL_M95:
+	case OFONO_VENDOR_QUECTEL_SERIAL:
 		g_at_result_iter_next_number(&iter, &status_min);
 		g_at_result_iter_next_number(&iter, &status_max);
 		if (status_min <= 1 && 1 <= status_max)
diff --git a/drivers/atmodem/vendor.h b/drivers/atmodem/vendor.h
index 10c04315..d839d1e0 100644
--- a/drivers/atmodem/vendor.h
+++ b/drivers/atmodem/vendor.h
@@ -44,7 +44,7 @@ enum ofono_vendor {
 	OFONO_VENDOR_WAVECOM_Q2XXX,
 	OFONO_VENDOR_ALCATEL,
 	OFONO_VENDOR_QUECTEL,
-	OFONO_VENDOR_QUECTEL_M95,
+	OFONO_VENDOR_QUECTEL_SERIAL,
 	OFONO_VENDOR_UBLOX,
 	OFONO_VENDOR_XMM,
 	OFONO_VENDOR_GEMALTO,
diff --git a/plugins/quectel.c b/plugins/quectel.c
index 11b864bc..f2b765b6 100644
--- a/plugins/quectel.c
+++ b/plugins/quectel.c
@@ -330,7 +330,7 @@ static void cgmm_cb(int ok, GAtResult *result, void *user_data)
 		data->vendor = OFONO_VENDOR_QUECTEL;
 	} else if (strcmp(model, "Quectel_M95") == 0) {
 		DBG("%p model M95", modem);
-		data->vendor = OFONO_VENDOR_QUECTEL_M95;
+		data->vendor = OFONO_VENDOR_QUECTEL_SERIAL;
 	} else {
 		ofono_warn("%p unknown model: '%s'", modem, model);
 		data->vendor = OFONO_VENDOR_QUECTEL;
-- 
2.22.0


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

* [PATCH 3/7] quectel: enable call volume settings
  2019-07-16 19:10 [PATCH 1/7] gatresult: strip trailing spaces from unquoted strings Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
  2019-07-16 19:10 ` [PATCH 2/7] atmodem: rename OFONO_VENDOR_QUECTEL_M95 to OFONO_VENDOR_QUECTEL_SERIAL Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
@ 2019-07-16 19:10 ` Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
  2019-07-16 19:10 ` [PATCH 4/7] quectel: store model id in private data Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Martin =?unknown-8bit?q?Hundeb=C3=B8ll?= @ 2019-07-16 19:10 UTC (permalink / raw)
  To: ofono

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

---
 plugins/quectel.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/plugins/quectel.c b/plugins/quectel.c
index f2b765b6..61b82744 100644
--- a/plugins/quectel.c
+++ b/plugins/quectel.c
@@ -45,6 +45,7 @@
 #include <ofono/sms.h>
 #include <ofono/phonebook.h>
 #include <ofono/voicecall.h>
+#include <ofono/call-volume.h>
 #include <ofono/gprs.h>
 #include <ofono/gprs-context.h>
 #include <ofono/log.h>
@@ -398,6 +399,7 @@ static void call_ready_notify(GAtResult *result, void *user_data)
 
 	ofono_phonebook_create(modem, 0, "atmodem", data->aux);
 	ofono_voicecall_create(modem, 0, "atmodem", data->aux);
+	ofono_call_volume_create(modem, 0, "atmodem", data->aux);
 }
 
 static int open_ttys(struct ofono_modem *modem)
-- 
2.22.0


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

* [PATCH 4/7] quectel: store model id in private data
  2019-07-16 19:10 [PATCH 1/7] gatresult: strip trailing spaces from unquoted strings Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
  2019-07-16 19:10 ` [PATCH 2/7] atmodem: rename OFONO_VENDOR_QUECTEL_M95 to OFONO_VENDOR_QUECTEL_SERIAL Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
  2019-07-16 19:10 ` [PATCH 3/7] quectel: enable call volume settings Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
@ 2019-07-16 19:10 ` Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
  2019-07-16 19:10 ` [PATCH 5/7] quectel: add support for the Quectel MC60 modem Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Martin =?unknown-8bit?q?Hundeb=C3=B8ll?= @ 2019-07-16 19:10 UTC (permalink / raw)
  To: ofono

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

Some Quectel models supports different features such has GNSS or
different URC strings. Add a field in the quectel data structure to be
used when adding support for said features.
---
 plugins/quectel.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/plugins/quectel.c b/plugins/quectel.c
index 61b82744..e84e3cf1 100644
--- a/plugins/quectel.c
+++ b/plugins/quectel.c
@@ -70,6 +70,13 @@ static const uint8_t gsm0710_terminate[] = {
 	0xf9, /* close flag */
 };
 
+enum quectel_model {
+	QUECTEL_UNKNOWN,
+	QUECTEL_UC15,
+	QUECTEL_M95,
+	QUECTEL_MC60,
+};
+
 struct quectel_data {
 	GAtChat *modem;
 	GAtChat *aux;
@@ -77,6 +84,7 @@ struct quectel_data {
 	guint call_ready;
 	bool have_sim;
 	enum ofono_vendor vendor;
+	enum quectel_model model;
 	struct l_timeout *sms_ready_timer;
 
 	/* used by quectel uart driver */
@@ -329,12 +337,15 @@ static void cgmm_cb(int ok, GAtResult *result, void *user_data)
 	if (strcmp(model, "UC15") == 0) {
 		DBG("%p model UC15", modem);
 		data->vendor = OFONO_VENDOR_QUECTEL;
+		data->model = QUECTEL_UC15;
 	} else if (strcmp(model, "Quectel_M95") == 0) {
 		DBG("%p model M95", modem);
 		data->vendor = OFONO_VENDOR_QUECTEL_SERIAL;
+		data->model = QUECTEL_M95;
 	} else {
 		ofono_warn("%p unknown model: '%s'", modem, model);
 		data->vendor = OFONO_VENDOR_QUECTEL;
+		data->model = QUECTEL_UNKNOWN;
 	}
 
 	g_at_chat_send(data->aux, "AT+CFUN?", cfun_prefix, cfun_query, modem,
-- 
2.22.0


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

* [PATCH 5/7] quectel: add support for the Quectel MC60 modem
  2019-07-16 19:10 [PATCH 1/7] gatresult: strip trailing spaces from unquoted strings Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
                   ` (2 preceding siblings ...)
  2019-07-16 19:10 ` [PATCH 4/7] quectel: store model id in private data Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
@ 2019-07-16 19:10 ` Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
  2019-07-16 19:10 ` [PATCH 6/7] quectel: add dbus hardware interface Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 10+ messages in thread
From: Martin =?unknown-8bit?q?Hundeb=C3=B8ll?= @ 2019-07-16 19:10 UTC (permalink / raw)
  To: ofono

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

The modem is AT-compatible with the Quectel M95 modem, but also features
a GNSS module.
---
 plugins/quectel.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/plugins/quectel.c b/plugins/quectel.c
index e84e3cf1..9cac92fa 100644
--- a/plugins/quectel.c
+++ b/plugins/quectel.c
@@ -56,7 +56,8 @@
 static const char *cfun_prefix[] = { "+CFUN:", NULL };
 static const char *cpin_prefix[] = { "+CPIN:", NULL };
 static const char *qinistat_prefix[] = { "+QINISTAT:", NULL };
-static const char *cgmm_prefix[] = { "UC15", "Quectel_M95", NULL };
+static const char *cgmm_prefix[] = { "UC15", "Quectel_M95", "Quectel_MC60",
+					NULL };
 static const char *none_prefix[] = { NULL };
 
 static const uint8_t gsm0710_terminate[] = {
@@ -342,6 +343,10 @@ static void cgmm_cb(int ok, GAtResult *result, void *user_data)
 		DBG("%p model M95", modem);
 		data->vendor = OFONO_VENDOR_QUECTEL_SERIAL;
 		data->model = QUECTEL_M95;
+	} else if (strcmp(model, "Quectel_MC60") == 0) {
+		DBG("%p model MC60", modem);
+		data->vendor = OFONO_VENDOR_QUECTEL_SERIAL;
+		data->model = QUECTEL_MC60;
 	} else {
 		ofono_warn("%p unknown model: '%s'", modem, model);
 		data->vendor = OFONO_VENDOR_QUECTEL;
-- 
2.22.0


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

* [PATCH 6/7] quectel: add dbus hardware interface
  2019-07-16 19:10 [PATCH 1/7] gatresult: strip trailing spaces from unquoted strings Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
                   ` (3 preceding siblings ...)
  2019-07-16 19:10 ` [PATCH 5/7] quectel: add support for the Quectel MC60 modem Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
@ 2019-07-16 19:10 ` Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
  2019-07-19  6:11   ` Denis Kenzior
  2019-07-16 19:10 ` [PATCH 7/7] quectel: implement dbus signals for modem power notifications Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
  2019-07-19  4:45 ` [PATCH 1/7] gatresult: strip trailing spaces from unquoted strings Denis Kenzior
  6 siblings, 1 reply; 10+ messages in thread
From: Martin =?unknown-8bit?q?Hundeb=C3=B8ll?= @ 2019-07-16 19:10 UTC (permalink / raw)
  To: ofono

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

For now the interface only exposes the modem supply voltage, but is
added as a preparation for signaling power events.
---
 doc/quectel-hardware-api.txt |  15 ++++
 plugins/quectel.c            | 154 +++++++++++++++++++++++++++++++++++
 2 files changed, 169 insertions(+)
 create mode 100644 doc/quectel-hardware-api.txt

diff --git a/doc/quectel-hardware-api.txt b/doc/quectel-hardware-api.txt
new file mode 100644
index 00000000..f54ea8c7
--- /dev/null
+++ b/doc/quectel-hardware-api.txt
@@ -0,0 +1,15 @@
+Hardware hierarchy
+==================
+
+Service		org.ofono
+Interface	org.ofono.quectel.Hardware
+Object path	/{device0,device1,...}
+
+Methods		array{string,variant} GetProperties
+
+			Returns hardware properties for the modem object. See
+			the properties section for available properties.
+
+Properties	uint32 Voltage [readonly]
+
+			Integer with the modem supply voltage in mV.
diff --git a/plugins/quectel.c b/plugins/quectel.c
index 9cac92fa..3c1d49cd 100644
--- a/plugins/quectel.c
+++ b/plugins/quectel.c
@@ -37,6 +37,7 @@
 #include <gattty.h>
 
 #define OFONO_API_SUBJECT_TO_CHANGE
+#include <ofono.h>
 #include <ofono/plugin.h>
 #include <ofono/modem.h>
 #include <ofono/devinfo.h>
@@ -49,12 +50,16 @@
 #include <ofono/gprs.h>
 #include <ofono/gprs-context.h>
 #include <ofono/log.h>
+#include <ofono/dbus.h>
+
+#include <gdbus/gdbus.h>
 
 #include <drivers/atmodem/atutil.h>
 #include <drivers/atmodem/vendor.h>
 
 static const char *cfun_prefix[] = { "+CFUN:", NULL };
 static const char *cpin_prefix[] = { "+CPIN:", NULL };
+static const char *cbc_prefix[] = { "+CBC:", NULL };
 static const char *qinistat_prefix[] = { "+QINISTAT:", NULL };
 static const char *cgmm_prefix[] = { "UC15", "Quectel_M95", "Quectel_MC60",
 					NULL };
@@ -95,6 +100,148 @@ struct quectel_data {
 	struct l_gpio_writer *gpio;
 };
 
+struct dbus_hw {
+	DBusMessage *msg;
+	struct ofono_modem *modem;
+	gint charge_status;
+	gint charge_level;
+	gint voltage;
+};
+
+static const char dbus_hw_interface[] = OFONO_SERVICE ".quectel.Hardware";
+
+static void dbus_hw_reply_properties(struct dbus_hw *hw)
+{
+	struct quectel_data *data = ofono_modem_get_data(hw->modem);
+	DBusMessage *reply;
+	DBusMessageIter dbus_iter;
+	DBusMessageIter dbus_dict;
+
+	DBG("%p", hw->modem);
+
+	reply = dbus_message_new_method_return(hw->msg);
+	dbus_message_iter_init_append(reply, &dbus_iter);
+	dbus_message_iter_open_container(&dbus_iter, DBUS_TYPE_ARRAY,
+			OFONO_PROPERTIES_ARRAY_SIGNATURE,
+			&dbus_dict);
+
+	if (data->model == QUECTEL_UC15) {
+		ofono_dbus_dict_append(&dbus_dict, "ChargeStatus",
+					DBUS_TYPE_INT32, &hw->charge_status);
+
+		ofono_dbus_dict_append(&dbus_dict, "ChargeLevel",
+					DBUS_TYPE_INT32, &hw->charge_level);
+	}
+
+	ofono_dbus_dict_append(&dbus_dict, "Voltage", DBUS_TYPE_UINT32,
+				&hw->voltage);
+
+	dbus_message_iter_close_container(&dbus_iter, &dbus_dict);
+
+	__ofono_dbus_pending_reply(&hw->msg, reply);
+}
+
+static void cbc_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+	struct dbus_hw *hw = user_data;
+	GAtResultIter iter;
+
+	DBG("%p", hw->modem);
+
+	if (!hw->msg)
+		return;
+
+	if (!ok)
+		goto error;
+
+	g_at_result_iter_init(&iter, result);
+
+	if (!g_at_result_iter_next(&iter, "+CBC:"))
+		goto error;
+
+	/* only uc15 returns valid charge status */
+	if (!g_at_result_iter_next_number(&iter, &hw->charge_status))
+		goto error;
+
+	/* only uc15 returns valid charge level */
+	if (!g_at_result_iter_next_number(&iter, &hw->charge_level))
+		goto error;
+
+	/* now comes the millivolts */
+	if (!g_at_result_iter_next_number(&iter, &hw->voltage))
+		goto error;
+
+	dbus_hw_reply_properties(hw);
+
+	return;
+
+error:
+	__ofono_dbus_pending_reply(&hw->msg, __ofono_error_failed(hw->msg));
+}
+
+static DBusMessage *dbus_hw_get_properties(DBusConnection *conn,
+						DBusMessage *msg,
+						void *user_data)
+{
+	struct dbus_hw *hw = user_data;
+	struct quectel_data *data = ofono_modem_get_data(hw->modem);
+
+	DBG("%p", hw->modem);
+
+	if (hw->msg != NULL)
+		return __ofono_error_busy(msg);
+
+	if (!g_at_chat_send(data->aux, "AT+CBC", cbc_prefix, cbc_cb, hw, NULL))
+		return __ofono_error_failed(msg);
+
+	hw->msg = dbus_message_ref(msg);
+
+	return NULL;
+}
+
+static const GDBusMethodTable dbus_hw_methods[] = {
+	{ GDBUS_ASYNC_METHOD("GetProperties",
+				NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+				dbus_hw_get_properties) },
+	{}
+};
+
+static void dbus_hw_cleanup(void *data)
+{
+	struct dbus_hw *hw = data;
+
+	DBG("%p", hw->modem);
+
+	if (hw->msg)
+		__ofono_dbus_pending_reply(&hw->msg,
+					__ofono_error_canceled(hw->msg));
+
+	l_free(hw);
+}
+
+static void dbus_hw_enable(struct ofono_modem *modem)
+{
+	DBusConnection *conn = ofono_dbus_get_connection();
+	const char *path = ofono_modem_get_path(modem);
+	struct dbus_hw *hw;
+
+	DBG("%p", modem);
+
+	hw = l_new(struct dbus_hw, 1);
+	hw->modem = modem;
+
+	if (!g_dbus_register_interface(conn, path, dbus_hw_interface,
+					dbus_hw_methods, NULL, NULL,
+					hw, dbus_hw_cleanup)) {
+		ofono_error("Could not register %s interface under %s",
+				dbus_hw_interface, path);
+		l_free(hw);
+		return;
+	}
+
+	ofono_modem_add_interface(modem, dbus_hw_interface);
+}
+
 static void quectel_debug(const char *str, void *user_data)
 {
 	const char *prefix = user_data;
@@ -253,6 +400,8 @@ static void cpin_notify(GAtResult *result, gpointer user_data)
 
 	g_at_chat_unregister(data->aux, data->cpin_ready);
 	data->cpin_ready = 0;
+
+	dbus_hw_enable(modem);
 }
 
 static void cpin_query(gboolean ok, GAtResult *result, gpointer user_data)
@@ -650,9 +799,14 @@ static void cfun_disable(gboolean ok, GAtResult *result, gpointer user_data)
 static int quectel_disable(struct ofono_modem *modem)
 {
 	struct quectel_data *data = ofono_modem_get_data(modem);
+	DBusConnection *conn = ofono_dbus_get_connection();
+	const char *path = ofono_modem_get_path(modem);
 
 	DBG("%p", modem);
 
+	if (g_dbus_unregister_interface(conn, path, dbus_hw_interface))
+		ofono_modem_remove_interface(modem, dbus_hw_interface);
+
 	g_at_chat_cancel_all(data->modem);
 	g_at_chat_unregister_all(data->modem);
 
-- 
2.22.0


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

* [PATCH 7/7] quectel: implement dbus signals for modem power notifications
  2019-07-16 19:10 [PATCH 1/7] gatresult: strip trailing spaces from unquoted strings Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
                   ` (4 preceding siblings ...)
  2019-07-16 19:10 ` [PATCH 6/7] quectel: add dbus hardware interface Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
@ 2019-07-16 19:10 ` Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
  2019-07-19  6:14   ` Denis Kenzior
  2019-07-19  4:45 ` [PATCH 1/7] gatresult: strip trailing spaces from unquoted strings Denis Kenzior
  6 siblings, 1 reply; 10+ messages in thread
From: Martin =?unknown-8bit?q?Hundeb=C3=B8ll?= @ 2019-07-16 19:10 UTC (permalink / raw)
  To: ofono

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

The Quectel modems issues unsolicited strings in case of power related
events. The UC15 uses +QIND: for the events, while M95 and MC60 uses
descriptive strings. (UC15 also uses a string for normal power down).

Register listeners for these strings/codes. The handler emits an
appropriate dbus signal, and closes down the modem if needed.
---
 doc/quectel-hardware-api.txt |  19 +++++
 plugins/quectel.c            | 148 ++++++++++++++++++++++++++++++++++-
 2 files changed, 166 insertions(+), 1 deletion(-)

diff --git a/doc/quectel-hardware-api.txt b/doc/quectel-hardware-api.txt
index f54ea8c7..c9e93926 100644
--- a/doc/quectel-hardware-api.txt
+++ b/doc/quectel-hardware-api.txt
@@ -10,6 +10,25 @@ Methods		array{string,variant} GetProperties
 			Returns hardware properties for the modem object. See
 			the properties section for available properties.
 
+Signals		PowerDown(string reason)
+
+			This signal is emitted on gracefull shutdowns initiated
+			by the modem.
+
+			Possible reasons:
+				"LowPower"	The supply voltage is too low
+				"Normal"	The PWRKEY pin was asserted
+				"HighPower"	The supply voltage is too high
+
+		PowerWarning(string reason)
+
+			This signal is emitted when the modem detects its supply
+			voltage is close to its supported limits.
+
+			Possible reasons:
+				"LowPower"	The supply voltage is low
+				"HighPower"	The supply voltage is high
+
 Properties	uint32 Voltage [readonly]
 
 			Integer with the modem supply voltage in mV.
diff --git a/plugins/quectel.c b/plugins/quectel.c
index 3c1d49cd..3c74fc41 100644
--- a/plugins/quectel.c
+++ b/plugins/quectel.c
@@ -108,8 +108,122 @@ struct dbus_hw {
 	gint voltage;
 };
 
+enum quectel_power_event {
+	LOW_POWER_DOWN    = -2,
+	LOW_WARNING       = -1,
+	NORMAL_POWER_DOWN =  0,
+	HIGH_WARNING      =  1,
+	HIGH_POWER_DOWN   =  2,
+};
+
 static const char dbus_hw_interface[] = OFONO_SERVICE ".quectel.Hardware";
 
+static void close_serial(struct ofono_modem *modem);
+
+static void power_handle(struct ofono_modem *modem,
+				enum quectel_power_event event)
+{
+	DBusConnection *conn = ofono_dbus_get_connection();
+	DBusMessage *signal;
+	DBusMessageIter iter;
+	const char *path = ofono_modem_get_path(modem);
+	const char *name;
+	const char *reason;
+	bool close;
+
+	DBG("%p", modem);
+
+	switch (event) {
+	case LOW_POWER_DOWN:
+		close = true;
+		name = "PowerDown";
+		reason = "LowPower";
+		break;
+	case LOW_WARNING:
+		close = false;
+		name = "PowerWarning";
+		reason = "LowPower";
+		break;
+	case NORMAL_POWER_DOWN:
+		close = true;
+		name = "PowerDown";
+		reason = "Normal";
+		break;
+	case HIGH_WARNING:
+		close = false;
+		name = "PowerWarning";
+		reason = "HighPower";
+		break;
+	case HIGH_POWER_DOWN:
+		close = true;
+		name = "PowerDown";
+		reason = "HighPower";
+		break;
+	default:
+		return;
+	}
+
+	signal = dbus_message_new_signal(path, dbus_hw_interface, name);
+	if (signal) {
+		dbus_message_iter_init_append(signal, &iter);
+		dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
+						&reason);
+		g_dbus_send_message(conn, signal);
+	}
+
+	if (close)
+		close_serial(modem);
+}
+
+static void qind_notify(GAtResult *result, void *user_data)
+{
+	struct dbus_hw *hw = user_data;
+	GAtResultIter iter;
+	enum quectel_power_event event;
+	const char *type;
+
+	DBG("%p", hw->modem);
+
+	g_at_result_iter_init(&iter, result);
+	g_at_result_iter_next(&iter, "+QIND:");
+
+	if (!g_at_result_iter_next_string(&iter, &type))
+		return;
+
+	if (!g_at_result_iter_next_number(&iter, &event))
+		return;
+
+	power_handle(hw->modem, event);
+}
+
+static void power_notify(GAtResult *result, void *user_data)
+{
+	struct dbus_hw *hw = user_data;
+	GAtResultIter iter;
+	const char *event;
+
+	DBG("%p", hw->modem);
+
+	g_at_result_iter_init(&iter, result);
+	g_at_result_iter_next(&iter, NULL);
+
+	if (!g_at_result_iter_next_unquoted_string(&iter, &event))
+		return;
+
+	DBG("event: %s", event);
+
+	if (g_strcmp0(event, "UNDER_VOLTAGE POWER DOWN") == 0)
+		power_handle(hw->modem, LOW_POWER_DOWN);
+	else if (g_strcmp0(event, "UNDER_VOLTAGE WARNING") == 0)
+		power_handle(hw->modem, LOW_WARNING);
+	else if (g_strcmp0(event, "NORMAL POWER DOWN") == 0)
+		power_handle(hw->modem, NORMAL_POWER_DOWN);
+	else if (g_strcmp0(event, "OVER_VOLTAGE WARNING") == 0)
+		power_handle(hw->modem, HIGH_WARNING);
+	else if (g_strcmp0(event, "OVER_VOLTAGE POWER DOWN") == 0)
+		power_handle(hw->modem, HIGH_POWER_DOWN);
+}
+
 static void dbus_hw_reply_properties(struct dbus_hw *hw)
 {
 	struct quectel_data *data = ofono_modem_get_data(hw->modem);
@@ -206,6 +320,14 @@ static const GDBusMethodTable dbus_hw_methods[] = {
 	{}
 };
 
+static const GDBusSignalTable dbus_hw_signals[] = {
+	{ GDBUS_SIGNAL("PowerDown",
+			GDBUS_ARGS({ "reason", "s" })) },
+	{ GDBUS_SIGNAL("PowerWarning",
+			GDBUS_ARGS({ "reason", "s" })) },
+	{ }
+};
+
 static void dbus_hw_cleanup(void *data)
 {
 	struct dbus_hw *hw = data;
@@ -222,6 +344,7 @@ static void dbus_hw_cleanup(void *data)
 static void dbus_hw_enable(struct ofono_modem *modem)
 {
 	DBusConnection *conn = ofono_dbus_get_connection();
+	struct quectel_data *data = ofono_modem_get_data(modem);
 	const char *path = ofono_modem_get_path(modem);
 	struct dbus_hw *hw;
 
@@ -231,7 +354,7 @@ static void dbus_hw_enable(struct ofono_modem *modem)
 	hw->modem = modem;
 
 	if (!g_dbus_register_interface(conn, path, dbus_hw_interface,
-					dbus_hw_methods, NULL, NULL,
+					dbus_hw_methods, dbus_hw_signals, NULL,
 					hw, dbus_hw_cleanup)) {
 		ofono_error("Could not register %s interface under %s",
 				dbus_hw_interface, path);
@@ -239,6 +362,29 @@ static void dbus_hw_enable(struct ofono_modem *modem)
 		return;
 	}
 
+	g_at_chat_register(data->aux, "NORMAL POWER DOWN", power_notify, FALSE,
+				hw, NULL);
+
+	switch (data->model) {
+	case QUECTEL_UC15:
+		g_at_chat_register(data->aux, "+QIND",  qind_notify, FALSE, hw,
+					NULL);
+		break;
+	case QUECTEL_M95:
+	case QUECTEL_MC60:
+		g_at_chat_register(data->aux, "OVER_VOLTAGE POWER DOWN",
+					power_notify, FALSE, hw, NULL);
+		g_at_chat_register(data->aux, "UNDER_VOLTAGE POWER DOWN",
+					power_notify, FALSE, hw, NULL);
+		g_at_chat_register(data->aux, "OVER_VOLTAGE WARNING",
+					power_notify, FALSE, hw, NULL);
+		g_at_chat_register(data->aux, "UNDER_VOLTAGE WARNING",
+					power_notify, FALSE, hw, NULL);
+		break;
+	case QUECTEL_UNKNOWN:
+		break;
+	}
+
 	ofono_modem_add_interface(modem, dbus_hw_interface);
 }
 
-- 
2.22.0


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

* Re: [PATCH 1/7] gatresult: strip trailing spaces from unquoted strings
  2019-07-16 19:10 [PATCH 1/7] gatresult: strip trailing spaces from unquoted strings Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
                   ` (5 preceding siblings ...)
  2019-07-16 19:10 ` [PATCH 7/7] quectel: implement dbus signals for modem power notifications Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
@ 2019-07-19  4:45 ` Denis Kenzior
  6 siblings, 0 replies; 10+ messages in thread
From: Denis Kenzior @ 2019-07-19  4:45 UTC (permalink / raw)
  To: ofono

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

Hi Martin,

On 7/16/19 2:10 PM, Martin Hundebøll wrote:
> Some vendors might print trailing spaces after unsolicited result codes.
> Avoid duplicating and stripping the string after calling
> g_at_result_iter_next_unquoted_string() by stripping the spaces in
> gatresult instead.
> ---
>   gatchat/gatresult.c | 8 +++++++-
>   1 file changed, 7 insertions(+), 1 deletion(-)
> 

Patches 1 - 5 applied, thanks.

Regards,
-Denis


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

* Re: [PATCH 6/7] quectel: add dbus hardware interface
  2019-07-16 19:10 ` [PATCH 6/7] quectel: add dbus hardware interface Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
@ 2019-07-19  6:11   ` Denis Kenzior
  0 siblings, 0 replies; 10+ messages in thread
From: Denis Kenzior @ 2019-07-19  6:11 UTC (permalink / raw)
  To: ofono

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

Hi Martin,

On 7/16/19 2:10 PM, Martin Hundebøll wrote:
> For now the interface only exposes the modem supply voltage, but is
> added as a preparation for signaling power events.
> ---
>   doc/quectel-hardware-api.txt |  15 ++++
>   plugins/quectel.c            | 154 +++++++++++++++++++++++++++++++++++
>   2 files changed, 169 insertions(+)
>   create mode 100644 doc/quectel-hardware-api.txt

Can you please separate this per 'HACKING', 'Submitting Patches' section?

> 
> diff --git a/doc/quectel-hardware-api.txt b/doc/quectel-hardware-api.txt
> new file mode 100644
> index 00000000..f54ea8c7
> --- /dev/null
> +++ b/doc/quectel-hardware-api.txt
> @@ -0,0 +1,15 @@
> +Hardware hierarchy
> +==================
> +
> +Service		org.ofono
> +Interface	org.ofono.quectel.Hardware
> +Object path	/{device0,device1,...}
> +
> +Methods		array{string,variant} GetProperties
> +
> +			Returns hardware properties for the modem object. See
> +			the properties section for available properties.
> +
> +Properties	uint32 Voltage [readonly]
> +
> +			Integer with the modem supply voltage in mV.
> diff --git a/plugins/quectel.c b/plugins/quectel.c
> index 9cac92fa..3c1d49cd 100644
> --- a/plugins/quectel.c
> +++ b/plugins/quectel.c
> @@ -37,6 +37,7 @@
>   #include <gattty.h>
>   
>   #define OFONO_API_SUBJECT_TO_CHANGE
> +#include <ofono.h>
>   #include <ofono/plugin.h>
>   #include <ofono/modem.h>
>   #include <ofono/devinfo.h>
> @@ -49,12 +50,16 @@
>   #include <ofono/gprs.h>
>   #include <ofono/gprs-context.h>
>   #include <ofono/log.h>
> +#include <ofono/dbus.h>
> +
> +#include <gdbus/gdbus.h>
>   
>   #include <drivers/atmodem/atutil.h>
>   #include <drivers/atmodem/vendor.h>
>   
>   static const char *cfun_prefix[] = { "+CFUN:", NULL };
>   static const char *cpin_prefix[] = { "+CPIN:", NULL };
> +static const char *cbc_prefix[] = { "+CBC:", NULL };
>   static const char *qinistat_prefix[] = { "+QINISTAT:", NULL };
>   static const char *cgmm_prefix[] = { "UC15", "Quectel_M95", "Quectel_MC60",
>   					NULL };
> @@ -95,6 +100,148 @@ struct quectel_data {
>   	struct l_gpio_writer *gpio;
>   };
>   
> +struct dbus_hw {
> +	DBusMessage *msg;
> +	struct ofono_modem *modem;
> +	gint charge_status;
> +	gint charge_level;
> +	gint voltage;

You export the voltage as unsigned, but it is a signed type here...

Also, you may want to just start using standard types here instead of 
glib ones.

> +};
> +
> +static const char dbus_hw_interface[] = OFONO_SERVICE ".quectel.Hardware";
> +
> +static void dbus_hw_reply_properties(struct dbus_hw *hw)
> +{
> +	struct quectel_data *data = ofono_modem_get_data(hw->modem);
> +	DBusMessage *reply;
> +	DBusMessageIter dbus_iter;
> +	DBusMessageIter dbus_dict;
> +
> +	DBG("%p", hw->modem);
> +
> +	reply = dbus_message_new_method_return(hw->msg);
> +	dbus_message_iter_init_append(reply, &dbus_iter);
> +	dbus_message_iter_open_container(&dbus_iter, DBUS_TYPE_ARRAY,
> +			OFONO_PROPERTIES_ARRAY_SIGNATURE,
> +			&dbus_dict);
> +
> +	if (data->model == QUECTEL_UC15) {
> +		ofono_dbus_dict_append(&dbus_dict, "ChargeStatus",
> +					DBUS_TYPE_INT32, &hw->charge_status);
> +
> +		ofono_dbus_dict_append(&dbus_dict, "ChargeLevel",
> +					DBUS_TYPE_INT32, &hw->charge_level);
> +	}

These are undocumented...

> +
> +	ofono_dbus_dict_append(&dbus_dict, "Voltage", DBUS_TYPE_UINT32,
> +				&hw->voltage);
> +
> +	dbus_message_iter_close_container(&dbus_iter, &dbus_dict);
> +
> +	__ofono_dbus_pending_reply(&hw->msg, reply);
> +}
> +
> +static void cbc_cb(gboolean ok, GAtResult *result, gpointer user_data)
> +{
> +	struct dbus_hw *hw = user_data;
> +	GAtResultIter iter;
> +
> +	DBG("%p", hw->modem);
> +
> +	if (!hw->msg)
> +		return;
> +
> +	if (!ok)
> +		goto error;
> +
> +	g_at_result_iter_init(&iter, result);
> +
> +	if (!g_at_result_iter_next(&iter, "+CBC:"))
> +		goto error;
> +
> +	/* only uc15 returns valid charge status */
> +	if (!g_at_result_iter_next_number(&iter, &hw->charge_status))
> +		goto error;
> +

So the comment is a bit confusing.  Is it that every modem returns all 3 
values, but only for UC15 they're valid; or CBC returns a different set 
of values for each modem?  I assume it is the latter since this doesn't 
match the traditional 27.007 CBC syntax?

> +	/* only uc15 returns valid charge level */
> +	if (!g_at_result_iter_next_number(&iter, &hw->charge_level))
> +		goto error;
> +
> +	/* now comes the millivolts */
> +	if (!g_at_result_iter_next_number(&iter, &hw->voltage))
> +		goto error;
> +
> +	dbus_hw_reply_properties(hw);
> +
> +	return;
> +
> +error:
> +	__ofono_dbus_pending_reply(&hw->msg, __ofono_error_failed(hw->msg));
> +}
> +
> +static DBusMessage *dbus_hw_get_properties(DBusConnection *conn,
> +						DBusMessage *msg,
> +						void *user_data)
> +{
> +	struct dbus_hw *hw = user_data;
> +	struct quectel_data *data = ofono_modem_get_data(hw->modem);
> +
> +	DBG("%p", hw->modem);
> +
> +	if (hw->msg != NULL)
> +		return __ofono_error_busy(msg);
> +
> +	if (!g_at_chat_send(data->aux, "AT+CBC", cbc_prefix, cbc_cb, hw, NULL))
> +		return __ofono_error_failed(msg);
> +
> +	hw->msg = dbus_message_ref(msg);
> +
> +	return NULL;
> +}
> +
> +static const GDBusMethodTable dbus_hw_methods[] = {
> +	{ GDBUS_ASYNC_METHOD("GetProperties",
> +				NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
> +				dbus_hw_get_properties) },
> +	{}
> +};
> +
> +static void dbus_hw_cleanup(void *data)
> +{
> +	struct dbus_hw *hw = data;
> +
> +	DBG("%p", hw->modem);
> +
> +	if (hw->msg)
> +		__ofono_dbus_pending_reply(&hw->msg,
> +					__ofono_error_canceled(hw->msg));
> +
> +	l_free(hw);
> +}
> +
> +static void dbus_hw_enable(struct ofono_modem *modem)
> +{
> +	DBusConnection *conn = ofono_dbus_get_connection();
> +	const char *path = ofono_modem_get_path(modem);
> +	struct dbus_hw *hw;
> +
> +	DBG("%p", modem);
> +
> +	hw = l_new(struct dbus_hw, 1);
> +	hw->modem = modem;
> +
> +	if (!g_dbus_register_interface(conn, path, dbus_hw_interface,
> +					dbus_hw_methods, NULL, NULL,
> +					hw, dbus_hw_cleanup)) {
> +		ofono_error("Could not register %s interface under %s",
> +				dbus_hw_interface, path);
> +		l_free(hw);
> +		return;
> +	}
> +
> +	ofono_modem_add_interface(modem, dbus_hw_interface);
> +}
> +
>   static void quectel_debug(const char *str, void *user_data)
>   {
>   	const char *prefix = user_data;
> @@ -253,6 +400,8 @@ static void cpin_notify(GAtResult *result, gpointer user_data)
>   
>   	g_at_chat_unregister(data->aux, data->cpin_ready);
>   	data->cpin_ready = 0;
> +
> +	dbus_hw_enable(modem);
>   }
>   
>   static void cpin_query(gboolean ok, GAtResult *result, gpointer user_data)
> @@ -650,9 +799,14 @@ static void cfun_disable(gboolean ok, GAtResult *result, gpointer user_data)
>   static int quectel_disable(struct ofono_modem *modem)
>   {
>   	struct quectel_data *data = ofono_modem_get_data(modem);
> +	DBusConnection *conn = ofono_dbus_get_connection();
> +	const char *path = ofono_modem_get_path(modem);
>   
>   	DBG("%p", modem);
>   
> +	if (g_dbus_unregister_interface(conn, path, dbus_hw_interface))
> +		ofono_modem_remove_interface(modem, dbus_hw_interface);
> +

If you want to be paranoid, you might want to either issue a 
g_at_chat_cancel_all / g_at_chat_unregister_all here to prevent 
g_dbus_unregister_interface from freeing a structure with pending 
commands.  Or alternatively use a dedicated chat for dbus_hw_interface 
stuff (e.g. g_at_chat_clone a version)

>   	g_at_chat_cancel_all(data->modem);
>   	g_at_chat_unregister_all(data->modem);
>   
> 

Regards,
-Denis

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

* Re: [PATCH 7/7] quectel: implement dbus signals for modem power notifications
  2019-07-16 19:10 ` [PATCH 7/7] quectel: implement dbus signals for modem power notifications Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
@ 2019-07-19  6:14   ` Denis Kenzior
  0 siblings, 0 replies; 10+ messages in thread
From: Denis Kenzior @ 2019-07-19  6:14 UTC (permalink / raw)
  To: ofono

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

Hi Martin,

On 7/16/19 2:10 PM, Martin Hundebøll wrote:
> The Quectel modems issues unsolicited strings in case of power related
> events. The UC15 uses +QIND: for the events, while M95 and MC60 uses
> descriptive strings. (UC15 also uses a string for normal power down).
> 
> Register listeners for these strings/codes. The handler emits an
> appropriate dbus signal, and closes down the modem if needed.
> ---
>   doc/quectel-hardware-api.txt |  19 +++++
>   plugins/quectel.c            | 148 ++++++++++++++++++++++++++++++++++-
>   2 files changed, 166 insertions(+), 1 deletion(-)
> 

2 separate commits please per HACKING, 'Submitting Patches'

<snip>

> diff --git a/plugins/quectel.c b/plugins/quectel.c
> index 3c1d49cd..3c74fc41 100644
> --- a/plugins/quectel.c
> +++ b/plugins/quectel.c
> @@ -108,8 +108,122 @@ struct dbus_hw {
>   	gint voltage;
>   };
>   
> +enum quectel_power_event {
> +	LOW_POWER_DOWN    = -2,
> +	LOW_WARNING       = -1,
> +	NORMAL_POWER_DOWN =  0,
> +	HIGH_WARNING      =  1,
> +	HIGH_POWER_DOWN   =  2,
> +};
> +
>   static const char dbus_hw_interface[] = OFONO_SERVICE ".quectel.Hardware";
>   
> +static void close_serial(struct ofono_modem *modem);
> +

We generally frown upon forward declaration of statics...

Regards,
-Denis

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

end of thread, other threads:[~2019-07-19  6:14 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-16 19:10 [PATCH 1/7] gatresult: strip trailing spaces from unquoted strings Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
2019-07-16 19:10 ` [PATCH 2/7] atmodem: rename OFONO_VENDOR_QUECTEL_M95 to OFONO_VENDOR_QUECTEL_SERIAL Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
2019-07-16 19:10 ` [PATCH 3/7] quectel: enable call volume settings Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
2019-07-16 19:10 ` [PATCH 4/7] quectel: store model id in private data Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
2019-07-16 19:10 ` [PATCH 5/7] quectel: add support for the Quectel MC60 modem Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
2019-07-16 19:10 ` [PATCH 6/7] quectel: add dbus hardware interface Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
2019-07-19  6:11   ` Denis Kenzior
2019-07-16 19:10 ` [PATCH 7/7] quectel: implement dbus signals for modem power notifications Martin =?unknown-8bit?q?Hundeb=C3=B8ll?=
2019-07-19  6:14   ` Denis Kenzior
2019-07-19  4:45 ` [PATCH 1/7] gatresult: strip trailing spaces from unquoted strings Denis Kenzior

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.