xref: /openbmc/phosphor-led-sysfs/physical.cpp (revision 305e3b76d46da517dc8be02e31f17a6c5e83d04e)
1 /**
2  * Copyright © 2016,2018 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "physical.hpp"
18 
19 #include <cassert>
20 #include <cstdlib>
21 #include <iostream>
22 #include <string>
23 namespace phosphor
24 {
25 namespace led
26 {
27 
28 /** @brief Populates key parameters */
29 void Physical::setInitialState()
30 {
31     assert = led.getMaxBrightness();
32     auto trigger = led.getTrigger();
33     if (trigger == "timer")
34     {
35         // LED is blinking. Get the on and off delays and derive percent duty
36         auto delayOn = led.getDelayOn();
37         uint16_t periodMs = delayOn + led.getDelayOff();
38         auto percentScale = periodMs / 100;
39         this->dutyOn(delayOn / percentScale);
40         this->period(periodMs);
41     }
42     else
43     {
44         // Cache current LED state
45         auto brightness = led.getBrightness();
46         if (brightness != 0U && assert != 0U)
47         {
48             sdbusplus::xyz::openbmc_project::Led::server::Physical::state(
49                 Action::On);
50         }
51         else
52         {
53             sdbusplus::xyz::openbmc_project::Led::server::Physical::state(
54                 Action::Off);
55         }
56     }
57 }
58 
59 auto Physical::state() const -> Action
60 {
61     return sdbusplus::xyz::openbmc_project::Led::server::Physical::state();
62 }
63 
64 auto Physical::state(Action value) -> Action
65 {
66     auto current =
67         sdbusplus::xyz::openbmc_project::Led::server::Physical::state();
68 
69     auto requested =
70         sdbusplus::xyz::openbmc_project::Led::server::Physical::state(value);
71 
72     driveLED(current, requested);
73 
74     return value;
75 }
76 
77 void Physical::driveLED(Action current, Action request)
78 {
79     if (current == request)
80     {
81         return;
82     }
83 
84     if (request == Action::On || request == Action::Off)
85     {
86         return stableStateOperation(request);
87     }
88 
89     assert(request == Action::Blink);
90     blinkOperation();
91 }
92 
93 void Physical::stableStateOperation(Action action)
94 {
95     auto value = (action == Action::On) ? assert : DEASSERT;
96 
97     led.setTrigger("none");
98     led.setBrightness(value);
99 }
100 
101 void Physical::blinkOperation()
102 {
103     auto dutyOn = this->dutyOn();
104 
105     /*
106       The configuration of the trigger type must precede the configuration of
107       the trigger type properties. From the kernel documentation:
108       "You can change triggers in a similar manner to the way an IO scheduler
109       is chosen (via /sys/class/leds/<device>/trigger). Trigger specific
110       parameters can appear in /sys/class/leds/<device> once a given trigger is
111       selected."
112       Refer:
113       https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/leds/leds-class.txt?h=v5.2#n26
114     */
115     led.setTrigger("timer");
116     // Convert percent duty to milliseconds for sysfs interface
117     auto factor = this->period() / 100.0;
118     led.setDelayOn(dutyOn * factor);
119     led.setDelayOff((100 - dutyOn) * factor);
120 }
121 
122 /** @brief set led color property in DBus*/
123 void Physical::setLedColor(const std::string& color)
124 {
125     static const std::string prefix =
126         "xyz.openbmc_project.Led.Physical.Palette.";
127     if (!color.length())
128         return;
129     std::string tmp = color;
130     tmp[0] = toupper(tmp[0]);
131     try
132     {
133         auto palette = convertPaletteFromString(prefix + tmp);
134         setPropertyByName("Color", palette);
135     }
136     catch (const sdbusplus::exception::InvalidEnumString&)
137     {
138         // if color var contains invalid color,
139         // Color property will have default value
140     }
141 }
142 
143 } // namespace led
144 } // namespace phosphor
145