Add OCP debug card host selector button interface
A new button interface class definition is added for handling OCP
debug card host selector button events.
In case of the button release event, The host selector property is
increased up to the max host position.
Design : https://gerrit.openbmc-project.xyz/c/openbmc/docs/+/45544
Signed-off-by: Naveen Moses <naveen.mosess@hcl.com>
Change-Id: Iec8fabb00d1daa10f587981a9c77df8a62e3c373
diff --git a/inc/button_handler.hpp b/inc/button_handler.hpp
index 5723cf7..819a433 100644
--- a/inc/button_handler.hpp
+++ b/inc/button_handler.hpp
@@ -83,6 +83,17 @@
void resetReleased(sdbusplus::message_t& msg);
/**
+ * @brief The handler for a OCP debug card host selector button press
+ *
+ * In multi host system increases host position by 1 up to max host
+ * position.
+ *
+ * @param[in] msg - sdbusplus message from signal
+ */
+
+ void debugHostSelectorReleased(sdbusplus::message::message& msg);
+
+ /**
* @brief Checks if system is powered on
*
* @return true if powered on, false else
@@ -105,7 +116,14 @@
*/
size_t getHostSelectorValue();
+ /**
+ * @brief increases the host selector position property
+ * by 1 upto max host selector position
+ *
+ * @return void
+ */
+ void increaseHostSelectorPosition();
/**
* @brief checks if the system has multi host
* based on the host selector property availability
@@ -146,6 +164,11 @@
* @brief Matches on the reset button released signal
*/
std::unique_ptr<sdbusplus::bus::match_t> resetButtonReleased;
+
+ /**
+ * @brief Matches on the ocp debug host selector button released signal
+ */
+ std::unique_ptr<sdbusplus::bus::match_t> debugHSButtonReleased;
};
} // namespace button
diff --git a/inc/debugHostSelector_button.hpp b/inc/debugHostSelector_button.hpp
new file mode 100644
index 0000000..bdd9dfa
--- /dev/null
+++ b/inc/debugHostSelector_button.hpp
@@ -0,0 +1,57 @@
+
+#pragma once
+#include "config.h"
+
+#include "button_factory.hpp"
+#include "button_interface.hpp"
+#include "common.hpp"
+#include "gpio.hpp"
+#include "xyz/openbmc_project/Chassis/Buttons/Button/server.hpp"
+#include "xyz/openbmc_project/Chassis/Common/error.hpp"
+
+#include <unistd.h>
+
+#include <phosphor-logging/elog-errors.hpp>
+#include <phosphor-logging/lg2.hpp>
+
+static constexpr std::string_view DEBUG_SELECTOR_BUTTON =
+ "DEBUG_SELECTOR_BUTTON";
+
+class DebugHostSelector final :
+ public sdbusplus::server::object_t<
+ sdbusplus::xyz::openbmc_project::Chassis::Buttons::server::Button>,
+ public ButtonIface
+
+{
+ public:
+ DebugHostSelector(sdbusplus::bus::bus& bus, const char* path,
+ EventPtr& event, buttonConfig& buttonCfg) :
+ sdbusplus::server::object_t<
+ sdbusplus::xyz::openbmc_project::Chassis::Buttons::server::Button>(
+ bus, path, action::defer_emit),
+ ButtonIface(bus, event, buttonCfg)
+ {
+ init();
+ emit_object_added();
+ }
+
+ ~DebugHostSelector()
+ {
+ deInit();
+ }
+
+ void simPress() override;
+ void simRelease() override;
+ void simLongPress() override;
+ void handleEvent(sd_event_source* es, int fd, uint32_t revents) override;
+
+ static constexpr std::string_view getFormFactorName()
+ {
+ return DEBUG_SELECTOR_BUTTON;
+ }
+
+ static const char* getDbusObjectPath()
+ {
+ return DBG_HS_DBUS_OBJECT_NAME;
+ }
+};
diff --git a/inc/gpio.hpp b/inc/gpio.hpp
index 6f0a67b..6a63056 100644
--- a/inc/gpio.hpp
+++ b/inc/gpio.hpp
@@ -21,6 +21,12 @@
#include <string>
#include <vector>
+enum class GpioState
+{
+ low,
+ high
+};
+
// this struct has the gpio config for single gpio
struct gpioInfo
{
diff --git a/inc/hostSelector_switch.hpp b/inc/hostSelector_switch.hpp
index dc98739..8030564 100644
--- a/inc/hostSelector_switch.hpp
+++ b/inc/hostSelector_switch.hpp
@@ -20,12 +20,6 @@
static constexpr auto INVALID_INDEX = std::numeric_limits<size_t>::max();
-enum class GpioState
-{
- low,
- high
-};
-
class HostSelector final :
public sdbusplus::server::object_t<
sdbusplus::xyz::openbmc_project::Chassis::Buttons::server::
diff --git a/meson.build b/meson.build
index cd23767..8b726f4 100644
--- a/meson.build
+++ b/meson.build
@@ -10,14 +10,23 @@
)
conf_data = configuration_data()
-conf_data.set_quoted('POWER_DBUS_OBJECT_NAME', '/xyz/openbmc_project/Chassis/Buttons/Power0')
-conf_data.set_quoted('RESET_DBUS_OBJECT_NAME', '/xyz/openbmc_project/Chassis/Buttons/Reset0')
-conf_data.set_quoted('ID_DBUS_OBJECT_NAME', '/xyz/openbmc_project/Chassis/Buttons/ID0')
-conf_data.set_quoted('HS_DBUS_OBJECT_NAME', '/xyz/openbmc_project/Chassis/Buttons/HostSelector')
+conf_data.set_quoted('POWER_DBUS_OBJECT_NAME',
+ '/xyz/openbmc_project/Chassis/Buttons/Power0')
+conf_data.set_quoted('RESET_DBUS_OBJECT_NAME',
+ '/xyz/openbmc_project/Chassis/Buttons/Reset0')
+conf_data.set_quoted('ID_DBUS_OBJECT_NAME',
+ '/xyz/openbmc_project/Chassis/Buttons/ID0')
+conf_data.set_quoted('HS_DBUS_OBJECT_NAME',
+ '/xyz/openbmc_project/Chassis/Buttons/HostSelector')
+conf_data.set_quoted('DBG_HS_DBUS_OBJECT_NAME',
+ '/xyz/openbmc_project/Chassis/Buttons/DebugHostSelector')
conf_data.set_quoted('GPIO_BASE_LABEL_NAME', '1e780000.gpio')
-conf_data.set_quoted('CHASSIS_STATE_OBJECT_NAME', '/xyz/openbmc_project/state/chassis')
-conf_data.set_quoted('CHASSISSYSTEM_STATE_OBJECT_NAME', '/xyz/openbmc_project/state/chassis_system')
-conf_data.set_quoted('HOST_STATE_OBJECT_NAME', '/xyz/openbmc_project/state/host')
+conf_data.set_quoted('CHASSIS_STATE_OBJECT_NAME',
+ '/xyz/openbmc_project/state/chassis')
+conf_data.set_quoted('CHASSISSYSTEM_STATE_OBJECT_NAME',
+ '/xyz/openbmc_project/state/chassis_system')
+conf_data.set_quoted('HOST_STATE_OBJECT_NAME',
+ '/xyz/openbmc_project/state/host')
conf_data.set_quoted('ID_LED_GROUP', get_option('id-led-group'))
conf_data.set('LONG_PRESS_TIME_MS', get_option('long-press-time-ms'))
@@ -53,6 +62,7 @@
sources_buttons = [
'src/gpio.cpp',
'src/hostSelector_switch.cpp',
+ 'src/debugHostSelector_button.cpp',
'src/id_button.cpp',
'src/main.cpp',
'src/power_button.cpp',
diff --git a/src/button_handler.cpp b/src/button_handler.cpp
index 72d2f65..054f642 100644
--- a/src/button_handler.cpp
+++ b/src/button_handler.cpp
@@ -23,7 +23,7 @@
constexpr auto hostSelectorIface =
"xyz.openbmc_project.Chassis.Buttons.HostSelector";
constexpr auto debugHostSelectorIface =
- "xyz.openbmc_project.Chassis.Buttons.DebugHostSelector";
+ "xyz.openbmc_project.Chassis.Buttons.Button";
constexpr auto propertyIface = "org.freedesktop.DBus.Properties";
constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper";
@@ -98,6 +98,25 @@
{
// The button wasn't implemented
}
+ try
+ {
+ if (!getService(DBG_HS_DBUS_OBJECT_NAME, debugHostSelectorIface)
+ .empty())
+ {
+ lg2::info("Registering debug host selector button handler");
+ debugHSButtonReleased = std::make_unique<sdbusplus::bus::match_t>(
+ bus,
+ sdbusRule::type::signal() + sdbusRule::member("Released") +
+ sdbusRule::path(DBG_HS_DBUS_OBJECT_NAME) +
+ sdbusRule::interface(debugHostSelectorIface),
+ std::bind(std::mem_fn(&Handler::debugHostSelectorReleased),
+ this, std::placeholders::_1));
+ }
+ }
+ catch (const sdbusplus::exception::exception& e)
+ {
+ // The button wasn't implemented
+ }
}
bool Handler::isMultiHost()
{
@@ -123,7 +142,7 @@
if (HSService.empty())
{
- lg2::info("Host Selector dbus object not available");
+ lg2::info("Host selector dbus object not available");
throw std::invalid_argument("Host selector dbus object not available");
}
@@ -142,7 +161,7 @@
}
catch (const sdbusplus::exception_t& e)
{
- lg2::error("Error reading Host selector Position: {ERROR}", "ERROR", e);
+ lg2::error("Error reading host selector position: {ERROR}", "ERROR", e);
throw;
}
}
@@ -175,7 +194,7 @@
if (isMultiHostSystem)
{
hostNumber = getHostSelectorValue();
- lg2::info("Multi host system detected : {POSITION}", "POSITION",
+ lg2::info("Multi-host system detected : {POSITION}", "POSITION",
hostNumber);
}
@@ -183,10 +202,10 @@
// ignore power and reset button events if BMC is selected.
if (isMultiHostSystem && (hostNumber == BMC_POSITION) &&
- (powerEventType != PowerEvent::longPowerPressed))
+ (powerEventType != PowerEvent::longPowerReleased))
{
lg2::info(
- "handlePowerEvent : BMC selected on multihost system. ignoring power and reset button events...");
+ "handlePowerEvent : BMC selected on multi-host system. ignoring power and reset button events...");
return;
}
@@ -204,11 +223,11 @@
{
transition = Host::Transition::Off;
}
- lg2::info("handlePowerEvent : handle power button press ");
+ lg2::info("handlePowerEvent : Handle power button press ");
break;
}
- case PowerEvent::longPowerPressed:
+ case PowerEvent::longPowerReleased:
{
dbusIfaceName = chassisIface;
transitionName = "RequestedPowerTransition";
@@ -351,5 +370,60 @@
"ERROR", e);
}
}
+
+void Handler::increaseHostSelectorPosition()
+{
+ try
+ {
+ auto HSService = getService(HS_DBUS_OBJECT_NAME, hostSelectorIface);
+
+ if (HSService.empty())
+ {
+ lg2::error("Host selector service not available");
+ return;
+ }
+
+ auto method =
+ bus.new_method_call(HSService.c_str(), HS_DBUS_OBJECT_NAME,
+ phosphor::button::propertyIface, "GetAll");
+ method.append(phosphor::button::hostSelectorIface);
+ auto result = bus.call(method);
+ std::unordered_map<std::string, std::variant<size_t>> properties;
+ result.read(properties);
+
+ auto maxPosition = std::get<size_t>(properties.at("MaxPosition"));
+ auto position = std::get<size_t>(properties.at("Position"));
+
+ std::variant<size_t> HSPositionVariant =
+ (position < maxPosition) ? (position + 1) : 0;
+
+ method = bus.new_method_call(HSService.c_str(), HS_DBUS_OBJECT_NAME,
+ phosphor::button::propertyIface, "Set");
+ method.append(phosphor::button::hostSelectorIface, "Position");
+
+ method.append(HSPositionVariant);
+ result = bus.call(method);
+ }
+ catch (const sdbusplus::exception::exception& e)
+ {
+ lg2::error("Error modifying host selector position : {ERROR}", "ERROR",
+ e);
+ }
+}
+
+void Handler::debugHostSelectorReleased(sdbusplus::message::message& /* msg */)
+{
+ try
+ {
+ increaseHostSelectorPosition();
+ }
+ catch (const sdbusplus::exception::exception& e)
+ {
+ lg2::error(
+ "Failed power process debug host selector button press : {ERROR}",
+ "ERROR", e);
+ }
+}
+
} // namespace button
} // namespace phosphor
diff --git a/src/debugHostSelector_button.cpp b/src/debugHostSelector_button.cpp
new file mode 100644
index 0000000..6f078f2
--- /dev/null
+++ b/src/debugHostSelector_button.cpp
@@ -0,0 +1,66 @@
+#include "debugHostSelector_button.hpp"
+// add the button iface class to registry
+static ButtonIFRegister<DebugHostSelector> buttonRegister;
+using namespace phosphor::logging;
+
+void DebugHostSelector::simPress()
+{
+ pressed();
+}
+
+void DebugHostSelector::simRelease()
+{
+ released();
+}
+
+void DebugHostSelector::simLongPress()
+{
+ pressedLong();
+}
+
+/**
+ * @brief This method is called from sd-event provided callback function
+ * callbackHandler if platform specific event handling is needed then a
+ * derived class instance with its specific event handling logic along with
+ * init() function can be created to override the default event handling
+ */
+
+void DebugHostSelector::handleEvent(sd_event_source* /* es */, int fd,
+ uint32_t /* revents*/)
+{
+ int n = -1;
+ char buf = '0';
+
+ n = ::lseek(fd, 0, SEEK_SET);
+
+ if (n < 0)
+ {
+ lg2::error("GPIO fd lseek error! : {FORM_FACTOR_TYPE}",
+ "FORM_FACTOR_TYPE", getFormFactorType());
+ return;
+ }
+
+ n = ::read(fd, &buf, sizeof(buf));
+ if (n < 0)
+ {
+ lg2::error("GPIO fd read error! : {FORM_FACTOR_TYPE}",
+ "FORM_FACTOR_TYPE", getFormFactorType());
+ throw sdbusplus::xyz::openbmc_project::Chassis::Common::Error::
+ IOError();
+ }
+
+ if (buf == '0')
+ {
+ lg2::info("Button pressed : {FORM_FACTOR_TYPE}", "FORM_FACTOR_TYPE",
+ getFormFactorType());
+ // emit pressed signal
+ pressed();
+ }
+ else
+ {
+ lg2::info("Button released{FORM_FACTOR_TYPE}", "FORM_FACTOR_TYPE",
+ getFormFactorType());
+ // emit released signal
+ released();
+ }
+}
\ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
index 90c189d..16ae7b0 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -19,6 +19,7 @@
#include <nlohmann/json.hpp>
#include <phosphor-logging/elog-errors.hpp>
+#include <phosphor-logging/lg2.hpp>
#include <fstream>
static constexpr auto gpioDefFile = "/etc/default/obmc/gpio/gpio_defs.json";
@@ -29,15 +30,13 @@
{
int ret = 0;
- phosphor::logging::log<phosphor::logging::level::INFO>(
- "Start Phosphor buttons service...");
+ lg2::info("Start Phosphor buttons service...");
sd_event* event = nullptr;
ret = sd_event_default(&event);
if (ret < 0)
{
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "Error creating a default sd_event handler");
+ lg2::error("Error creating a default sd_event handler");
return ret;
}
EventPtr eventP{event};
@@ -68,6 +67,8 @@
/* The folloing code checks if the gpio config read
from json file is single gpio config or group gpio config,
based on that further data is processed. */
+ lg2::debug("Found button config : {FORM_FACTOR_NAME}",
+ "FORM_FACTOR_NAME", buttonCfg.formFactorName);
if (gpioConfig.contains("group_gpio_config"))
{
const auto& groupGpio = gpioConfig["group_gpio_config"];
@@ -105,9 +106,8 @@
ret = sd_event_loop(eventP.get());
if (ret < 0)
{
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "Error occurred during the sd_event_loop",
- phosphor::logging::entry("RET=%d", ret));
+ lg2::error("Error occurred during the sd_event_loop : {RESULT}",
+ "RESULT", ret);
}
}
catch (const std::exception& e)