blob: 5fd430c0541d1bd26a2b08e2c66ac77bae6463f3 [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
175 physicalLEDPaths = dBusHandler.getSubTreePaths(PHY_LED_PATH, PHY_LED_IFACE);
176
George Liub6151622020-11-23 18:16:18 +0800177 // Get physical LEDs states before lamp test
178 storePhysicalLEDsStates();
179
George Liuc777bef2020-11-23 17:04:21 +0800180 // restart lamp test, it contains initiate or reset the timer.
181 timer.restart(std::chrono::seconds(LAMP_TEST_TIMEOUT_IN_SECS));
George Liub6151622020-11-23 18:16:18 +0800182 isLampTestRunning = true;
George Liu87fd11c2020-11-23 16:40:14 +0800183
George Liuce4d1c52021-01-25 11:32:37 +0800184 // Notify PHYP to start the lamp test
185 doHostLampTest(true);
186
George Liu87fd11c2020-11-23 16:40:14 +0800187 // Set all the Physical action to On for lamp test
188 for (const auto& path : physicalLEDPaths)
189 {
George Liu82150322021-03-03 17:13:13 +0800190 auto iter =
191 std::find_if(skipUpdateLEDs.begin(), skipUpdateLEDs.end(),
192 [&path](const auto& skip) { return skip == path; });
193
194 if (iter != skipUpdateLEDs.end())
195 {
196 // Skip update physical path
197 continue;
198 }
199
George Liu87fd11c2020-11-23 16:40:14 +0800200 manager.drivePhysicalLED(path, Layout::Action::On, 0, 0);
201 }
George Liuc777bef2020-11-23 17:04:21 +0800202}
203
204void LampTest::timeOutHandler()
205{
206 // set the Asserted property of lamp test to false
George Liu87fd11c2020-11-23 16:40:14 +0800207 if (!groupObj)
208 {
George Liue9fb5c62021-07-01 14:05:32 +0800209 lg2::error("the Group object is nullptr");
George Liu87fd11c2020-11-23 16:40:14 +0800210 throw std::runtime_error("the Group object is nullptr");
211 }
212
213 groupObj->asserted(false);
George Liuc777bef2020-11-23 17:04:21 +0800214}
215
George Liu87fd11c2020-11-23 16:40:14 +0800216void LampTest::requestHandler(Group* group, bool value)
George Liuc777bef2020-11-23 17:04:21 +0800217{
George Liu87fd11c2020-11-23 16:40:14 +0800218 if (groupObj == NULL)
219 {
220 groupObj = std::move(group);
221 }
222
George Liuc777bef2020-11-23 17:04:21 +0800223 if (value)
224 {
225 start();
226 }
227 else
228 {
229 stop();
230 }
231}
232
George Liub6151622020-11-23 18:16:18 +0800233void LampTest::restorePhysicalLedStates()
234{
235 // restore physical LEDs states before lamp test
Patrick Williams158b2c12022-03-17 05:57:44 -0500236 ActionSet ledsDeAssert{};
George Liu82150322021-03-03 17:13:13 +0800237 manager.driveLEDs(physicalLEDStatesPriorToLampTest, ledsDeAssert);
George Liub6151622020-11-23 18:16:18 +0800238 physicalLEDStatesPriorToLampTest.clear();
239
240 // restore physical LEDs states during lamp test
241 while (!updatedLEDsDuringLampTest.empty())
242 {
243 auto& [ledsAssert, ledsDeAssert] = updatedLEDsDuringLampTest.front();
244 manager.driveLEDs(ledsAssert, ledsDeAssert);
245 updatedLEDsDuringLampTest.pop();
246 }
247}
248
George Liuce4d1c52021-01-25 11:32:37 +0800249void LampTest::doHostLampTest(bool value)
250{
251 try
252 {
253 PropertyValue assertedValue{value};
254 dBusHandler.setProperty(HOST_LAMP_TEST_OBJECT,
255 "xyz.openbmc_project.Led.Group", "Asserted",
256 assertedValue);
257 }
Patrick Williams3e073ba2022-07-22 19:26:52 -0500258 catch (const sdbusplus::exception_t& e)
George Liuce4d1c52021-01-25 11:32:37 +0800259 {
George Liue9fb5c62021-07-01 14:05:32 +0800260 lg2::error(
261 "Failed to set Asserted property, ERROR = {ERROR}, PATH = {PATH}",
262 "ERROR", e, "PATH", std::string(HOST_LAMP_TEST_OBJECT));
George Liuce4d1c52021-01-25 11:32:37 +0800263 }
264}
265
George Liu82150322021-03-03 17:13:13 +0800266void LampTest::getPhysicalLEDNamesFromJson(const fs::path& path)
267{
268 if (!fs::exists(path) || fs::is_empty(path))
269 {
George Liue9fb5c62021-07-01 14:05:32 +0800270 lg2::info("The file does not exist or is empty, FILE_PATH = {PATH}",
271 "PATH", path);
George Liu82150322021-03-03 17:13:13 +0800272 return;
273 }
274
275 try
276 {
277 std::ifstream jsonFile(path);
278 auto json = Json::parse(jsonFile);
279
280 // define the default JSON as empty
281 const std::vector<std::string> empty{};
282 auto forceLEDs = json.value("forceLEDs", empty);
George Liuc5e0f312021-12-27 15:54:31 +0800283 std::ranges::transform(forceLEDs, std::back_inserter(forceUpdateLEDs),
284 [](const auto& i) { return PHY_LED_PATH + i; });
George Liu82150322021-03-03 17:13:13 +0800285
286 auto skipLEDs = json.value("skipLEDs", empty);
George Liuc5e0f312021-12-27 15:54:31 +0800287 std::ranges::transform(skipLEDs, std::back_inserter(skipUpdateLEDs),
288 [](const auto& i) { return PHY_LED_PATH + i; });
George Liu82150322021-03-03 17:13:13 +0800289 }
290 catch (const std::exception& e)
291 {
George Liue9fb5c62021-07-01 14:05:32 +0800292 lg2::error(
293 "Failed to parse config file, ERROR = {ERROR}, FILE_PATH = {PATH}",
294 "ERROR", e, "PATH", path);
George Liu82150322021-03-03 17:13:13 +0800295 }
296 return;
297}
298
George Liuc777bef2020-11-23 17:04:21 +0800299} // namespace led
300} // namespace phosphor