blob: f7f9e901b90af1fdaa848a52d8b8039f564007d0 [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;
Sunny Srivastavae3515c72022-10-15 12:45:40 -050013static const fs::path lampTestIndicator =
14 "/var/lib/phosphor-led-manager/lamp-test-running";
George Liub6151622020-11-23 18:16:18 +080015
Patrick Williams158b2c12022-03-17 05:57:44 -050016bool LampTest::processLEDUpdates(const ActionSet& ledsAssert,
17 const ActionSet& ledsDeAssert)
George Liub6151622020-11-23 18:16:18 +080018{
19 // If the physical LED status is updated during the lamp test, it should be
20 // saved to Queue, and the queue will be processed after the lamp test is
21 // stopped.
22 if (isLampTestRunning)
23 {
George Liu82150322021-03-03 17:13:13 +080024 // Physical LEDs will be updated during lamp test
25 for (const auto& it : ledsDeAssert)
26 {
George Liu1f0b7152023-07-18 09:24:34 +080027 std::string path = std::string(phyLedPath) + it.name;
George Liu82150322021-03-03 17:13:13 +080028 auto iter = std::find_if(
29 forceUpdateLEDs.begin(), forceUpdateLEDs.end(),
30 [&path](const auto& name) { return name == path; });
31
32 if (iter != forceUpdateLEDs.end())
33 {
George Liuf0592552024-08-23 09:46:17 +080034 phosphor::led::Manager::drivePhysicalLED(
35 path, Layout::Action::Off, it.dutyOn, it.period);
George Liu82150322021-03-03 17:13:13 +080036 }
37 }
38
39 for (const auto& it : ledsAssert)
40 {
George Liu1f0b7152023-07-18 09:24:34 +080041 std::string path = std::string(phyLedPath) + it.name;
George Liu82150322021-03-03 17:13:13 +080042 auto iter = std::find_if(
43 forceUpdateLEDs.begin(), forceUpdateLEDs.end(),
44 [&path](const auto& name) { return name == path; });
45
46 if (iter != forceUpdateLEDs.end())
47 {
George Liuf0592552024-08-23 09:46:17 +080048 phosphor::led::Manager::drivePhysicalLED(path, it.action,
49 it.dutyOn, it.period);
George Liu82150322021-03-03 17:13:13 +080050 }
51 }
52
George Liufcf08102024-08-22 17:00:05 +080053 updatedLEDsDuringLampTest.emplace(ledsAssert, ledsDeAssert);
George Liub6151622020-11-23 18:16:18 +080054 return true;
55 }
56 return false;
57}
58
George Liuc777bef2020-11-23 17:04:21 +080059void LampTest::stop()
60{
George Liub6151622020-11-23 18:16:18 +080061 if (!isLampTestRunning)
62 {
63 return;
64 }
65
George Liuc777bef2020-11-23 17:04:21 +080066 timer.setEnabled(false);
George Liu87fd11c2020-11-23 16:40:14 +080067
George Liuce4d1c52021-01-25 11:32:37 +080068 // Stop host lamp test
69 doHostLampTest(false);
70
George Liu87fd11c2020-11-23 16:40:14 +080071 // Set all the Physical action to Off
72 for (const auto& path : physicalLEDPaths)
73 {
George Liu82150322021-03-03 17:13:13 +080074 auto iter =
75 std::find_if(skipUpdateLEDs.begin(), skipUpdateLEDs.end(),
76 [&path](const auto& skip) { return skip == path; });
77
78 if (iter != skipUpdateLEDs.end())
79 {
80 // Skip update physical path
81 continue;
82 }
83
George Liuf0592552024-08-23 09:46:17 +080084 phosphor::led::Manager::drivePhysicalLED(path, Layout::Action::Off, 0,
85 0);
George Liu87fd11c2020-11-23 16:40:14 +080086 }
George Liub6151622020-11-23 18:16:18 +080087
Sunny Srivastavae3515c72022-10-15 12:45:40 -050088 if (std::filesystem::exists(lampTestIndicator))
89 {
90 if (!std::filesystem::remove(lampTestIndicator))
91 {
92 lg2::error(
93 "Error removing lamp test on indicator file after lamp test execution.");
94 }
95 }
96
George Liub6151622020-11-23 18:16:18 +080097 isLampTestRunning = false;
98 restorePhysicalLedStates();
99}
100
101Layout::Action LampTest::getActionFromString(const std::string& str)
102{
Patrick Williamsed80e882022-03-17 05:03:51 -0500103 Layout::Action action = Layout::Action::Off;
George Liub6151622020-11-23 18:16:18 +0800104
105 if (str == "xyz.openbmc_project.Led.Physical.Action.On")
106 {
Patrick Williamsed80e882022-03-17 05:03:51 -0500107 action = Layout::Action::On;
George Liub6151622020-11-23 18:16:18 +0800108 }
109 else if (str == "xyz.openbmc_project.Led.Physical.Action.Blink")
110 {
Patrick Williamsed80e882022-03-17 05:03:51 -0500111 action = Layout::Action::Blink;
George Liub6151622020-11-23 18:16:18 +0800112 }
113
114 return action;
115}
116
117void LampTest::storePhysicalLEDsStates()
118{
119 physicalLEDStatesPriorToLampTest.clear();
120
121 for (const auto& path : physicalLEDPaths)
122 {
Patrick Williams605600e2023-10-20 11:18:04 -0500123 auto iter = std::find_if(
124 skipUpdateLEDs.begin(), skipUpdateLEDs.end(),
125 [&path](const auto& skipLed) { return skipLed == path; });
George Liu82150322021-03-03 17:13:13 +0800126
127 if (iter != skipUpdateLEDs.end())
128 {
129 // Physical LEDs will be skipped
130 continue;
131 }
132
George Liub6151622020-11-23 18:16:18 +0800133 // Reverse intercept path, Get the name of each member of physical led
134 // e.g: path = /xyz/openbmc_project/led/physical/front_fan
135 // name = front_fan
136 sdbusplus::message::object_path object_path(path);
137 auto name = object_path.filename();
138 if (name.empty())
139 {
George Liue9fb5c62021-07-01 14:05:32 +0800140 lg2::error(
141 "Failed to get the name of member of physical LED path, PATH = {PATH}, NAME = {NAME}",
142 "PATH", path, "NAME", name);
George Liub6151622020-11-23 18:16:18 +0800143 continue;
144 }
145
146 std::string state{};
147 uint16_t period{};
148 uint8_t dutyOn{};
149 try
150 {
George Liuf0592552024-08-23 09:46:17 +0800151 auto properties =
152 phosphor::led::utils::DBusHandler::getAllProperties(path,
153 phyLedIntf);
George Liub6151622020-11-23 18:16:18 +0800154
155 state = std::get<std::string>(properties["State"]);
156 period = std::get<uint16_t>(properties["Period"]);
157 dutyOn = std::get<uint8_t>(properties["DutyOn"]);
158 }
Patrick Williams3e073ba2022-07-22 19:26:52 -0500159 catch (const sdbusplus::exception_t& e)
George Liub6151622020-11-23 18:16:18 +0800160 {
George Liue9fb5c62021-07-01 14:05:32 +0800161 lg2::error(
162 "Failed to get All properties, ERROR = {ERROR}, PATH = {PATH}",
163 "ERROR", e, "PATH", path);
George Liub6151622020-11-23 18:16:18 +0800164 continue;
165 }
166
167 phosphor::led::Layout::Action action = getActionFromString(state);
Patrick Williamsed80e882022-03-17 05:03:51 -0500168 if (action != phosphor::led::Layout::Action::Off)
George Liub6151622020-11-23 18:16:18 +0800169 {
170 phosphor::led::Layout::LedAction ledAction{
Patrick Williamsed80e882022-03-17 05:03:51 -0500171 name, action, dutyOn, period,
172 phosphor::led::Layout::Action::On};
George Liub6151622020-11-23 18:16:18 +0800173 physicalLEDStatesPriorToLampTest.emplace(ledAction);
174 }
175 }
George Liuc777bef2020-11-23 17:04:21 +0800176}
177
178void LampTest::start()
179{
George Liub6151622020-11-23 18:16:18 +0800180 if (isLampTestRunning)
181 {
182 // reset the timer and then return
183 timer.restart(std::chrono::seconds(LAMP_TEST_TIMEOUT_IN_SECS));
PriyangaRamasamy180090c2022-10-10 10:50:52 +0530184
185 // Notify host to reset the timer
186 doHostLampTest(true);
187
George Liub6151622020-11-23 18:16:18 +0800188 return;
189 }
190
George Liu87fd11c2020-11-23 16:40:14 +0800191 // Get paths of all the Physical LED objects
George Liu785f5052023-07-18 09:38:43 +0800192 try
193 {
George Liuf0592552024-08-23 09:46:17 +0800194 physicalLEDPaths = phosphor::led::utils::DBusHandler::getSubTreePaths(
195 phyLedPath, phyLedIntf);
George Liu785f5052023-07-18 09:38:43 +0800196 }
197 catch (const sdbusplus::exception_t& e)
198 {
199 lg2::error(
200 "Failed to call the SubTreePaths method: {ERROR}, ledPath: {PATH}, ledInterface: {INTERFACE}",
George Liu1f0b7152023-07-18 09:24:34 +0800201 "ERROR", e, "PATH", phyLedPath, "INTERFACE", phyLedIntf);
George Liu785f5052023-07-18 09:38:43 +0800202 return;
203 }
George Liu87fd11c2020-11-23 16:40:14 +0800204
George Liub6151622020-11-23 18:16:18 +0800205 // Get physical LEDs states before lamp test
206 storePhysicalLEDsStates();
207
George Liuc777bef2020-11-23 17:04:21 +0800208 // restart lamp test, it contains initiate or reset the timer.
209 timer.restart(std::chrono::seconds(LAMP_TEST_TIMEOUT_IN_SECS));
George Liub6151622020-11-23 18:16:18 +0800210 isLampTestRunning = true;
George Liu87fd11c2020-11-23 16:40:14 +0800211
PriyangaRamasamy180090c2022-10-10 10:50:52 +0530212 // Notify host to start the lamp test
George Liuce4d1c52021-01-25 11:32:37 +0800213 doHostLampTest(true);
214
Sunny Srivastavae3515c72022-10-15 12:45:40 -0500215 // Create a file to maintain the state across reboots that Lamp test is on.
216 // This is required as there was a scenario where it has been found that
217 // LEDs remains in "on" state if lamp test is triggered and reboot takes
218 // place.
219 const auto ledDirectory = lampTestIndicator.parent_path();
220
221 if (!fs::exists(ledDirectory))
222 {
223 fs::create_directories(ledDirectory);
224 }
225
George Liu8f538d92024-08-22 15:41:22 +0800226 std::ofstream ofs(lampTestIndicator.c_str());
Sunny Srivastavae3515c72022-10-15 12:45:40 -0500227
George Liu87fd11c2020-11-23 16:40:14 +0800228 // Set all the Physical action to On for lamp test
229 for (const auto& path : physicalLEDPaths)
230 {
George Liu82150322021-03-03 17:13:13 +0800231 auto iter =
232 std::find_if(skipUpdateLEDs.begin(), skipUpdateLEDs.end(),
233 [&path](const auto& skip) { return skip == path; });
234
235 if (iter != skipUpdateLEDs.end())
236 {
237 // Skip update physical path
238 continue;
239 }
240
George Liuf0592552024-08-23 09:46:17 +0800241 phosphor::led::Manager::drivePhysicalLED(path, Layout::Action::On, 0,
242 0);
George Liu87fd11c2020-11-23 16:40:14 +0800243 }
George Liuc777bef2020-11-23 17:04:21 +0800244}
245
246void LampTest::timeOutHandler()
247{
248 // set the Asserted property of lamp test to false
George Liu49875a22024-08-23 08:58:59 +0800249 if (groupObj == nullptr)
George Liu87fd11c2020-11-23 16:40:14 +0800250 {
George Liue9fb5c62021-07-01 14:05:32 +0800251 lg2::error("the Group object is nullptr");
George Liu87fd11c2020-11-23 16:40:14 +0800252 throw std::runtime_error("the Group object is nullptr");
253 }
254
255 groupObj->asserted(false);
George Liuc777bef2020-11-23 17:04:21 +0800256}
257
PriyangaRamasamy180090c2022-10-10 10:50:52 +0530258bool LampTest::requestHandler(Group* group, bool value)
George Liuc777bef2020-11-23 17:04:21 +0800259{
George Liuaaa667f2024-08-22 17:37:51 +0800260 if (groupObj == nullptr)
George Liu87fd11c2020-11-23 16:40:14 +0800261 {
George Liudf3ab7c2024-08-22 19:05:27 +0800262 groupObj = group;
George Liu87fd11c2020-11-23 16:40:14 +0800263 }
264
George Liuc777bef2020-11-23 17:04:21 +0800265 if (value)
266 {
267 start();
PriyangaRamasamy180090c2022-10-10 10:50:52 +0530268
269 // Return true in both cases (F -> T && T -> T)
270 return true;
George Liuc777bef2020-11-23 17:04:21 +0800271 }
272 else
273 {
PriyangaRamasamy180090c2022-10-10 10:50:52 +0530274 if (timer.hasExpired())
275 {
276 stop();
277
278 // Return true as the request to stop the lamptest is handled
279 // successfully.
280 return true;
281 }
282 else if (timer.isEnabled())
283 {
284 lg2::info(
285 "Lamp test is still running. Cannot force stop the lamp test. Asserted is set back to true.");
286
287 // Return false as the request to stop lamptest is not handled as
288 // the lamptest is still running.
289 return false;
290 }
291 return false;
George Liuc777bef2020-11-23 17:04:21 +0800292 }
293}
294
George Liub6151622020-11-23 18:16:18 +0800295void LampTest::restorePhysicalLedStates()
296{
297 // restore physical LEDs states before lamp test
Patrick Williams158b2c12022-03-17 05:57:44 -0500298 ActionSet ledsDeAssert{};
George Liu82150322021-03-03 17:13:13 +0800299 manager.driveLEDs(physicalLEDStatesPriorToLampTest, ledsDeAssert);
George Liub6151622020-11-23 18:16:18 +0800300 physicalLEDStatesPriorToLampTest.clear();
301
302 // restore physical LEDs states during lamp test
303 while (!updatedLEDsDuringLampTest.empty())
304 {
305 auto& [ledsAssert, ledsDeAssert] = updatedLEDsDuringLampTest.front();
306 manager.driveLEDs(ledsAssert, ledsDeAssert);
307 updatedLEDsDuringLampTest.pop();
308 }
309}
310
George Liuce4d1c52021-01-25 11:32:37 +0800311void LampTest::doHostLampTest(bool value)
312{
313 try
314 {
315 PropertyValue assertedValue{value};
George Liuf0592552024-08-23 09:46:17 +0800316 phosphor::led::utils::DBusHandler::setProperty(
317 HOST_LAMP_TEST_OBJECT, "xyz.openbmc_project.Led.Group", "Asserted",
318 assertedValue);
George Liuce4d1c52021-01-25 11:32:37 +0800319 }
Patrick Williams3e073ba2022-07-22 19:26:52 -0500320 catch (const sdbusplus::exception_t& e)
George Liuce4d1c52021-01-25 11:32:37 +0800321 {
George Liue9fb5c62021-07-01 14:05:32 +0800322 lg2::error(
323 "Failed to set Asserted property, ERROR = {ERROR}, PATH = {PATH}",
324 "ERROR", e, "PATH", std::string(HOST_LAMP_TEST_OBJECT));
George Liuce4d1c52021-01-25 11:32:37 +0800325 }
326}
327
George Liu82150322021-03-03 17:13:13 +0800328void LampTest::getPhysicalLEDNamesFromJson(const fs::path& path)
329{
330 if (!fs::exists(path) || fs::is_empty(path))
331 {
George Liue9fb5c62021-07-01 14:05:32 +0800332 lg2::info("The file does not exist or is empty, FILE_PATH = {PATH}",
333 "PATH", path);
George Liu82150322021-03-03 17:13:13 +0800334 return;
335 }
336
337 try
338 {
339 std::ifstream jsonFile(path);
340 auto json = Json::parse(jsonFile);
341
342 // define the default JSON as empty
343 const std::vector<std::string> empty{};
344 auto forceLEDs = json.value("forceLEDs", empty);
George Liuc5e0f312021-12-27 15:54:31 +0800345 std::ranges::transform(forceLEDs, std::back_inserter(forceUpdateLEDs),
George Liu1f0b7152023-07-18 09:24:34 +0800346 [](const auto& i) { return phyLedPath + i; });
George Liu82150322021-03-03 17:13:13 +0800347
348 auto skipLEDs = json.value("skipLEDs", empty);
George Liuc5e0f312021-12-27 15:54:31 +0800349 std::ranges::transform(skipLEDs, std::back_inserter(skipUpdateLEDs),
George Liu1f0b7152023-07-18 09:24:34 +0800350 [](const auto& i) { return phyLedPath + i; });
George Liu82150322021-03-03 17:13:13 +0800351 }
352 catch (const std::exception& e)
353 {
George Liue9fb5c62021-07-01 14:05:32 +0800354 lg2::error(
355 "Failed to parse config file, ERROR = {ERROR}, FILE_PATH = {PATH}",
356 "ERROR", e, "PATH", path);
George Liu82150322021-03-03 17:13:13 +0800357 }
358 return;
359}
Sunny Srivastavae3515c72022-10-15 12:45:40 -0500360
361void LampTest::clearLamps()
362{
363 if (std::filesystem::exists(lampTestIndicator))
364 {
365 // we need to off all the LEDs.
George Liuf0592552024-08-23 09:46:17 +0800366 std::vector<std::string> physicalLedPaths =
367 phosphor::led::utils::DBusHandler::getSubTreePaths(
368 phosphor::led::phyLedPath, phosphor::led::phyLedIntf);
Sunny Srivastavae3515c72022-10-15 12:45:40 -0500369
370 for (const auto& path : physicalLedPaths)
371 {
George Liuf0592552024-08-23 09:46:17 +0800372 phosphor::led::Manager::drivePhysicalLED(
373 path, phosphor::led::Layout::Action::Off, 0, 0);
Sunny Srivastavae3515c72022-10-15 12:45:40 -0500374 }
375
376 // Also remove the lamp test on indicator file.
377 if (!std::filesystem::remove(lampTestIndicator))
378 {
379 lg2::error(
380 "Error removing lamp test on indicator file after lamp test execution.");
381 }
382 }
383}
George Liuc777bef2020-11-23 17:04:21 +0800384} // namespace led
385} // namespace phosphor