public inbox for linux-bluetooth@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] adapter: Implement PowerState property
@ 2022-08-25 13:26 Bastien Nocera
  2022-08-25 13:50 ` bluez.test.bot
                   ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Bastien Nocera @ 2022-08-25 13:26 UTC (permalink / raw)
  To: linux-bluetooth

This property should allow any program to show the transitional state,
not just the one that requested the change, and will also show
transitional states that were the results of other system changes, like
rfkill changes.
---

Downstream bug in gnome-bluetooth:
https://gitlab.gnome.org/GNOME/gnome-bluetooth/-/issues/121

Note that this probably doesn't handle multiple, conflicting requests
for power on, or power off. Is there a good way to protect against
that?

 client/main.c       |  1 +
 doc/adapter-api.txt | 14 ++++++++++
 src/adapter.c       | 66 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 81 insertions(+)

diff --git a/client/main.c b/client/main.c
index 19139d15b..ddd97c23c 100644
--- a/client/main.c
+++ b/client/main.c
@@ -981,6 +981,7 @@ static void cmd_show(int argc, char *argv[])
        print_property(adapter->proxy, "Alias");
        print_property(adapter->proxy, "Class");
        print_property(adapter->proxy, "Powered");
+       print_property(adapter->proxy, "PowerState");
        print_property(adapter->proxy, "Discoverable");
        print_property(adapter->proxy, "DiscoverableTimeout");
        print_property(adapter->proxy, "Pairable");
diff --git a/doc/adapter-api.txt b/doc/adapter-api.txt
index 48466ab75..5bdb9c34e 100644
--- a/doc/adapter-api.txt
+++ b/doc/adapter-api.txt
@@ -269,6 +269,20 @@ Properties string Address [readonly]
                        restart or unplugging of the adapter it will reset
                        back to false.
 
+               string PowerState [readonly]
+
+                       The power state of an adapter.
+
+                       The power state will show whether the adapter is
+                       turning off, or turning on, as well as being on
+                       or off.
+
+                       Possible values:
+                               "on" - powered on
+                               "off" - powered off
+                               "turning-on" - transitioning from "off" to "on"
+                               "turning-off" - transitioning from "on" to "off"
+
                boolean Discoverable [readwrite]
 
                        Switch an adapter to discoverable or non-discoverable
diff --git a/src/adapter.c b/src/adapter.c
index ec26aab1a..3b0237708 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -239,6 +239,12 @@ struct btd_adapter_pin_cb_iter {
        /* When the iterator reaches the end, it is NULL and attempt is 0 */
 };
 
+enum {
+       ADAPTER_POWER_STATE_TARGET_NONE = 0,
+       ADAPTER_POWER_STATE_TARGET_OFF,
+       ADAPTER_POWER_STATE_TARGET_ON
+};
+
 struct btd_adapter {
        int ref_count;
 
@@ -252,6 +258,7 @@ struct btd_adapter {
        char *short_name;               /* controller short name */
        uint32_t supported_settings;    /* controller supported settings */
        uint32_t pending_settings;      /* pending controller settings */
+       uint32_t power_state_target;    /* the target power state */
        uint32_t current_settings;      /* current controller settings */
 
        char *path;                     /* adapter object path */
@@ -579,6 +586,8 @@ static void settings_changed(struct btd_adapter *adapter, uint32_t settings)
        if (changed_mask & MGMT_SETTING_POWERED) {
                g_dbus_emit_property_changed(dbus_conn, adapter->path,
                                        ADAPTER_INTERFACE, "Powered");
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "PowerState");
 
                if (adapter->current_settings & MGMT_SETTING_POWERED) {
                        adapter_start(adapter);
@@ -635,6 +644,11 @@ static void new_settings_callback(uint16_t index, uint16_t length,
        if (settings == adapter->current_settings)
                return;
 
+       if ((adapter->current_settings & MGMT_SETTING_POWERED) !=
+           (settings & MGMT_SETTING_POWERED)) {
+               adapter->power_state_target = ADAPTER_POWER_STATE_TARGET_NONE;
+       }
+
        DBG("Settings: 0x%08x", settings);
 
        settings_changed(adapter, settings);
@@ -684,6 +698,11 @@ static bool set_mode(struct btd_adapter *adapter, uint16_t opcode,
        switch (opcode) {
        case MGMT_OP_SET_POWERED:
                setting = MGMT_SETTING_POWERED;
+               adapter->power_state_target = mode ?
+                       ADAPTER_POWER_STATE_TARGET_ON :
+                       ADAPTER_POWER_STATE_TARGET_OFF;
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "PowerState");
                break;
        case MGMT_OP_SET_CONNECTABLE:
                setting = MGMT_SETTING_CONNECTABLE;
@@ -708,6 +727,12 @@ static bool set_mode(struct btd_adapter *adapter, uint16_t opcode,
                                set_mode_complete, adapter, NULL) > 0)
                return true;
 
+       if (setting == MGMT_SETTING_POWERED) {
+               /* cancel the earlier setting */
+               adapter->power_state_target = ADAPTER_POWER_STATE_TARGET_NONE;
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "PowerState");
+       }
        btd_error(adapter->dev_id, "Failed to set mode for index %u",
                                                        adapter->dev_id);
 
@@ -2878,6 +2903,7 @@ static gboolean property_get_mode(struct btd_adapter *adapter,
 struct property_set_data {
        struct btd_adapter *adapter;
        GDBusPendingPropertySet id;
+       uint32_t setting;
 };
 
 static void property_set_mode_complete(uint8_t status, uint16_t length,
@@ -2888,6 +2914,9 @@ static void property_set_mode_complete(uint8_t status, uint16_t length,
 
        DBG("%s (0x%02x)", mgmt_errstr(status), status);
 
+       if (data->setting == MGMT_SETTING_POWERED)
+               adapter->power_state_target = ADAPTER_POWER_STATE_TARGET_NONE;
+
        if (status != MGMT_STATUS_SUCCESS) {
                const char *dbus_err;
 
@@ -3025,6 +3054,15 @@ static void property_set_mode(struct btd_adapter *adapter, uint32_t setting,
 
        data->adapter = adapter;
        data->id = id;
+       data->setting = setting;
+
+       if (setting == MGMT_SETTING_POWERED) {
+               adapter->power_state_target = mode ?
+                       ADAPTER_POWER_STATE_TARGET_ON :
+                       ADAPTER_POWER_STATE_TARGET_OFF;
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "PowerState");
+       }
 
        if (mgmt_send(adapter->mgmt, opcode, adapter->dev_id, len, param,
                        property_set_mode_complete, data, g_free) > 0)
@@ -3062,6 +3100,29 @@ static void property_set_powered(const GDBusPropertyTable *property,
        property_set_mode(adapter, MGMT_SETTING_POWERED, iter, id);
 }
 
+static gboolean property_get_power_state(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       const char *str;
+
+       if (adapter->power_state_target == ADAPTER_POWER_STATE_TARGET_NONE) {
+               if (adapter->current_settings & MGMT_SETTING_POWERED)
+                       str = "on";
+               else
+                       str = "off";
+       } else {
+               if (adapter->power_state_target == ADAPTER_POWER_STATE_TARGET_ON)
+                       str = "turning-on";
+               else
+                       str = "turning-off";
+       }
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
+
+       return TRUE;
+}
+
 static gboolean property_get_discoverable(const GDBusPropertyTable *property,
                                        DBusMessageIter *iter, void *user_data)
 {
@@ -3700,6 +3761,7 @@ static const GDBusPropertyTable adapter_properties[] = {
        { "Alias", "s", property_get_alias, property_set_alias },
        { "Class", "u", property_get_class },
        { "Powered", "b", property_get_powered, property_set_powered },
+       { "PowerState", "s", property_get_power_state },
        { "Discoverable", "b", property_get_discoverable,
                                        property_set_discoverable },
        { "DiscoverableTimeout", "u", property_get_discoverable_timeout,
@@ -5506,6 +5568,8 @@ static void adapter_start(struct btd_adapter *adapter)
 {
        g_dbus_emit_property_changed(dbus_conn, adapter->path,
                                                ADAPTER_INTERFACE, "Powered");
+       g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "PowerState");
 
        DBG("adapter %s has been enabled", adapter->path);
 
@@ -7249,6 +7313,8 @@ static void adapter_stop(struct btd_adapter *adapter)
 
        g_dbus_emit_property_changed(dbus_conn, adapter->path,
                                                ADAPTER_INTERFACE, "Powered");
+       g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "PowerState");
 
        DBG("adapter %s has been disabled", adapter->path);
 }
-- 
2.37.2


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

end of thread, other threads:[~2022-08-30 17:41 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-08-25 13:26 [PATCH] adapter: Implement PowerState property Bastien Nocera
2022-08-25 13:50 ` bluez.test.bot
2022-08-25 15:30 ` [PATCH] " Bastien Nocera
2022-08-25 23:06   ` Luiz Augusto von Dentz
2022-08-25 23:10     ` Luiz Augusto von Dentz
2022-08-26  9:26       ` Bastien Nocera
2022-08-26  9:25     ` Bastien Nocera
2022-08-26 18:50 ` Luiz Augusto von Dentz
2022-08-29  9:47   ` Bastien Nocera
2022-08-30 16:59     ` Bastien Nocera
2022-08-30 17:35       ` Luiz Augusto von Dentz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox