blob: 57e5a33b8e4baba768f223628eadb2e3c0520d71 [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 {
George Liu82150322021-03-03 17:13:13 +0800111 auto iter = std::find_if(
112 skipUpdateLEDs.begin(), skipUpdateLEDs.end(),
113 [&path](const auto& skipLed) { return skipLed == path; });
114
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 {
139 auto properties = dBusHandler.getAllProperties(path, PHY_LED_IFACE);
140
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));
170 return;
171 }
172
George Liu87fd11c2020-11-23 16:40:14 +0800173 // Get paths of all the Physical LED objects
174 physicalLEDPaths = dBusHandler.getSubTreePaths(PHY_LED_PATH, PHY_LED_IFACE);
175
George Liub6151622020-11-23 18:16:18 +0800176 // Get physical LEDs states before lamp test
177 storePhysicalLEDsStates();
178
George Liuc777bef2020-11-23 17:04:21 +0800179 // restart lamp test, it contains initiate or reset the timer.
180 timer.restart(std::chrono::seconds(LAMP_TEST_TIMEOUT_IN_SECS));
George Liub6151622020-11-23 18:16:18 +0800181 isLampTestRunning = true;
George Liu87fd11c2020-11-23 16:40:14 +0800182
George Liuce4d1c52021-01-25 11:32:37 +0800183 // Notify PHYP to start the lamp test
184 doHostLampTest(true);
185
George Liu87fd11c2020-11-23 16:40:14 +0800186 // Set all the Physical action to On for lamp test
187 for (const auto& path : physicalLEDPaths)
188 {
George Liu82150322021-03-03 17:13:13 +0800189 auto iter =
190 std::find_if(skipUpdateLEDs.begin(), skipUpdateLEDs.end(),
191 [&path](const auto& skip) { return skip == path; });
192
193 if (iter != skipUpdateLEDs.end())
194 {
195 // Skip update physical path
196 continue;
197 }
198
George Liu87fd11c2020-11-23 16:40:14 +0800199 manager.drivePhysicalLED(path, Layout::Action::On, 0, 0);
200 }
George Liuc777bef2020-11-23 17:04:21 +0800201}
202
203void LampTest::timeOutHandler()
204{
205 // set the Asserted property of lamp test to false
George Liu87fd11c2020-11-23 16:40:14 +0800206 if (!groupObj)
207 {
George Liue9fb5c62021-07-01 14:05:32 +0800208 lg2::error("the Group object is nullptr");
George Liu87fd11c2020-11-23 16:40:14 +0800209 throw std::runtime_error("the Group object is nullptr");
210 }
211
212 groupObj->asserted(false);
George Liuc777bef2020-11-23 17:04:21 +0800213}
214
George Liu87fd11c2020-11-23 16:40:14 +0800215void LampTest::requestHandler(Group* group, bool value)
George Liuc777bef2020-11-23 17:04:21 +0800216{
George Liu87fd11c2020-11-23 16:40:14 +0800217 if (groupObj == NULL)
218 {
219 groupObj = std::move(group);
220 }
221
George Liuc777bef2020-11-23 17:04:21 +0800222 if (value)
223 {
224 start();
225 }
226 else
227 {
228 stop();
229 }
230}
231
George Liub6151622020-11-23 18:16:18 +0800232void LampTest::restorePhysicalLedStates()
233{
234 // restore physical LEDs states before lamp test
Patrick Williams158b2c12022-03-17 05:57:44 -0500235 ActionSet ledsDeAssert{};
George Liu82150322021-03-03 17:13:13 +0800236 manager.driveLEDs(physicalLEDStatesPriorToLampTest, ledsDeAssert);
George Liub6151622020-11-23 18:16:18 +0800237 physicalLEDStatesPriorToLampTest.clear();
238
239 // restore physical LEDs states during lamp test
240 while (!updatedLEDsDuringLampTest.empty())
241 {
242 auto& [ledsAssert, ledsDeAssert] = updatedLEDsDuringLampTest.front();
243 manager.driveLEDs(ledsAssert, ledsDeAssert);
244 updatedLEDsDuringLampTest.pop();
245 }
246}
247
George Liuce4d1c52021-01-25 11:32:37 +0800248void LampTest::doHostLampTest(bool value)
249{
250 try
251 {
252 PropertyValue assertedValue{value};
253 dBusHandler.setProperty(HOST_LAMP_TEST_OBJECT,
254 "xyz.openbmc_project.Led.Group", "Asserted",
255 assertedValue);
256 }
Patrick Williams3e073ba2022-07-22 19:26:52 -0500257 catch (const sdbusplus::exception_t& e)
George Liuce4d1c52021-01-25 11:32:37 +0800258 {
George Liue9fb5c62021-07-01 14:05:32 +0800259 lg2::error(
260 "Failed to set Asserted property, ERROR = {ERROR}, PATH = {PATH}",
261 "ERROR", e, "PATH", std::string(HOST_LAMP_TEST_OBJECT));
George Liuce4d1c52021-01-25 11:32:37 +0800262 }
263}
264
George Liu82150322021-03-03 17:13:13 +0800265void LampTest::getPhysicalLEDNamesFromJson(const fs::path& path)
266{
267 if (!fs::exists(path) || fs::is_empty(path))
268 {
George Liue9fb5c62021-07-01 14:05:32 +0800269 lg2::info("The file does not exist or is empty, FILE_PATH = {PATH}",
270 "PATH", path);
George Liu82150322021-03-03 17:13:13 +0800271 return;
272 }
273
274 try
275 {
276 std::ifstream jsonFile(path);
277 auto json = Json::parse(jsonFile);
278
279 // define the default JSON as empty
280 const std::vector<std::string> empty{};
281 auto forceLEDs = json.value("forceLEDs", empty);
George Liuc5e0f312021-12-27 15:54:31 +0800282 std::ranges::transform(forceLEDs, std::back_inserter(forceUpdateLEDs),
283 [](const auto& i) { return PHY_LED_PATH + i; });
George Liu82150322021-03-03 17:13:13 +0800284
285 auto skipLEDs = json.value("skipLEDs", empty);
George Liuc5e0f312021-12-27 15:54:31 +0800286 std::ranges::transform(skipLEDs, std::back_inserter(skipUpdateLEDs),
287 [](const auto& i) { return PHY_LED_PATH + i; });
George Liu82150322021-03-03 17:13:13 +0800288 }
289 catch (const std::exception& e)
290 {
George Liue9fb5c62021-07-01 14:05:32 +0800291 lg2::error(
292 "Failed to parse config file, ERROR = {ERROR}, FILE_PATH = {PATH}",
293 "ERROR", e, "PATH", path);
George Liu82150322021-03-03 17:13:13 +0800294 }
295 return;
296}
297
George Liuc777bef2020-11-23 17:04:21 +0800298} // namespace led
299} // namespace phosphor