xref: /openbmc/phosphor-led-sysfs/physical.cpp (revision 9e500aa81b71b8c702808b7b4025c3528d61cc7e)
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 == assert)
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     return;
58 }
59 
60 auto Physical::state(Action value) -> Action
61 {
62     auto current =
63         sdbusplus::xyz::openbmc_project::Led::server::Physical::state();
64 
65     auto requested =
66         sdbusplus::xyz::openbmc_project::Led::server::Physical::state(value);
67 
68     driveLED(current, requested);
69 
70     return value;
71 }
72 
73 void Physical::driveLED(Action current, Action request)
74 {
75     if (current == request)
76     {
77         return;
78     }
79 
80     if (request == Action::On || request == Action::Off)
81     {
82         return stableStateOperation(request);
83     }
84 
85     assert(request == Action::Blink);
86     blinkOperation();
87 }
88 
89 void Physical::stableStateOperation(Action action)
90 {
91     auto value = (action == Action::On) ? assert : DEASSERT;
92 
93     led.setTrigger("none");
94     led.setBrightness(value);
95     return;
96 }
97 
98 void Physical::blinkOperation()
99 {
100     auto dutyOn = this->dutyOn();
101 
102     /*
103       The configuration of the trigger type must precede the configuration of
104       the trigger type properties. From the kernel documentation:
105       "You can change triggers in a similar manner to the way an IO scheduler
106       is chosen (via /sys/class/leds/<device>/trigger). Trigger specific
107       parameters can appear in /sys/class/leds/<device> once a given trigger is
108       selected."
109       Refer:
110       https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/leds/leds-class.txt?h=v5.2#n26
111     */
112     led.setTrigger("timer");
113     // Convert percent duty to milliseconds for sysfs interface
114     auto factor = this->period() / 100.0;
115     led.setDelayOn(dutyOn * factor);
116     led.setDelayOff((100 - dutyOn) * factor);
117 
118     return;
119 }
120 
121 /** @brief set led color property in DBus*/
122 void Physical::setLedColor(const std::string& color)
123 {
124     static const std::string prefix =
125         "xyz.openbmc_project.Led.Physical.Palette.";
126     if (!color.length())
127         return;
128     std::string tmp = color;
129     tmp[0] = toupper(tmp[0]);
130     try
131     {
132         auto palette = convertPaletteFromString(prefix + tmp);
133         setPropertyByName("Color", palette);
134     }
135     catch (const sdbusplus::exception::InvalidEnumString&)
136     {
137         // if color var contains invalid color,
138         // Color property will have default value
139     }
140 }
141 
142 } // namespace led
143 } // namespace phosphor
144