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
_______________________________________________
ofono mailing list
[email protected]
https://lists.ofono.org/mailman/listinfo/ofono