blob: cd87bc26391ad02fa5674029cfd5b45597c048fc [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
14bool LampTest::processLEDUpdates(const Manager::group& ledsAssert,
15 const Manager::group& ledsDeAssert)
16{
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{
91 Layout::Action action = Layout::Off;
92
93 if (str == "xyz.openbmc_project.Led.Physical.Action.On")
94 {
95 action = Layout::On;
96 }
97 else if (str == "xyz.openbmc_project.Led.Physical.Action.Blink")
98 {
99 action = Layout::Blink;
100 }
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 Williams7152edc2021-09-02 09:41:54 -0500145 catch (const sdbusplus::exception::exception& 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);
154 if (action != phosphor::led::Layout::Off)
155 {
156 phosphor::led::Layout::LedAction ledAction{
157 name, action, dutyOn, period, phosphor::led::Layout::On};
158 physicalLEDStatesPriorToLampTest.emplace(ledAction);
159 }
160 }
George Liuc777bef2020-11-23 17:04:21 +0800161}
162
163void LampTest::start()
164{
George Liub6151622020-11-23 18:16:18 +0800165 if (isLampTestRunning)
166 {
167 // reset the timer and then return
168 timer.restart(std::chrono::seconds(LAMP_TEST_TIMEOUT_IN_SECS));
169 return;
170 }
171
George Liu87fd11c2020-11-23 16:40:14 +0800172 // Get paths of all the Physical LED objects
173 physicalLEDPaths = dBusHandler.getSubTreePaths(PHY_LED_PATH, PHY_LED_IFACE);
174
George Liub6151622020-11-23 18:16:18 +0800175 // Get physical LEDs states before lamp test
176 storePhysicalLEDsStates();
177
George Liuc777bef2020-11-23 17:04:21 +0800178 // restart lamp test, it contains initiate or reset the timer.
179 timer.restart(std::chrono::seconds(LAMP_TEST_TIMEOUT_IN_SECS));
George Liub6151622020-11-23 18:16:18 +0800180 isLampTestRunning = true;
George Liu87fd11c2020-11-23 16:40:14 +0800181
George Liuce4d1c52021-01-25 11:32:37 +0800182 // Notify PHYP to start the lamp test
183 doHostLampTest(true);
184
George Liu87fd11c2020-11-23 16:40:14 +0800185 // Set all the Physical action to On for lamp test
186 for (const auto& path : physicalLEDPaths)
187 {
George Liu82150322021-03-03 17:13:13 +0800188 auto iter =
189 std::find_if(skipUpdateLEDs.begin(), skipUpdateLEDs.end(),
190 [&path](const auto& skip) { return skip == path; });
191
192 if (iter != skipUpdateLEDs.end())
193 {
194 // Skip update physical path
195 continue;
196 }
197
George Liu87fd11c2020-11-23 16:40:14 +0800198 manager.drivePhysicalLED(path, Layout::Action::On, 0, 0);
199 }
George Liuc777bef2020-11-23 17:04:21 +0800200}
201
202void LampTest::timeOutHandler()
203{
204 // set the Asserted property of lamp test to false
George Liu87fd11c2020-11-23 16:40:14 +0800205 if (!groupObj)
206 {
George Liue9fb5c62021-07-01 14:05:32 +0800207 lg2::error("the Group object is nullptr");
George Liu87fd11c2020-11-23 16:40:14 +0800208 throw std::runtime_error("the Group object is nullptr");
209 }
210
211 groupObj->asserted(false);
George Liuc777bef2020-11-23 17:04:21 +0800212}
213
George Liu87fd11c2020-11-23 16:40:14 +0800214void LampTest::requestHandler(Group* group, bool value)
George Liuc777bef2020-11-23 17:04:21 +0800215{
George Liu87fd11c2020-11-23 16:40:14 +0800216 if (groupObj == NULL)
217 {
218 groupObj = std::move(group);
219 }
220
George Liuc777bef2020-11-23 17:04:21 +0800221 if (value)
222 {
223 start();
224 }
225 else
226 {
227 stop();
228 }
229}
230
George Liub6151622020-11-23 18:16:18 +0800231void LampTest::restorePhysicalLedStates()
232{
233 // restore physical LEDs states before lamp test
George Liu82150322021-03-03 17:13:13 +0800234 Manager::group ledsDeAssert{};
235 manager.driveLEDs(physicalLEDStatesPriorToLampTest, ledsDeAssert);
George Liub6151622020-11-23 18:16:18 +0800236 physicalLEDStatesPriorToLampTest.clear();
237
238 // restore physical LEDs states during lamp test
239 while (!updatedLEDsDuringLampTest.empty())
240 {
241 auto& [ledsAssert, ledsDeAssert] = updatedLEDsDuringLampTest.front();
242 manager.driveLEDs(ledsAssert, ledsDeAssert);
243 updatedLEDsDuringLampTest.pop();
244 }
245}
246
George Liuce4d1c52021-01-25 11:32:37 +0800247void LampTest::doHostLampTest(bool value)
248{
249 try
250 {
251 PropertyValue assertedValue{value};
252 dBusHandler.setProperty(HOST_LAMP_TEST_OBJECT,
253 "xyz.openbmc_project.Led.Group", "Asserted",
254 assertedValue);
255 }
Patrick Williams7152edc2021-09-02 09:41:54 -0500256 catch (const sdbusplus::exception::exception& e)
George Liuce4d1c52021-01-25 11:32:37 +0800257 {
George Liue9fb5c62021-07-01 14:05:32 +0800258 lg2::error(
259 "Failed to set Asserted property, ERROR = {ERROR}, PATH = {PATH}",
260 "ERROR", e, "PATH", std::string(HOST_LAMP_TEST_OBJECT));
George Liuce4d1c52021-01-25 11:32:37 +0800261 }
262}
263
George Liu82150322021-03-03 17:13:13 +0800264void LampTest::getPhysicalLEDNamesFromJson(const fs::path& path)
265{
266 if (!fs::exists(path) || fs::is_empty(path))
267 {
George Liue9fb5c62021-07-01 14:05:32 +0800268 lg2::info("The file does not exist or is empty, FILE_PATH = {PATH}",
269 "PATH", path);
George Liu82150322021-03-03 17:13:13 +0800270 return;
271 }
272
273 try
274 {
275 std::ifstream jsonFile(path);
276 auto json = Json::parse(jsonFile);
277
278 // define the default JSON as empty
279 const std::vector<std::string> empty{};
280 auto forceLEDs = json.value("forceLEDs", empty);
George Liuc5e0f312021-12-27 15:54:31 +0800281 std::ranges::transform(forceLEDs, std::back_inserter(forceUpdateLEDs),
282 [](const auto& i) { return PHY_LED_PATH + i; });
George Liu82150322021-03-03 17:13:13 +0800283
284 auto skipLEDs = json.value("skipLEDs", empty);
George Liuc5e0f312021-12-27 15:54:31 +0800285 std::ranges::transform(skipLEDs, std::back_inserter(skipUpdateLEDs),
286 [](const auto& i) { return PHY_LED_PATH + i; });
George Liu82150322021-03-03 17:13:13 +0800287 }
288 catch (const std::exception& e)
289 {
George Liue9fb5c62021-07-01 14:05:32 +0800290 lg2::error(
291 "Failed to parse config file, ERROR = {ERROR}, FILE_PATH = {PATH}",
292 "ERROR", e, "PATH", path);
George Liu82150322021-03-03 17:13:13 +0800293 }
294 return;
295}
296
George Liuc777bef2020-11-23 17:04:21 +0800297} // namespace led
298} // namespace phosphor