[PATCH 3/3] sim7100: add dbus under/over voltage warnings
Sean Nyekjaer <[email protected]> Wed, 13 May 2026 14:59:23 +0200
| Newsgroups | dev.linux.lists.ofono |
|---|---|
| Message-ID | <[email protected]> |
---
plugins/sim7100.c | 284 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 281 insertions(+), 3 deletions(-)
diff --git a/plugins/sim7100.c b/plugins/sim7100.c
index 01620e31..ed4f759d 100644
--- a/plugins/sim7100.c
+++ b/plugins/sim7100.c
@@ -16,6 +16,7 @@
#include <config.h>
#endif
+#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
@@ -25,6 +26,8 @@
#include <ell/ell.h>
#define OFONO_API_SUBJECT_TO_CHANGE
+#include <ofono.h>
+#include <ofono/dbus.h>
#include <ofono/plugin.h>
#include <ofono/log.h>
#include <ofono/modem.h>
@@ -45,9 +48,12 @@
#include <ofono/gprs.h>
#include <ofono/gprs-context.h>
+#include <gdbus/gdbus.h>
+
#include <drivers/atmodem/vendor.h>
#include <drivers/atmodem/atutil.h>
+static const char *cbc_prefix[] = { "+CBC:", NULL };
static const char *cfun_prefix[] = { "+CFUN:", NULL };
enum sim7x00_model {
@@ -66,6 +72,21 @@ struct sim7100_data {
guint init_cmd;
};
+struct dbus_hw {
+ DBusMessage *msg;
+ struct ofono_modem *modem;
+ int32_t voltage;
+};
+
+enum sim7100_power_event {
+ LOW_POWER_DOWN = -2,
+ LOW_POWER_WARNING = -1,
+ HIGH_POWER_WARNING = 1,
+ HIGH_POWER_DOWN = 2,
+};
+
+static const char dbus_hw_interface[] = OFONO_SERVICE ".sim7100.Hardware";
+
static void sim7100_debug(const char *str, void *user_data)
{
const char *prefix = user_data;
@@ -109,6 +130,217 @@ static void sim7100_remove(struct ofono_modem *modem)
g_free(data);
}
+static void dbus_hw_reply_properties(struct dbus_hw *hw)
+{
+ struct sim7100_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);
+
+ ofono_dbus_dict_append(&dbus_dict, "Voltage", DBUS_TYPE_INT32,
+ &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;
+ const char *voltage;
+ double volts = 0.0;
+
+ 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;
+
+ if (!g_at_result_iter_next_unquoted_string(&iter, &voltage))
+ goto error;
+
+ if (sscanf(voltage, "%lfV", &volts) == 1) {
+ hw->voltage = (int)(volts * 1000);
+ DBG("%s = %d mV\n", voltage, hw->voltage);
+ } else {
+ DBG("Failed to parse voltage\n");
+ 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 sim7100_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->at, "AT+CBC", cbc_prefix, cbc_cb, hw, NULL))
+ return __ofono_error_failed(msg);
+
+ hw->msg = dbus_message_ref(msg);
+
+ return NULL;
+}
+
+static void voltage_handle(struct ofono_modem *modem,
+ enum sim7100_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;
+
+ DBG("%p", modem);
+
+ switch (event) {
+ case LOW_POWER_DOWN:
+ name = "PowerDown";
+ reason = "voltagelow";
+ break;
+ case LOW_POWER_WARNING:
+ name = "PowerWarning";
+ reason = "voltagelow";
+ break;
+ case HIGH_POWER_WARNING:
+ name = "PowerWarning";
+ reason = "voltagehigh";
+ break;
+ case HIGH_POWER_DOWN:
+ name = "PowerDown";
+ reason = "voltagehigh";
+ break;
+ default:
+ return;
+ }
+
+ signal = dbus_message_new_signal(path, dbus_hw_interface, name);
+ if (!signal)
+ return;
+
+ dbus_message_iter_init_append(signal, &iter);
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
+ &reason);
+ g_dbus_send_message(conn, signal);
+}
+
+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 WARNNING POWER DOWN") == 0)
+ voltage_handle(hw->modem, LOW_POWER_DOWN);
+ else if (g_strcmp0(event, "UNDER-VOLTAGE WARNNING") == 0)
+ voltage_handle(hw->modem, LOW_POWER_WARNING);
+ else if (g_strcmp0(event, "OVER-VOLTAGE WARNNING") == 0)
+ voltage_handle(hw->modem, HIGH_POWER_WARNING);
+ else if (g_strcmp0(event, "OVER-VOLTAGE WARNNING POWER DOWN") == 0)
+ voltage_handle(hw->modem, HIGH_POWER_DOWN);
+}
+
+static const GDBusMethodTable dbus_hw_methods[] = {
+ {GDBUS_ASYNC_METHOD("GetProperties",
+ NULL, GDBUS_ARGS({"properties", "a{sv}"}),
+ dbus_hw_get_properties)},
+ {}
+};
+
+static const GDBusSignalTable dbus_hw_signals[] = {
+ {GDBUS_SIGNAL("PowerWarning",
+ GDBUS_ARGS({"reason", "s"}))},
+ {GDBUS_SIGNAL("PowerDown",
+ GDBUS_ARGS({"reason", "s"}))},
+ {}
+};
+
+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();
+ struct sim7100_data *data = ofono_modem_get_data(modem);
+ 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, dbus_hw_signals, NULL,
+ hw, dbus_hw_cleanup)) {
+ ofono_error("Could not register %s interface under %s",
+ dbus_hw_interface, path);
+ l_free(hw);
+ return;
+ }
+
+ g_at_chat_register(data->at, "UNDER-VOLTAGE WARNNING POWER DOWN",
+ power_notify, FALSE, hw, NULL);
+ g_at_chat_register(data->at, "UNDER-VOLTAGE WARNNING",
+ power_notify, FALSE, hw, NULL);
+ g_at_chat_register(data->at, "OVER-VOLTAGE WARNNING",
+ power_notify, FALSE, hw, NULL);
+ g_at_chat_register(data->at, "OVER-VOLTAGE WARNNING POWER DOWN",
+ power_notify, FALSE, hw, NULL);
+
+ ofono_modem_add_interface(modem, dbus_hw_interface);
+}
+
static void ppptim_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct ofono_modem *modem = user_data;
@@ -169,6 +401,39 @@ static void cfun_set_on_cb(gboolean ok, GAtResult *result, gpointer user_data)
ofono_modem_set_powered(modem, TRUE);
}
+static void cvalarm_set_on_cb(gboolean ok, GAtResult *result,
+ gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct sim7100_data *data = ofono_modem_get_data(modem);
+
+ DBG("");
+
+ if (!ok)
+ return;
+
+ dbus_hw_enable(modem);
+
+ /* power up modem */
+ g_at_chat_send(data->at, "AT+CFUN=4", NULL, cfun_set_on_cb, modem,
+ NULL);
+}
+
+static void cpmvt_set_on_cb(gboolean ok, GAtResult *result, gpointer user_data)
+{
+ struct ofono_modem *modem = user_data;
+ struct sim7100_data *data = ofono_modem_get_data(modem);
+
+ DBG("");
+
+ if (!ok)
+ return;
+
+ /* enable under/over voltage warning */
+ g_at_chat_send(data->at, "AT+CVALARM=1", NULL, cvalarm_set_on_cb, modem,
+ NULL);
+}
+
static void cgmm_cb(gboolean ok, GAtResult *result, gpointer user_data)
{
struct ofono_modem *modem = user_data;
@@ -205,14 +470,17 @@ static void cgmm_cb(gboolean ok, GAtResult *result, gpointer user_data)
/* ignore NO CARRIER on the AT channel when disconnecting PPP */
g_at_chat_blacklist_terminator(data->at,
G_AT_CHAT_TERMINATOR_NO_CARRIER);
+ /* enable under/over voltage warning + powerdown */
+ g_at_chat_send(data->at, "AT+CPMVT=1", NULL, cpmvt_set_on_cb,
+ modem, NULL);
break;
default:
+ /* power up modem */
+ g_at_chat_send(data->at, "AT+CFUN=4", NULL, cfun_set_on_cb, modem,
+ NULL);
break;
}
- /* power up modem */
- g_at_chat_send(data->at, "AT+CFUN=4", NULL, cfun_set_on_cb, modem,
- NULL);
}
static void init_cmd_cb(gboolean ok, GAtResult *result, void *user_data)
@@ -317,6 +585,8 @@ static void cfun_set_off_cb(gboolean ok, GAtResult *result, gpointer user_data)
static int sim7100_disable(struct ofono_modem *modem)
{
struct sim7100_data *data = ofono_modem_get_data(modem);
+ DBusConnection *conn = ofono_dbus_get_connection();
+ const char *path = ofono_modem_get_path(modem);
DBG("");
@@ -325,6 +595,14 @@ static int sim7100_disable(struct ofono_modem *modem)
g_at_chat_cancel_all(data->at);
g_at_chat_unregister_all(data->ppp);
g_at_chat_unregister_all(data->at);
+
+ switch (data->model) {
+ case SIMCOM_A7671:
+ case SIMCOM_A7672:
+ if (g_dbus_unregister_interface(conn, path, dbus_hw_interface))
+ ofono_modem_remove_interface(modem, dbus_hw_interface);
+ }
+
g_at_chat_send(data->at, "AT+CFUN=0", NULL, cfun_set_off_cb,
modem, NULL);
--
2.52.0