blob: 38c69b0a669c188d09e6d14c3559c5e9cd5f485b [file] [log] [blame]
/**
* Copyright © 2016 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 <iostream>
#include <string>
#include "physical.hpp"
namespace phosphor
{
namespace led
{
/** @brief Populates key parameters */
void Physical::setInitialState()
{
// Control files in /sys/class/leds/<led-name>
brightCtrl = path + BRIGHTNESS;
blinkCtrl = path + BLINKCTRL;
delayOnCtrl = path + DELAYON;
delayOffCtrl = path + DELAYOFF;
// 1. read /sys/class/leds/name/trigger
// 2. If its 'timer', then its blinking.
// 2.1: On blink, use delay_on and delay_off into dutyOn
// 3. If its 'none', then read brightness. 255 means, its ON, else OFF.
auto trigger = read<std::string>(blinkCtrl);
if (trigger == "timer")
{
// LED is blinking. Get the delay_on and delay_off and compute
// DutyCycle. sfsfs values are in strings. Need to convert 'em over to
// integer.
auto delayOn = std::stoi(read<std::string>(delayOnCtrl));
auto delayOff = std::stoi(read<std::string>(delayOffCtrl));
// Calculate frequency and then percentage ON
frequency = delayOn + delayOff;
auto factor = frequency / 100;
auto dutyOn = delayOn / factor;
// Update.
this->dutyOn(dutyOn);
}
else
{
// This is hardcoded for now. This will be changed to this->frequency()
// when frequency is implemented.
// TODO
frequency = 1000;
// LED is either ON or OFF
auto brightness = read<std::string>(brightCtrl);
if (brightness == std::string(ASSERT))
{
// LED is in Solid ON
sdbusplus::xyz::openbmc_project::Led::server
::Physical::state(Action::On);
}
else
{
// LED is in OFF state
sdbusplus::xyz::openbmc_project::Led::server
::Physical::state(Action::Off);
}
}
return;
}
/** @brief Overloaded State Property Setter function */
auto Physical::state(Action value) -> Action
{
// Obtain current operation
auto current = sdbusplus::xyz::openbmc_project::Led::server
::Physical::state();
// Update requested operation into base class
auto requested = sdbusplus::xyz::openbmc_project::Led::server
::Physical::state(value);
// Apply the action.
driveLED(current, requested);
return value;
}
/** @brief apply action on the LED */
void Physical::driveLED(Action current, Action request)
{
if (current == request)
{
// Best we can do here is ignore.
return;
}
// Transition TO Blinking state
if (request == Action::Blink)
{
return blinkOperation();
}
// Transition TO Stable states.
if(request == Action::On || request == Action::Off)
{
return stableStateOperation(request);
}
return;
}
/** @brief Either TurnON -or- TurnOFF */
void Physical::stableStateOperation(Action action)
{
auto value = (action == Action::On) ? ASSERT : DEASSERT;
// Write "none" to trigger to clear any previous action
write(blinkCtrl, "none");
// And write the current command
write(brightCtrl, value);
return;
}
/** @brief BLINK the LED */
void Physical::blinkOperation()
{
// Get the latest dutyOn that the user requested
auto dutyOn = this->dutyOn();
// Write "timer" to "trigger" file
write(blinkCtrl, "timer");
// Write DutyON. Value in percentage 1_millisecond.
// so 50% input becomes 500. Driver wants string input
auto percentage = frequency / 100;
write(delayOnCtrl, std::to_string(dutyOn * percentage));
// Write DutyOFF. Value in milli seconds so 50% input becomes 500.
write(delayOffCtrl, std::to_string((100 - dutyOn) * percentage));
return;
}
} // namespace led
} // namespace phosphor