blob: 8220f96090215655e1a4a9923c9d9ecef0b3b078 [file] [log] [blame]
George Liuc777bef2020-11-23 17:04:21 +08001#include "lamptest.hpp"
2
George Liu87fd11c2020-11-23 16:40:14 +08003#include <phosphor-logging/log.hpp>
4
George Liuc777bef2020-11-23 17:04:21 +08005namespace phosphor
6{
7namespace led
8{
9
George Liub6151622020-11-23 18:16:18 +080010using namespace phosphor::logging;
George Liu82150322021-03-03 17:13:13 +080011using Json = nlohmann::json;
George Liub6151622020-11-23 18:16:18 +080012
13bool LampTest::processLEDUpdates(const Manager::group& ledsAssert,
14 const Manager::group& ledsDeAssert)
15{
16 // If the physical LED status is updated during the lamp test, it should be
17 // saved to Queue, and the queue will be processed after the lamp test is
18 // stopped.
19 if (isLampTestRunning)
20 {
George Liu82150322021-03-03 17:13:13 +080021 // Physical LEDs will be updated during lamp test
22 for (const auto& it : ledsDeAssert)
23 {
24 std::string path = std::string(PHY_LED_PATH) + it.name;
25 auto iter = std::find_if(
26 forceUpdateLEDs.begin(), forceUpdateLEDs.end(),
27 [&path](const auto& name) { return name == path; });
28
29 if (iter != forceUpdateLEDs.end())
30 {
31 manager.drivePhysicalLED(path, Layout::Action::Off, it.dutyOn,
32 it.period);
33 }
34 }
35
36 for (const auto& it : ledsAssert)
37 {
38 std::string path = std::string(PHY_LED_PATH) + it.name;
39 auto iter = std::find_if(
40 forceUpdateLEDs.begin(), forceUpdateLEDs.end(),
41 [&path](const auto& name) { return name == path; });
42
43 if (iter != forceUpdateLEDs.end())
44 {
45 manager.drivePhysicalLED(path, it.action, it.dutyOn, it.period);
46 }
47 }
48
George Liub6151622020-11-23 18:16:18 +080049 updatedLEDsDuringLampTest.emplace(
50 std::make_pair(ledsAssert, ledsDeAssert));
51 return true;
52 }
53 return false;
54}
55
George Liuc777bef2020-11-23 17:04:21 +080056void LampTest::stop()
57{
George Liub6151622020-11-23 18:16:18 +080058 if (!isLampTestRunning)
59 {
60 return;
61 }
62
George Liuc777bef2020-11-23 17:04:21 +080063 timer.setEnabled(false);
George Liu87fd11c2020-11-23 16:40:14 +080064
George Liuce4d1c52021-01-25 11:32:37 +080065 // Stop host lamp test
66 doHostLampTest(false);
67
George Liu87fd11c2020-11-23 16:40:14 +080068 // Set all the Physical action to Off
69 for (const auto& path : physicalLEDPaths)
70 {
George Liu82150322021-03-03 17:13:13 +080071 auto iter =
72 std::find_if(skipUpdateLEDs.begin(), skipUpdateLEDs.end(),
73 [&path](const auto& skip) { return skip == path; });
74
75 if (iter != skipUpdateLEDs.end())
76 {
77 // Skip update physical path
78 continue;
79 }
80
George Liu87fd11c2020-11-23 16:40:14 +080081 manager.drivePhysicalLED(path, Layout::Action::Off, 0, 0);
82 }
George Liub6151622020-11-23 18:16:18 +080083
84 isLampTestRunning = false;
85 restorePhysicalLedStates();
86}
87
88Layout::Action LampTest::getActionFromString(const std::string& str)
89{
90 Layout::Action action = Layout::Off;
91
92 if (str == "xyz.openbmc_project.Led.Physical.Action.On")
93 {
94 action = Layout::On;
95 }
96 else if (str == "xyz.openbmc_project.Led.Physical.Action.Blink")
97 {
98 action = Layout::Blink;
99 }
100
101 return action;
102}
103
104void LampTest::storePhysicalLEDsStates()
105{
106 physicalLEDStatesPriorToLampTest.clear();
107
108 for (const auto& path : physicalLEDPaths)
109 {
George Liu82150322021-03-03 17:13:13 +0800110 auto iter = std::find_if(
111 skipUpdateLEDs.begin(), skipUpdateLEDs.end(),
112 [&path](const auto& skipLed) { return skipLed == path; });
113
114 if (iter != skipUpdateLEDs.end())
115 {
116 // Physical LEDs will be skipped
117 continue;
118 }
119
George Liub6151622020-11-23 18:16:18 +0800120 // Reverse intercept path, Get the name of each member of physical led
121 // e.g: path = /xyz/openbmc_project/led/physical/front_fan
122 // name = front_fan
123 sdbusplus::message::object_path object_path(path);
124 auto name = object_path.filename();
125 if (name.empty())
126 {
127 log<level::ERR>(
128 "Failed to get the name of member of physical LED path",
129 entry("PATH=%s", path.c_str()), entry("NAME=%s", name.c_str()));
130 continue;
131 }
132
133 std::string state{};
134 uint16_t period{};
135 uint8_t dutyOn{};
136 try
137 {
138 auto properties = dBusHandler.getAllProperties(path, PHY_LED_IFACE);
139
140 state = std::get<std::string>(properties["State"]);
141 period = std::get<uint16_t>(properties["Period"]);
142 dutyOn = std::get<uint8_t>(properties["DutyOn"]);
143 }
144 catch (const sdbusplus::exception::SdBusError& e)
145 {
146 log<level::ERR>("Failed to get All properties",
147 entry("ERROR=%s", e.what()),
148 entry("PATH=%s", path.c_str()));
149 continue;
150 }
151
152 phosphor::led::Layout::Action action = getActionFromString(state);
153 if (action != phosphor::led::Layout::Off)
154 {
155 phosphor::led::Layout::LedAction ledAction{
156 name, action, dutyOn, period, phosphor::led::Layout::On};
157 physicalLEDStatesPriorToLampTest.emplace(ledAction);
158 }
159 }
George Liuc777bef2020-11-23 17:04:21 +0800160}
161
162void LampTest::start()
163{
George Liub6151622020-11-23 18:16:18 +0800164 if (isLampTestRunning)
165 {
166 // reset the timer and then return
167 timer.restart(std::chrono::seconds(LAMP_TEST_TIMEOUT_IN_SECS));
168 return;
169 }
170
George Liu87fd11c2020-11-23 16:40:14 +0800171 // Get paths of all the Physical LED objects
172 physicalLEDPaths = dBusHandler.getSubTreePaths(PHY_LED_PATH, PHY_LED_IFACE);
173
George Liub6151622020-11-23 18:16:18 +0800174 // Get physical LEDs states before lamp test
175 storePhysicalLEDsStates();
176
George Liuc777bef2020-11-23 17:04:21 +0800177 // restart lamp test, it contains initiate or reset the timer.
178 timer.restart(std::chrono::seconds(LAMP_TEST_TIMEOUT_IN_SECS));
George Liub6151622020-11-23 18:16:18 +0800179 isLampTestRunning = true;
George Liu87fd11c2020-11-23 16:40:14 +0800180
George Liuce4d1c52021-01-25 11:32:37 +0800181 // Notify PHYP to start the lamp test
182 doHostLampTest(true);
183
George Liu87fd11c2020-11-23 16:40:14 +0800184 // Set all the Physical action to On for lamp test
185 for (const auto& path : physicalLEDPaths)
186 {
George Liu82150322021-03-03 17:13:13 +0800187 auto iter =
188 std::find_if(skipUpdateLEDs.begin(), skipUpdateLEDs.end(),
189 [&path](const auto& skip) { return skip == path; });
190
191 if (iter != skipUpdateLEDs.end())
192 {
193 // Skip update physical path
194 continue;
195 }
196
George Liu87fd11c2020-11-23 16:40:14 +0800197 manager.drivePhysicalLED(path, Layout::Action::On, 0, 0);
198 }
George Liuc777bef2020-11-23 17:04:21 +0800199}
200
201void LampTest::timeOutHandler()
202{
203 // set the Asserted property of lamp test to false
George Liu87fd11c2020-11-23 16:40:14 +0800204 if (!groupObj)
205 {
206 log<level::ERR>("the Group object is nullptr");
207 throw std::runtime_error("the Group object is nullptr");
208 }
209
210 groupObj->asserted(false);
George Liuc777bef2020-11-23 17:04:21 +0800211}
212
George Liu87fd11c2020-11-23 16:40:14 +0800213void LampTest::requestHandler(Group* group, bool value)
George Liuc777bef2020-11-23 17:04:21 +0800214{
George Liu87fd11c2020-11-23 16:40:14 +0800215 if (groupObj == NULL)
216 {
217 groupObj = std::move(group);
218 }
219
George Liuc777bef2020-11-23 17:04:21 +0800220 if (value)
221 {
222 start();
223 }
224 else
225 {
226 stop();
227 }
228}
229
George Liub6151622020-11-23 18:16:18 +0800230void LampTest::restorePhysicalLedStates()
231{
232 // restore physical LEDs states before lamp test
George Liu82150322021-03-03 17:13:13 +0800233 Manager::group ledsDeAssert{};
234 manager.driveLEDs(physicalLEDStatesPriorToLampTest, ledsDeAssert);
George Liub6151622020-11-23 18:16:18 +0800235 physicalLEDStatesPriorToLampTest.clear();
236
237 // restore physical LEDs states during lamp test
238 while (!updatedLEDsDuringLampTest.empty())
239 {
240 auto& [ledsAssert, ledsDeAssert] = updatedLEDsDuringLampTest.front();
241 manager.driveLEDs(ledsAssert, ledsDeAssert);
242 updatedLEDsDuringLampTest.pop();
243 }
244}
245
George Liuce4d1c52021-01-25 11:32:37 +0800246void LampTest::doHostLampTest(bool value)
247{
248 try
249 {
250 PropertyValue assertedValue{value};
251 dBusHandler.setProperty(HOST_LAMP_TEST_OBJECT,
252 "xyz.openbmc_project.Led.Group", "Asserted",
253 assertedValue);
254 }
255 catch (const sdbusplus::exception::SdBusError& e)
256 {
257 log<level::ERR>("Failed to set Asserted property",
258 entry("ERROR=%s", e.what()),
259 entry("PATH=%s", HOST_LAMP_TEST_OBJECT));
260 }
261}
262
George Liu82150322021-03-03 17:13:13 +0800263void LampTest::getPhysicalLEDNamesFromJson(const fs::path& path)
264{
265 if (!fs::exists(path) || fs::is_empty(path))
266 {
267 log<level::INFO>("The file does not exist or is empty",
268 entry("FILE_PATH=%s", path.c_str()));
269 return;
270 }
271
272 try
273 {
274 std::ifstream jsonFile(path);
275 auto json = Json::parse(jsonFile);
276
277 // define the default JSON as empty
278 const std::vector<std::string> empty{};
279 auto forceLEDs = json.value("forceLEDs", empty);
280 for (auto& member : forceLEDs)
281 {
282 forceUpdateLEDs.push_back(PHY_LED_PATH + member);
283 }
284
285 auto skipLEDs = json.value("skipLEDs", empty);
286 for (auto& member : skipLEDs)
287 {
288 skipUpdateLEDs.push_back(PHY_LED_PATH + member);
289 }
290 }
291 catch (const std::exception& e)
292 {
293 log<level::ERR>("Failed to parse config file",
294 entry("ERROR=%s", e.what()),
295 entry("FILE_PATH=%s", path.c_str()));
296 }
297 return;
298}
299
George Liuc777bef2020-11-23 17:04:21 +0800300} // namespace led
301} // namespace phosphor