Change the ID LED from on to blinking for identify command
The ID LED will be blinking on ipmi identify command,
And will be on/off when ID button is pressed.
Tested:
Pressed on the ID button, the ID LED will be on/off
ipmitool chassis identify 10, the ID LED will be blinking 10 seconds
Change-Id: Ib0bef20e6716096c59e722597fbac25187b4d174
Signed-off-by: Yong Li <yong.b.li@linux.intel.com>
Signed-off-by: Yuan Li <yuan.li@linux.intel.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 93663c0..667c677 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -94,6 +94,7 @@
src/smbioshandler.cpp src/smbiosmdrv2handler.cpp
src/manufacturingcommands.cpp src/bmccontrolservices.cpp
src/bridgingcommands.cpp src/ipmi_to_redfish_hooks.cpp
+ src/chassiscommands.cpp
)
set_target_properties (zinteloemcmds PROPERTIES VERSION "0.1.0")
set_target_properties (zinteloemcmds PROPERTIES SOVERSION "0")
diff --git a/src/chassiscommands.cpp b/src/chassiscommands.cpp
new file mode 100644
index 0000000..72439f7
--- /dev/null
+++ b/src/chassiscommands.cpp
@@ -0,0 +1,217 @@
+/*
+// Copyright (c) 2019 Intel Corporation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+*/
+#include "xyz/openbmc_project/Common/error.hpp"
+
+#include <fstream>
+#include <ipmid/api.hpp>
+#include <ipmid/utils.hpp>
+#include <nlohmann/json.hpp>
+#include <phosphor-logging/elog-errors.hpp>
+#include <regex>
+#include <sdbusplus/timer.hpp>
+
+namespace ipmi
+{
+const static constexpr char *idButtonPath =
+ "/xyz/openbmc_project/chassis/buttons/id";
+const static constexpr char *idButtonInterface =
+ "xyz.openbmc_project.Chassis.Buttons";
+const static constexpr char *idButtonProp = "ButtonPressed";
+
+const static constexpr char *ledService =
+ "xyz.openbmc_project.LED.GroupManager";
+const static constexpr char *ledIDOnObj =
+ "/xyz/openbmc_project/led/groups/enclosure_identify";
+const static constexpr char *ledIDBlinkObj =
+ "/xyz/openbmc_project/led/groups/enclosure_identify_blink";
+const static constexpr char *ledInterface = "xyz.openbmc_project.Led.Group";
+const static constexpr char *ledProp = "Asserted";
+
+constexpr size_t defaultIdentifyTimeOut = 15;
+
+std::unique_ptr<phosphor::Timer> identifyTimer
+ __attribute__((init_priority(101)));
+std::unique_ptr<sdbusplus::bus::match_t> matchPtr
+ __attribute__((init_priority(101)));
+
+static void registerChassisFunctions() __attribute__((constructor));
+
+static ipmi::ServiceCache LEDService(ledInterface, ledIDBlinkObj);
+
+void enclosureIdentifyLed(const char *objName, bool isIdLedOn)
+{
+ auto bus = getSdBus();
+
+ try
+ {
+ std::string service = LEDService.getService(*bus);
+ setDbusProperty(*bus, service, objName, ledInterface, ledProp,
+ isIdLedOn);
+ }
+ catch (const std::exception &e)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "enclosureIdentifyLed: can't set property",
+ phosphor::logging::entry("ERR=%s", e.what()));
+ }
+}
+
+bool getIDState(const char *objName, bool &state)
+{
+ auto bus = getSdBus();
+
+ try
+ {
+ std::string service = LEDService.getService(*bus);
+ ipmi::Value enabled =
+ getDbusProperty(*bus, service, objName, ledInterface, ledProp);
+ state = std::get<bool>(enabled);
+ }
+ catch (sdbusplus::exception::SdBusError &e)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Fail to get property",
+ phosphor::logging::entry("PATH=%s", objName),
+ phosphor::logging::entry("ERROR=%s", e.what()));
+ return false;
+ }
+ return true;
+}
+
+void enclosureIdentifyLedBlinkOff()
+{
+ enclosureIdentifyLed(ledIDBlinkObj, false);
+}
+
+void idButtonPropChanged(sdbusplus::message::message &msg)
+{
+ bool asserted = false;
+ bool buttonPressed = false;
+
+ std::map<std::string, ipmi::Value> props;
+ std::vector<std::string> inval;
+ std::string iface;
+ msg.read(iface, props, inval);
+
+ for (const auto &t : props)
+ {
+ auto key = t.first;
+ auto value = t.second;
+
+ if (key == idButtonProp)
+ {
+ buttonPressed = std::get<bool>(value);
+ }
+ break;
+ }
+
+ if (buttonPressed)
+ {
+ if (identifyTimer->isRunning())
+ {
+ phosphor::logging::log<phosphor::logging::level::INFO>(
+ "ID timer is running");
+ }
+
+ // make sure timer is stopped
+ identifyTimer->stop();
+
+ if (!getIDState(ledIDBlinkObj, asserted))
+ {
+ return;
+ }
+
+ if (asserted)
+ {
+ // LED is blinking, turn off the LED
+ enclosureIdentifyLed(ledIDBlinkObj, false);
+ enclosureIdentifyLed(ledIDOnObj, false);
+ }
+ else
+ {
+ // toggle the IED on/off
+ if (!getIDState(ledIDOnObj, asserted))
+ {
+ return;
+ }
+ enclosureIdentifyLed(ledIDOnObj, !asserted);
+ }
+ }
+}
+
+void createIdentifyTimer()
+{
+ if (!identifyTimer)
+ {
+ identifyTimer =
+ std::make_unique<phosphor::Timer>(enclosureIdentifyLedBlinkOff);
+ }
+}
+
+ipmi::RspType<> ipmiChassisIdentify(std::optional<uint8_t> interval,
+ std::optional<uint8_t> force)
+{
+ uint8_t identifyInterval = interval.value_or(defaultIdentifyTimeOut);
+ bool forceIdentify = force.value_or(0) & 0x01;
+
+ enclosureIdentifyLed(ledIDOnObj, false);
+ identifyTimer->stop();
+
+ if (identifyInterval || forceIdentify)
+ {
+ enclosureIdentifyLed(ledIDBlinkObj, true);
+ if (forceIdentify)
+ {
+ return ipmi::responseSuccess();
+ }
+ // start the timer
+ auto time = std::chrono::duration_cast<std::chrono::microseconds>(
+ std::chrono::seconds(identifyInterval));
+ identifyTimer->start(time);
+ }
+ else
+ {
+ enclosureIdentifyLed(ledIDBlinkObj, false);
+ }
+ return ipmi::responseSuccess();
+}
+
+static void registerChassisFunctions(void)
+{
+ phosphor::logging::log<phosphor::logging::level::INFO>(
+ "Registering Chassis commands");
+
+ createIdentifyTimer();
+
+ if (matchPtr == nullptr)
+ {
+ using namespace sdbusplus::bus::match::rules;
+ auto bus = getSdBus();
+
+ matchPtr = std::make_unique<sdbusplus::bus::match_t>(
+ *bus,
+ sdbusplus::bus::match::rules::propertiesChanged(idButtonPath,
+ idButtonInterface),
+ std::bind(idButtonPropChanged, std::placeholders::_1));
+ }
+
+ // <Chassis Identify>
+ ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnChassis,
+ ipmi::chassis::cmdChassisIdentify,
+ ipmi::Privilege::Operator, ipmiChassisIdentify);
+}
+
+} // namespace ipmi