blob: 72439f74a27e32b302b7afc5ec9e053ff2c82db1 [file] [log] [blame]
/*
// 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