diff options
-rw-r--r-- | argument.cpp | 3 | ||||
-rw-r--r-- | physical.cpp | 115 | ||||
-rw-r--r-- | physical.hpp | 118 |
3 files changed, 222 insertions, 14 deletions
diff --git a/argument.cpp b/argument.cpp index 7b70fe0..b70a0dd 100644 --- a/argument.cpp +++ b/argument.cpp @@ -73,7 +73,8 @@ void ArgumentParser::usage(char** argv) std::cerr << "Usage: " << argv[0] << " [options]" << std::endl; std::cerr << "Options:" << std::endl; std::cerr << " --help Print this menu" << std::endl; - std::cerr << " --path=<path> sysfs path like /sys/class/leds" + std::cerr << " --path=<path> absolute path of LED in sysfs; like"; + std::cerr << " /sys/class/leds/<name>" << std::endl; } } // namespace led diff --git a/physical.cpp b/physical.cpp index 31fc1ee..38c69b0 100644 --- a/physical.cpp +++ b/physical.cpp @@ -25,32 +25,129 @@ 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. - // Implementation in the next patchset. + + 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 { - // Set the base class's state to actuals since the getter - // operation is handled there. - auto action = sdbusplus::xyz::openbmc_project::Led::server + // 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(); + driveLED(current, requested); - return action; + return value; } /** @brief apply action on the LED */ -void Physical::driveLED() +void Physical::driveLED(Action current, Action request) { - // Replace with actual code. - std::cout << " Drive LED STUB :: \n"; + 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; } diff --git a/physical.hpp b/physical.hpp index 0eac97b..c24d3f2 100644 --- a/physical.hpp +++ b/physical.hpp @@ -1,6 +1,7 @@ #pragma once #include <string> +#include <fstream> #include <sdbusplus/bus.hpp> #include <sdbusplus/server/object.hpp> #include "xyz/openbmc_project/Led/Physical/server.hpp" @@ -8,6 +9,42 @@ namespace phosphor { namespace led { +/** @brief Acts as input and output file for the current LED power state. + * Write "0" to trigger a LED OFF operation. + * Write "255" to trigger a LED ON operation. + * To know the current power state of the LED, a read on this + * would give either 0 or 255 indicating if the LED is currently + * Off / On AT THAT moment. + * Example: /sys/class/leds/myled/brightness + */ +constexpr auto BRIGHTNESS = "/brightness"; + +/** @brief Assert LED by writing 255 */ +constexpr auto ASSERT = "255"; + +/** @brief De-assert by writing "0" */ +constexpr auto DEASSERT = "0"; + +/** @brief Write "timer" to this file telling the driver that + * the intended operation is BLINK. When the value "timer" is written to + * the file, 2 more files get auto generated and are named "delay_on" and + * "delay_off" + * To move away from blinking, write "none" + * Example: /sys/class/leds/myled/trigger + */ +constexpr auto BLINKCTRL = "/trigger"; + +/** @brief write number of milliseconds that the LED needs to be ON + * while blinking. Default is 500 by the driver. + * Example: /sys/class/leds/myled/delay_on + */ +constexpr auto DELAYON = "/delay_on"; + +/** @brief Write number of milliseconds that the LED needs to be OFF + * while blinking. Default is 500 by the driver. + * Example: /sys/class/leds/myled/delay_off + */ +constexpr auto DELAYOFF = "/delay_off"; /** @class Physical * @brief Responsible for applying actions on a particular physical LED @@ -62,18 +99,91 @@ class Physical : public sdbusplus::server::object::object< */ std::string path; + /** @brief Frequency range that the LED can operate on. + * Will be removed when frequency is put into interface + */ + uint32_t frequency; + + /** @brief Brightness described above */ + std::string brightCtrl; + + /** @brief BlinkCtrl described above */ + std::string blinkCtrl; + + /** @brief delay_on described above */ + std::string delayOnCtrl; + + /** @brief delay_ff described above */ + std::string delayOffCtrl; + + /** @brief reads sysfs and then setsup the parameteres accordingly + * + * @return None + */ + void setInitialState(); + /** @brief Applies the user triggered action on the LED * by writing to sysfs * + * @param [in] current - Current state of LED + * @param [in] request - Requested state + * * @return None */ - void driveLED(void); + void driveLED(Action current, Action request); - /** @brief reads sysfs and then setsup the parameteres accordingly + /** @brief Sets the LED to either ON or OFF state + * + * @param [in] action - Requested action. Could be OFF or ON + * @return None + */ + void stableStateOperation(Action action); + + /** @brief Sets the LED to BLINKING + * + * @return None + */ + void blinkOperation(); + + /** @brief Generic file writer. + * There are files like "brightness", "trigger" , "delay_on" and + * "delay_off" that will tell what the LED driver needs to do. * - * @return Status or exception thrown + * @param[in] filename - Name of file to be written + * @param[in] data - Data to be written to + * @return - None */ - void setInitialState(void); + template <typename T> + auto write(const std::string& fileName, T&& data) + { + if(std::ifstream(fileName)) + { + std::ofstream file(fileName, std::ios::out); + file << data; + file.close(); + } + return; + } + + /** @brief Generic file reader. + * There are files like "brightness", "trigger" , "delay_on" and + * "delay_off" that will tell what the LED driver needs to do. + * + * @param[in] filename - Name of file to be read + * @return - File content + */ + template <typename T> + T read(const std::string& fileName) + { + T data = T(); + if(std::ifstream(fileName)) + { + std::ifstream file(fileName, std::ios::in); + file >> data; + file.close(); + } + return data; + } }; } // namespace led |