blob: d90fc8a5aa003f40948b86e76094e09bc643fba3 [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 {
25 std::string path = std::string(PHY_LED_PATH) + it.name;
26 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 {
39 std::string path = std::string(PHY_LED_PATH) + it.name;
40 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 Williams857da382023-05-10 07:50:20 -0500111 auto iter = std::find_if(skipUpdateLEDs.begin(), skipUpdateLEDs.end(),
112 [&path](const auto& skipLed) {
113 return skipLed == path;
114 });
George Liu82150322021-03-03 17:13:13 +0800115
116 if (iter != skipUpdateLEDs.end())
117 {
118 // Physical LEDs will be skipped
119 continue;
120 }
121
George Liub6151622020-11-23 18:16:18 +0800122 // Reverse intercept path, Get the name of each member of physical led
123 // e.g: path = /xyz/openbmc_project/led/physical/front_fan
124 // name = front_fan
125 sdbusplus::message::object_path object_path(path);
126 auto name = object_path.filename();
127 if (name.empty())
128 {
George Liue9fb5c62021-07-01 14:05:32 +0800129 lg2::error(
130 "Failed to get the name of member of physical LED path, PATH = {PATH}, NAME = {NAME}",
131 "PATH", path, "NAME", name);
George Liub6151622020-11-23 18:16:18 +0800132 continue;
133 }
134
135 std::string state{};
136 uint16_t period{};
137 uint8_t dutyOn{};
138 try
139 {
140 auto properties = dBusHandler.getAllProperties(path, PHY_LED_IFACE);
141
142 state = std::get<std::string>(properties["State"]);
143 period = std::get<uint16_t>(properties["Period"]);
144 dutyOn = std::get<uint8_t>(properties["DutyOn"]);
145 }
Patrick Williams3e073ba2022-07-22 19:26:52 -0500146 catch (const sdbusplus::exception_t& e)
George Liub6151622020-11-23 18:16:18 +0800147 {
George Liue9fb5c62021-07-01 14:05:32 +0800148 lg2::error(
149 "Failed to get All properties, ERROR = {ERROR}, PATH = {PATH}",
150 "ERROR", e, "PATH", path);
George Liub6151622020-11-23 18:16:18 +0800151 continue;
152 }
153
154 phosphor::led::Layout::Action action = getActionFromString(state);
Patrick Williamsed80e882022-03-17 05:03:51 -0500155 if (action != phosphor::led::Layout::Action::Off)
George Liub6151622020-11-23 18:16:18 +0800156 {
157 phosphor::led::Layout::LedAction ledAction{
Patrick Williamsed80e882022-03-17 05:03:51 -0500158 name, action, dutyOn, period,
159 phosphor::led::Layout::Action::On};
George Liub6151622020-11-23 18:16:18 +0800160 physicalLEDStatesPriorToLampTest.emplace(ledAction);
161 }
162 }
George Liuc777bef2020-11-23 17:04:21 +0800163}
164
165void LampTest::start()
166{
George Liub6151622020-11-23 18:16:18 +0800167 if (isLampTestRunning)
168 {
169 // reset the timer and then return
170 timer.restart(std::chrono::seconds(LAMP_TEST_TIMEOUT_IN_SECS));
171 return;
172 }
173
George Liu87fd11c2020-11-23 16:40:14 +0800174 // Get paths of all the Physical LED objects
George Liu785f5052023-07-18 09:38:43 +0800175 try
176 {
177 physicalLEDPaths = dBusHandler.getSubTreePaths(PHY_LED_PATH,
178 PHY_LED_IFACE);
179 }
180 catch (const sdbusplus::exception_t& e)
181 {
182 lg2::error(
183 "Failed to call the SubTreePaths method: {ERROR}, ledPath: {PATH}, ledInterface: {INTERFACE}",
184 "ERROR", e, "PATH", PHY_LED_PATH, "INTERFACE", PHY_LED_IFACE);
185 return;
186 }
George Liu87fd11c2020-11-23 16:40:14 +0800187
George Liub6151622020-11-23 18:16:18 +0800188 // Get physical LEDs states before lamp test
189 storePhysicalLEDsStates();
190
George Liuc777bef2020-11-23 17:04:21 +0800191 // restart lamp test, it contains initiate or reset the timer.
192 timer.restart(std::chrono::seconds(LAMP_TEST_TIMEOUT_IN_SECS));
George Liub6151622020-11-23 18:16:18 +0800193 isLampTestRunning = true;
George Liu87fd11c2020-11-23 16:40:14 +0800194
George Liuce4d1c52021-01-25 11:32:37 +0800195 // Notify PHYP to start the lamp test
196 doHostLampTest(true);
197
George Liu87fd11c2020-11-23 16:40:14 +0800198 // Set all the Physical action to On for lamp test
199 for (const auto& path : physicalLEDPaths)
200 {
George Liu82150322021-03-03 17:13:13 +0800201 auto iter =
202 std::find_if(skipUpdateLEDs.begin(), skipUpdateLEDs.end(),
203 [&path](const auto& skip) { return skip == path; });
204
205 if (iter != skipUpdateLEDs.end())
206 {
207 // Skip update physical path
208 continue;
209 }
210
George Liu87fd11c2020-11-23 16:40:14 +0800211 manager.drivePhysicalLED(path, Layout::Action::On, 0, 0);
212 }
George Liuc777bef2020-11-23 17:04:21 +0800213}
214
215void LampTest::timeOutHandler()
216{
217 // set the Asserted property of lamp test to false
George Liu87fd11c2020-11-23 16:40:14 +0800218 if (!groupObj)
219 {
George Liue9fb5c62021-07-01 14:05:32 +0800220 lg2::error("the Group object is nullptr");
George Liu87fd11c2020-11-23 16:40:14 +0800221 throw std::runtime_error("the Group object is nullptr");
222 }
223
224 groupObj->asserted(false);
George Liuc777bef2020-11-23 17:04:21 +0800225}
226
George Liu87fd11c2020-11-23 16:40:14 +0800227void LampTest::requestHandler(Group* group, bool value)
George Liuc777bef2020-11-23 17:04:21 +0800228{
George Liu87fd11c2020-11-23 16:40:14 +0800229 if (groupObj == NULL)
230 {
231 groupObj = std::move(group);
232 }
233
George Liuc777bef2020-11-23 17:04:21 +0800234 if (value)
235 {
236 start();
237 }
238 else
239 {
240 stop();
241 }
242}
243
George Liub6151622020-11-23 18:16:18 +0800244void LampTest::restorePhysicalLedStates()
245{
246 // restore physical LEDs states before lamp test
Patrick Williams158b2c12022-03-17 05:57:44 -0500247 ActionSet ledsDeAssert{};
George Liu82150322021-03-03 17:13:13 +0800248 manager.driveLEDs(physicalLEDStatesPriorToLampTest, ledsDeAssert);
George Liub6151622020-11-23 18:16:18 +0800249 physicalLEDStatesPriorToLampTest.clear();
250
251 // restore physical LEDs states during lamp test
252 while (!updatedLEDsDuringLampTest.empty())
253 {
254 auto& [ledsAssert, ledsDeAssert] = updatedLEDsDuringLampTest.front();
255 manager.driveLEDs(ledsAssert, ledsDeAssert);
256 updatedLEDsDuringLampTest.pop();
257 }
258}
259
George Liuce4d1c52021-01-25 11:32:37 +0800260void LampTest::doHostLampTest(bool value)
261{
262 try
263 {
264 PropertyValue assertedValue{value};
265 dBusHandler.setProperty(HOST_LAMP_TEST_OBJECT,
266 "xyz.openbmc_project.Led.Group", "Asserted",
267 assertedValue);
268 }
Patrick Williams3e073ba2022-07-22 19:26:52 -0500269 catch (const sdbusplus::exception_t& e)
George Liuce4d1c52021-01-25 11:32:37 +0800270 {
George Liue9fb5c62021-07-01 14:05:32 +0800271 lg2::error(
272 "Failed to set Asserted property, ERROR = {ERROR}, PATH = {PATH}",
273 "ERROR", e, "PATH", std::string(HOST_LAMP_TEST_OBJECT));
George Liuce4d1c52021-01-25 11:32:37 +0800274 }
275}
276
George Liu82150322021-03-03 17:13:13 +0800277void LampTest::getPhysicalLEDNamesFromJson(const fs::path& path)
278{
279 if (!fs::exists(path) || fs::is_empty(path))
280 {
George Liue9fb5c62021-07-01 14:05:32 +0800281 lg2::info("The file does not exist or is empty, FILE_PATH = {PATH}",
282 "PATH", path);
George Liu82150322021-03-03 17:13:13 +0800283 return;
284 }
285
286 try
287 {
288 std::ifstream jsonFile(path);
289 auto json = Json::parse(jsonFile);
290
291 // define the default JSON as empty
292 const std::vector<std::string> empty{};
293 auto forceLEDs = json.value("forceLEDs", empty);
George Liuc5e0f312021-12-27 15:54:31 +0800294 std::ranges::transform(forceLEDs, std::back_inserter(forceUpdateLEDs),
295 [](const auto& i) { return PHY_LED_PATH + i; });
George Liu82150322021-03-03 17:13:13 +0800296
297 auto skipLEDs = json.value("skipLEDs", empty);
George Liuc5e0f312021-12-27 15:54:31 +0800298 std::ranges::transform(skipLEDs, std::back_inserter(skipUpdateLEDs),
299 [](const auto& i) { return PHY_LED_PATH + i; });
George Liu82150322021-03-03 17:13:13 +0800300 }
301 catch (const std::exception& e)
302 {
George Liue9fb5c62021-07-01 14:05:32 +0800303 lg2::error(
304 "Failed to parse config file, ERROR = {ERROR}, FILE_PATH = {PATH}",
305 "ERROR", e, "PATH", path);
George Liu82150322021-03-03 17:13:13 +0800306 }
307 return;
308}
309
George Liuc777bef2020-11-23 17:04:21 +0800310} // namespace led
311} // namespace phosphor