blob: 3dfaaa598255731cc3ac35655a96b04c769e50cd [file] [log] [blame]
George Liuc777bef2020-11-23 17:04:21 +08001#include "lamptest.hpp"
2
George Liue9fb5c62021-07-01 14:05:32 +08003#include <phosphor-logging/lg2.hpp>
George Liu87fd11c2020-11-23 16:40:14 +08004
George Liuc5e0f312021-12-27 15:54:31 +08005#include <algorithm>
6
George Liuc777bef2020-11-23 17:04:21 +08007namespace phosphor
8{
9namespace led
10{
11
George Liu82150322021-03-03 17:13:13 +080012using Json = nlohmann::json;
George Liub6151622020-11-23 18:16:18 +080013
Patrick Williams158b2c12022-03-17 05:57:44 -050014bool LampTest::processLEDUpdates(const ActionSet& ledsAssert,
15 const ActionSet& ledsDeAssert)
George Liub6151622020-11-23 18:16:18 +080016{
17 // If the physical LED status is updated during the lamp test, it should be
18 // saved to Queue, and the queue will be processed after the lamp test is
19 // stopped.
20 if (isLampTestRunning)
21 {
George Liu82150322021-03-03 17:13:13 +080022 // Physical LEDs will be updated during lamp test
23 for (const auto& it : ledsDeAssert)
24 {
George Liu1f0b7152023-07-18 09:24:34 +080025 std::string path = std::string(phyLedPath) + it.name;
George Liu82150322021-03-03 17:13:13 +080026 auto iter = std::find_if(
27 forceUpdateLEDs.begin(), forceUpdateLEDs.end(),
28 [&path](const auto& name) { return name == path; });
29
30 if (iter != forceUpdateLEDs.end())
31 {
32 manager.drivePhysicalLED(path, Layout::Action::Off, it.dutyOn,
33 it.period);
34 }
35 }
36
37 for (const auto& it : ledsAssert)
38 {
George Liu1f0b7152023-07-18 09:24:34 +080039 std::string path = std::string(phyLedPath) + it.name;
George Liu82150322021-03-03 17:13:13 +080040 auto iter = std::find_if(
41 forceUpdateLEDs.begin(), forceUpdateLEDs.end(),
42 [&path](const auto& name) { return name == path; });
43
44 if (iter != forceUpdateLEDs.end())
45 {
46 manager.drivePhysicalLED(path, it.action, it.dutyOn, it.period);
47 }
48 }
49
George Liub6151622020-11-23 18:16:18 +080050 updatedLEDsDuringLampTest.emplace(
51 std::make_pair(ledsAssert, ledsDeAssert));
52 return true;
53 }
54 return false;
55}
56
George Liuc777bef2020-11-23 17:04:21 +080057void LampTest::stop()
58{
George Liub6151622020-11-23 18:16:18 +080059 if (!isLampTestRunning)
60 {
61 return;
62 }
63
George Liuc777bef2020-11-23 17:04:21 +080064 timer.setEnabled(false);
George Liu87fd11c2020-11-23 16:40:14 +080065
George Liuce4d1c52021-01-25 11:32:37 +080066 // Stop host lamp test
67 doHostLampTest(false);
68
George Liu87fd11c2020-11-23 16:40:14 +080069 // Set all the Physical action to Off
70 for (const auto& path : physicalLEDPaths)
71 {
George Liu82150322021-03-03 17:13:13 +080072 auto iter =
73 std::find_if(skipUpdateLEDs.begin(), skipUpdateLEDs.end(),
74 [&path](const auto& skip) { return skip == path; });
75
76 if (iter != skipUpdateLEDs.end())
77 {
78 // Skip update physical path
79 continue;
80 }
81
George Liu87fd11c2020-11-23 16:40:14 +080082 manager.drivePhysicalLED(path, Layout::Action::Off, 0, 0);
83 }
George Liub6151622020-11-23 18:16:18 +080084
85 isLampTestRunning = false;
86 restorePhysicalLedStates();
87}
88
89Layout::Action LampTest::getActionFromString(const std::string& str)
90{
Patrick Williamsed80e882022-03-17 05:03:51 -050091 Layout::Action action = Layout::Action::Off;
George Liub6151622020-11-23 18:16:18 +080092
93 if (str == "xyz.openbmc_project.Led.Physical.Action.On")
94 {
Patrick Williamsed80e882022-03-17 05:03:51 -050095 action = Layout::Action::On;
George Liub6151622020-11-23 18:16:18 +080096 }
97 else if (str == "xyz.openbmc_project.Led.Physical.Action.Blink")
98 {
Patrick Williamsed80e882022-03-17 05:03:51 -050099 action = Layout::Action::Blink;
George Liub6151622020-11-23 18:16:18 +0800100 }
101
102 return action;
103}
104
105void LampTest::storePhysicalLEDsStates()
106{
107 physicalLEDStatesPriorToLampTest.clear();
108
109 for (const auto& path : physicalLEDPaths)
110 {
Patrick Williams605600e2023-10-20 11:18:04 -0500111 auto iter = std::find_if(
112 skipUpdateLEDs.begin(), skipUpdateLEDs.end(),
113 [&path](const auto& skipLed) { return skipLed == path; });
George Liu82150322021-03-03 17:13:13 +0800114
115 if (iter != skipUpdateLEDs.end())
116 {
117 // Physical LEDs will be skipped
118 continue;
119 }
120
George Liub6151622020-11-23 18:16:18 +0800121 // Reverse intercept path, Get the name of each member of physical led
122 // e.g: path = /xyz/openbmc_project/led/physical/front_fan
123 // name = front_fan
124 sdbusplus::message::object_path object_path(path);
125 auto name = object_path.filename();
126 if (name.empty())
127 {
George Liue9fb5c62021-07-01 14:05:32 +0800128 lg2::error(
129 "Failed to get the name of member of physical LED path, PATH = {PATH}, NAME = {NAME}",
130 "PATH", path, "NAME", name);
George Liub6151622020-11-23 18:16:18 +0800131 continue;
132 }
133
134 std::string state{};
135 uint16_t period{};
136 uint8_t dutyOn{};
137 try
138 {
George Liu1f0b7152023-07-18 09:24:34 +0800139 auto properties = dBusHandler.getAllProperties(path, phyLedIntf);
George Liub6151622020-11-23 18:16:18 +0800140
141 state = std::get<std::string>(properties["State"]);
142 period = std::get<uint16_t>(properties["Period"]);
143 dutyOn = std::get<uint8_t>(properties["DutyOn"]);
144 }
Patrick Williams3e073ba2022-07-22 19:26:52 -0500145 catch (const sdbusplus::exception_t& e)
George Liub6151622020-11-23 18:16:18 +0800146 {
George Liue9fb5c62021-07-01 14:05:32 +0800147 lg2::error(
148 "Failed to get All properties, ERROR = {ERROR}, PATH = {PATH}",
149 "ERROR", e, "PATH", path);
George Liub6151622020-11-23 18:16:18 +0800150 continue;
151 }
152
153 phosphor::led::Layout::Action action = getActionFromString(state);
Patrick Williamsed80e882022-03-17 05:03:51 -0500154 if (action != phosphor::led::Layout::Action::Off)
George Liub6151622020-11-23 18:16:18 +0800155 {
156 phosphor::led::Layout::LedAction ledAction{
Patrick Williamsed80e882022-03-17 05:03:51 -0500157 name, action, dutyOn, period,
158 phosphor::led::Layout::Action::On};
George Liub6151622020-11-23 18:16:18 +0800159 physicalLEDStatesPriorToLampTest.emplace(ledAction);
160 }
161 }
George Liuc777bef2020-11-23 17:04:21 +0800162}
163
164void LampTest::start()
165{
George Liub6151622020-11-23 18:16:18 +0800166 if (isLampTestRunning)
167 {
168 // reset the timer and then return
169 timer.restart(std::chrono::seconds(LAMP_TEST_TIMEOUT_IN_SECS));
PriyangaRamasamy180090c2022-10-10 10:50:52 +0530170
171 // Notify host to reset the timer
172 doHostLampTest(true);
173
George Liub6151622020-11-23 18:16:18 +0800174 return;
175 }
176
George Liu87fd11c2020-11-23 16:40:14 +0800177 // Get paths of all the Physical LED objects
George Liu785f5052023-07-18 09:38:43 +0800178 try
179 {
George Liu1f0b7152023-07-18 09:24:34 +0800180 physicalLEDPaths = dBusHandler.getSubTreePaths(phyLedPath, phyLedIntf);
George Liu785f5052023-07-18 09:38:43 +0800181 }
182 catch (const sdbusplus::exception_t& e)
183 {
184 lg2::error(
185 "Failed to call the SubTreePaths method: {ERROR}, ledPath: {PATH}, ledInterface: {INTERFACE}",
George Liu1f0b7152023-07-18 09:24:34 +0800186 "ERROR", e, "PATH", phyLedPath, "INTERFACE", phyLedIntf);
George Liu785f5052023-07-18 09:38:43 +0800187 return;
188 }
George Liu87fd11c2020-11-23 16:40:14 +0800189
George Liub6151622020-11-23 18:16:18 +0800190 // Get physical LEDs states before lamp test
191 storePhysicalLEDsStates();
192
George Liuc777bef2020-11-23 17:04:21 +0800193 // restart lamp test, it contains initiate or reset the timer.
194 timer.restart(std::chrono::seconds(LAMP_TEST_TIMEOUT_IN_SECS));
George Liub6151622020-11-23 18:16:18 +0800195 isLampTestRunning = true;
George Liu87fd11c2020-11-23 16:40:14 +0800196
PriyangaRamasamy180090c2022-10-10 10:50:52 +0530197 // Notify host to start the lamp test
George Liuce4d1c52021-01-25 11:32:37 +0800198 doHostLampTest(true);
199
George Liu87fd11c2020-11-23 16:40:14 +0800200 // Set all the Physical action to On for lamp test
201 for (const auto& path : physicalLEDPaths)
202 {
George Liu82150322021-03-03 17:13:13 +0800203 auto iter =
204 std::find_if(skipUpdateLEDs.begin(), skipUpdateLEDs.end(),
205 [&path](const auto& skip) { return skip == path; });
206
207 if (iter != skipUpdateLEDs.end())
208 {
209 // Skip update physical path
210 continue;
211 }
212
George Liu87fd11c2020-11-23 16:40:14 +0800213 manager.drivePhysicalLED(path, Layout::Action::On, 0, 0);
214 }
George Liuc777bef2020-11-23 17:04:21 +0800215}
216
217void LampTest::timeOutHandler()
218{
219 // set the Asserted property of lamp test to false
George Liu87fd11c2020-11-23 16:40:14 +0800220 if (!groupObj)
221 {
George Liue9fb5c62021-07-01 14:05:32 +0800222 lg2::error("the Group object is nullptr");
George Liu87fd11c2020-11-23 16:40:14 +0800223 throw std::runtime_error("the Group object is nullptr");
224 }
225
226 groupObj->asserted(false);
George Liuc777bef2020-11-23 17:04:21 +0800227}
228
PriyangaRamasamy180090c2022-10-10 10:50:52 +0530229bool LampTest::requestHandler(Group* group, bool value)
George Liuc777bef2020-11-23 17:04:21 +0800230{
George Liu87fd11c2020-11-23 16:40:14 +0800231 if (groupObj == NULL)
232 {
233 groupObj = std::move(group);
234 }
235
George Liuc777bef2020-11-23 17:04:21 +0800236 if (value)
237 {
238 start();
PriyangaRamasamy180090c2022-10-10 10:50:52 +0530239
240 // Return true in both cases (F -> T && T -> T)
241 return true;
George Liuc777bef2020-11-23 17:04:21 +0800242 }
243 else
244 {
PriyangaRamasamy180090c2022-10-10 10:50:52 +0530245 if (timer.hasExpired())
246 {
247 stop();
248
249 // Return true as the request to stop the lamptest is handled
250 // successfully.
251 return true;
252 }
253 else if (timer.isEnabled())
254 {
255 lg2::info(
256 "Lamp test is still running. Cannot force stop the lamp test. Asserted is set back to true.");
257
258 // Return false as the request to stop lamptest is not handled as
259 // the lamptest is still running.
260 return false;
261 }
262 return false;
George Liuc777bef2020-11-23 17:04:21 +0800263 }
264}
265
George Liub6151622020-11-23 18:16:18 +0800266void LampTest::restorePhysicalLedStates()
267{
268 // restore physical LEDs states before lamp test
Patrick Williams158b2c12022-03-17 05:57:44 -0500269 ActionSet ledsDeAssert{};
George Liu82150322021-03-03 17:13:13 +0800270 manager.driveLEDs(physicalLEDStatesPriorToLampTest, ledsDeAssert);
George Liub6151622020-11-23 18:16:18 +0800271 physicalLEDStatesPriorToLampTest.clear();
272
273 // restore physical LEDs states during lamp test
274 while (!updatedLEDsDuringLampTest.empty())
275 {
276 auto& [ledsAssert, ledsDeAssert] = updatedLEDsDuringLampTest.front();
277 manager.driveLEDs(ledsAssert, ledsDeAssert);
278 updatedLEDsDuringLampTest.pop();
279 }
280}
281
George Liuce4d1c52021-01-25 11:32:37 +0800282void LampTest::doHostLampTest(bool value)
283{
284 try
285 {
286 PropertyValue assertedValue{value};
287 dBusHandler.setProperty(HOST_LAMP_TEST_OBJECT,
288 "xyz.openbmc_project.Led.Group", "Asserted",
289 assertedValue);
290 }
Patrick Williams3e073ba2022-07-22 19:26:52 -0500291 catch (const sdbusplus::exception_t& e)
George Liuce4d1c52021-01-25 11:32:37 +0800292 {
George Liue9fb5c62021-07-01 14:05:32 +0800293 lg2::error(
294 "Failed to set Asserted property, ERROR = {ERROR}, PATH = {PATH}",
295 "ERROR", e, "PATH", std::string(HOST_LAMP_TEST_OBJECT));
George Liuce4d1c52021-01-25 11:32:37 +0800296 }
297}
298
George Liu82150322021-03-03 17:13:13 +0800299void LampTest::getPhysicalLEDNamesFromJson(const fs::path& path)
300{
301 if (!fs::exists(path) || fs::is_empty(path))
302 {
George Liue9fb5c62021-07-01 14:05:32 +0800303 lg2::info("The file does not exist or is empty, FILE_PATH = {PATH}",
304 "PATH", path);
George Liu82150322021-03-03 17:13:13 +0800305 return;
306 }
307
308 try
309 {
310 std::ifstream jsonFile(path);
311 auto json = Json::parse(jsonFile);
312
313 // define the default JSON as empty
314 const std::vector<std::string> empty{};
315 auto forceLEDs = json.value("forceLEDs", empty);
George Liuc5e0f312021-12-27 15:54:31 +0800316 std::ranges::transform(forceLEDs, std::back_inserter(forceUpdateLEDs),
George Liu1f0b7152023-07-18 09:24:34 +0800317 [](const auto& i) { return phyLedPath + i; });
George Liu82150322021-03-03 17:13:13 +0800318
319 auto skipLEDs = json.value("skipLEDs", empty);
George Liuc5e0f312021-12-27 15:54:31 +0800320 std::ranges::transform(skipLEDs, std::back_inserter(skipUpdateLEDs),
George Liu1f0b7152023-07-18 09:24:34 +0800321 [](const auto& i) { return phyLedPath + i; });
George Liu82150322021-03-03 17:13:13 +0800322 }
323 catch (const std::exception& e)
324 {
George Liue9fb5c62021-07-01 14:05:32 +0800325 lg2::error(
326 "Failed to parse config file, ERROR = {ERROR}, FILE_PATH = {PATH}",
327 "ERROR", e, "PATH", path);
George Liu82150322021-03-03 17:13:13 +0800328 }
329 return;
330}
George Liuc777bef2020-11-23 17:04:21 +0800331} // namespace led
332} // namespace phosphor