hostSelector_switch: add support polling mode
Task Description:
Add support for polling mode to periodically sample the group GPIO
selector inputs and update the HostSelector interface’s Position
property on D-Bus.
Motivation:
-Some platforms expose the host-selector via a CPLD as GPIO inputs
without edge interrupts.
-Polling ensures all position changes are detected reliably.
Design:
- Enabled polling through the 'polling_mode' and 'polling_interval_ms'
options in JSON configuration.
- Introduced pollTimerHandler to periodically check GPIO states
and update the internal host selector position.
Tested:
journalctl -xeu xyz.openbmc_project.Chassis.Buttons.service -f
Jul 31 00:06:47 bmc buttons[629]: Start Phosphor buttons service...
Jul 31 00:06:47 bmc buttons[629]: Started polling mode: 2000ms
Jul 31 00:06:49 bmc buttons[629]: Host selector position updated to 0
Jul 31 00:06:53 bmc systemd[1]: Started Phosphor Buttons.
Jul 31 00:13:50 bmc buttons[629]: Host selector position updated to 1
Jul 31 00:13:52 bmc buttons[629]: Host selector position updated to 2
Jul 31 00:13:54 bmc buttons[629]: Host selector position updated to 3
Jul 31 00:14:00 bmc buttons[629]: Host selector position updated to 4
Jul 31 00:14:04 bmc buttons[629]: Host selector position updated to 5
Jul 31 00:14:10 bmc buttons[629]: Host selector position updated to 6
Jul 31 00:14:14 bmc buttons[629]: Host selector position updated to 7
Jul 31 00:14:16 bmc buttons[629]: Host selector position updated to 8
Jul 31 00:14:20 bmc buttons[629]: Host selector position updated to 0
Change-Id: I8b95d773191f1af03b747f9eeb33494da9878bc8
Signed-off-by: Liora Guo <liora.guo.wiwynn@gmail.com>
diff --git a/README.md b/README.md
index 9e2d5b6..8b63513 100644
--- a/README.md
+++ b/README.md
@@ -143,6 +143,19 @@
the value read from the host selector gpios is mapped to the respective host
number.
+**Optional: Polling Configuration** Some platforms expose the host selector via
+a CPLD as GPIO inputs without edge-triggered interrupt support (e.g., no edge
+detection on GPIOs). In such situations, software-based polling mode can be
+enabled using the following optional fields in the JSON configuration:
+
+- **polling_mode** : Set to `true` to enable polling mode.
+- **polling_interval_ms** (optional): Polling interval in milliseconds. Defaults
+ to `1000` ms if not specified.
+
+### Config Example
+
+#### A.Interrupt example
+
Example : The value of "7" derived from the 4 host select gpio lines are mapped
to host position 1.
@@ -192,6 +205,54 @@
}
```
+#### B.Polling example
+
+```json
+{
+ "name": "HOST_SELECTOR",
+ "polling_mode": true,
+ "polling_interval_ms": 3000,
+ "group_gpio_config": [
+ {
+ "name": "host_select_sel_0",
+ "num": 2340,
+ "direction": "in",
+ "polarity": "active_low"
+ },
+ {
+ "name": "host_select_sel_1",
+ "num": 2341,
+ "direction": "in",
+ "polarity": "active_low"
+ },
+ {
+ "name": "host_select_sel_2",
+ "num": 2342,
+ "direction": "in",
+ "polarity": "active_low"
+ },
+ {
+ "name": "host_select_sel_3",
+ "num": 2343,
+ "direction": "in",
+ "polarity": "active_low"
+ }
+ ],
+ "max_position": 8,
+ "host_selector_map": {
+ "0": 0,
+ "1": 1,
+ "2": 2,
+ "3": 3,
+ "4": 4,
+ "5": 5,
+ "6": 6,
+ "7": 7,
+ "8": 8
+ }
+}
+```
+
### Host selector cpld config example
There are also some systems that get the host selector selection from the CPLD,
diff --git a/inc/hostSelector_switch.hpp b/inc/hostSelector_switch.hpp
index 04f80bb..24947ea 100644
--- a/inc/hostSelector_switch.hpp
+++ b/inc/hostSelector_switch.hpp
@@ -11,9 +11,17 @@
#include <nlohmann/json.hpp>
#include <phosphor-logging/elog-errors.hpp>
+#include <sdeventplus/event.hpp>
+#include <sdeventplus/utility/timer.hpp>
+#include <chrono>
#include <fstream>
#include <iostream>
+#include <optional>
+
+using sdeventplus::ClockId;
+using sdeventplus::Event;
+using Timer = sdeventplus::utility::Timer<ClockId::Monotonic>;
static constexpr auto HOST_SELECTOR = "HOST_SELECTOR";
@@ -66,10 +74,15 @@
void setInitialHostSelectorValue(void);
void setHostSelectorValue(int fd, GpioState state);
char getValueFromFd(int fd);
+ void pollGpioState();
+
+ private:
+ std::optional<Timer> pollTimer;
protected:
size_t hostSelectorPosition = 0;
size_t gpioLineCount;
+ size_t previousPos = INVALID_INDEX;
// map of read Host selector switch value and corresponding host number
// value.
diff --git a/src/hostSelector_switch.cpp b/src/hostSelector_switch.cpp
index c398e35..567f338 100644
--- a/src/hostSelector_switch.cpp
+++ b/src/hostSelector_switch.cpp
@@ -1,6 +1,8 @@
#include "hostSelector_switch.hpp"
+#include "gpio.hpp"
+
#include <error.h>
#include <phosphor-logging/lg2.hpp>
@@ -87,6 +89,19 @@
getFormFactorType(), "ERROR", e.what());
}
+ if (config.extraJsonInfo.value("polling_mode", false))
+ {
+ // If polling mode is enabled, set up a timer to poll the GPIO state
+ int intervalMs =
+ config.extraJsonInfo.value("polling_interval_ms", 1000);
+ auto event = Event::get_default();
+ pollTimer.emplace(
+ event, [this](Timer&) { pollGpioState(); },
+ std::chrono::milliseconds(intervalMs));
+ pollTimer->setEnabled(true);
+ lg2::info("Started polling mode: {MS}ms", "MS", intervalMs);
+ }
+
if (hsPosMapped != INVALID_INDEX)
{
position(hsPosMapped, true);
@@ -152,3 +167,23 @@
position(hsPosMapped);
}
}
+
+void HostSelector::pollGpioState()
+{
+ for (const auto& gpioInfo : config.gpios)
+ {
+ GpioState state = getGpioState(gpioInfo.fd, gpioInfo.polarity);
+ setHostSelectorValue(gpioInfo.fd, state);
+ lg2::debug("GPIO {NUM} state is {STATE}", "NUM", gpioInfo.number,
+ "STATE", state);
+ }
+
+ size_t currentPos = getMappedHSConfig(hostSelectorPosition);
+
+ if (currentPos != INVALID_INDEX && currentPos != previousPos)
+ {
+ position(currentPos);
+ previousPos = currentPos;
+ lg2::info("Host selector position updated to {POS}", "POS", currentPos);
+ }
+}