/** * Copyright © 2016,2018 IBM 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 "physical.hpp" #include #include #include #include namespace phosphor { namespace led { /** @brief Populates key parameters */ void Physical::setInitialState() { assert = led->getMaxBrightness(); auto trigger = led->getTrigger(); if (trigger == "timer") { // LED is blinking. Get the on and off delays and derive percent duty auto delayOn = led->getDelayOn(); uint16_t periodMs = delayOn + led->getDelayOff(); auto percentScale = periodMs / 100; this->dutyOn(delayOn / percentScale); this->period(periodMs); sdbusplus::xyz::openbmc_project::Led::server::Physical::state( Action::Blink); } else { // Cache current LED state auto brightness = led->getBrightness(); if (brightness != 0U && assert != 0U) { sdbusplus::xyz::openbmc_project::Led::server::Physical::state( Action::On); } else { sdbusplus::xyz::openbmc_project::Led::server::Physical::state( Action::Off); } } } auto Physical::state() const -> Action { return sdbusplus::xyz::openbmc_project::Led::server::Physical::state(); } auto Physical::state(Action value) -> Action { auto current = sdbusplus::xyz::openbmc_project::Led::server::Physical::state(); auto requested = sdbusplus::xyz::openbmc_project::Led::server::Physical::state(value); driveLED(current, requested); return value; } void Physical::driveLED(Action current, Action request) { if (current == request) { return; } if (request == Action::On || request == Action::Off) { return stableStateOperation(request); } assert(request == Action::Blink); blinkOperation(); } void Physical::stableStateOperation(Action action) { auto value = (action == Action::On) ? assert : deasserted; led->setTrigger("none"); led->setBrightness(value); } void Physical::blinkOperation() { /* The configuration of the trigger type must precede the configuration of the trigger type properties. From the kernel documentation: "You can change triggers in a similar manner to the way an IO scheduler is chosen (via /sys/class/leds//trigger). Trigger specific parameters can appear in /sys/class/leds/ once a given trigger is selected." Refer: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/leds/leds-class.txt?h=v5.2#n26 */ auto d = static_cast(dutyOn()); if (d > 100) { d = 100; } auto p = static_cast(period()); led->setTrigger("timer"); led->setDelayOn(p * d / 100UL); led->setDelayOff(p * (100UL - d) / 100UL); } /** @brief set led color property in DBus*/ void Physical::setLedColor(const std::string& color) { static const std::string prefix = "xyz.openbmc_project.Led.Physical.Palette."; if (color.empty()) { return; } std::string tmp = color; tmp[0] = static_cast(toupper(tmp[0])); try { auto palette = convertPaletteFromString(prefix + tmp); setPropertyByName("Color", palette); } catch (const sdbusplus::exception::InvalidEnumString&) { // if color var contains invalid color, // Color property will have default value } } } // namespace led } // namespace phosphor