blob: 4c58e805d417eaf6ba34023340631cd5ba6ff6aa [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 Liuc777bef2020-11-23 17:04:21 +08005namespace phosphor
6{
7namespace led
8{
9
George Liu82150322021-03-03 17:13:13 +080010using Json = nlohmann::json;
George Liub6151622020-11-23 18:16:18 +080011
12bool LampTest::processLEDUpdates(const Manager::group& ledsAssert,
13 const Manager::group& ledsDeAssert)
14{
15 // If the physical LED status is updated during the lamp test, it should be
16 // saved to Queue, and the queue will be processed after the lamp test is
17 // stopped.
18 if (isLampTestRunning)
19 {
George Liu82150322021-03-03 17:13:13 +080020 // Physical LEDs will be updated during lamp test
21 for (const auto& it : ledsDeAssert)
22 {
23 std::string path = std::string(PHY_LED_PATH) + it.name;
24 auto iter = std::find_if(
25 forceUpdateLEDs.begin(), forceUpdateLEDs.end(),
26 [&path](const auto& name) { return name == path; });
27
28 if (iter != forceUpdateLEDs.end())
29 {
30 manager.drivePhysicalLED(path, Layout::Action::Off, it.dutyOn,
31 it.period);
32 }
33 }
34
35 for (const auto& it : ledsAssert)
36 {
37 std::string path = std::string(PHY_LED_PATH) + it.name;
38 auto iter = std::find_if(
39 forceUpdateLEDs.begin(), forceUpdateLEDs.end(),
40 [&path](const auto& name) { return name == path; });
41
42 if (iter != forceUpdateLEDs.end())
43 {
44 manager.drivePhysicalLED(path, it.action, it.dutyOn, it.period);
45 }
46 }
47
George Liub6151622020-11-23 18:16:18 +080048 updatedLEDsDuringLampTest.emplace(
49 std::make_pair(ledsAssert, ledsDeAssert));
50 return true;
51 }
52 return false;
53}
54
George Liuc777bef2020-11-23 17:04:21 +080055void LampTest::stop()
56{
George Liub6151622020-11-23 18:16:18 +080057 if (!isLampTestRunning)
58 {
59 return;
60 }
61
George Liuc777bef2020-11-23 17:04:21 +080062 timer.setEnabled(false);
George Liu87fd11c2020-11-23 16:40:14 +080063
George Liuce4d1c52021-01-25 11:32:37 +080064 // Stop host lamp test
65 doHostLampTest(false);
66
George Liu87fd11c2020-11-23 16:40:14 +080067 // Set all the Physical action to Off
68 for (const auto& path : physicalLEDPaths)
69 {
George Liu82150322021-03-03 17:13:13 +080070 auto iter =
71 std::find_if(skipUpdateLEDs.begin(), skipUpdateLEDs.end(),
72 [&path](const auto& skip) { return skip == path; });
73
74 if (iter != skipUpdateLEDs.end())
75 {
76 // Skip update physical path
77 continue;
78 }
79
George Liu87fd11c2020-11-23 16:40:14 +080080 manager.drivePhysicalLED(path, Layout::Action::Off, 0, 0);
81 }
George Liub6151622020-11-23 18:16:18 +080082
83 isLampTestRunning = false;
84 restorePhysicalLedStates();
85}
86
87Layout::Action LampTest::getActionFromString(const std::string& str)
88{
89 Layout::Action action = Layout::Off;
90
91 if (str == "xyz.openbmc_project.Led.Physical.Action.On")
92 {
93 action = Layout::On;
94 }
95 else if (str == "xyz.openbmc_project.Led.Physical.Action.Blink")
96 {
97 action = Layout::Blink;
98 }
99
100 return action;
101}
102
103void LampTest::storePhysicalLEDsStates()
104{
105 physicalLEDStatesPriorToLampTest.clear();
106
107 for (const auto& path : physicalLEDPaths)
108 {
George Liu82150322021-03-03 17:13:13 +0800109 auto iter = std::find_if(
110 skipUpdateLEDs.begin(), skipUpdateLEDs.end(),
111 [&path](const auto& skipLed) { return skipLed == path; });
112
113 if (iter != skipUpdateLEDs.end())
114 {
115 // Physical LEDs will be skipped
116 continue;
117 }
118
George Liub6151622020-11-23 18:16:18 +0800119 // Reverse intercept path, Get the name of each member of physical led
120 // e.g: path = /xyz/openbmc_project/led/physical/front_fan
121 // name = front_fan
122 sdbusplus::message::object_path object_path(path);
123 auto name = object_path.filename();
124 if (name.empty())
125 {
George Liue9fb5c62021-07-01 14:05:32 +0800126 lg2::error(
127 "Failed to get the name of member of physical LED path, PATH = {PATH}, NAME = {NAME}",
128 "PATH", path, "NAME", name);
George Liub6151622020-11-23 18:16:18 +0800129 continue;
130 }
131
132 std::string state{};
133 uint16_t period{};
134 uint8_t dutyOn{};
135 try
136 {
137 auto properties = dBusHandler.getAllProperties(path, PHY_LED_IFACE);
138
139 state = std::get<std::string>(properties["State"]);
140 period = std::get<uint16_t>(properties["Period"]);
141 dutyOn = std::get<uint8_t>(properties["DutyOn"]);
142 }
Patrick Williams7152edc2021-09-02 09:41:54 -0500143 catch (const sdbusplus::exception::exception& e)
George Liub6151622020-11-23 18:16:18 +0800144 {
George Liue9fb5c62021-07-01 14:05:32 +0800145 lg2::error(
146 "Failed to get All properties, ERROR = {ERROR}, PATH = {PATH}",
147 "ERROR", e, "PATH", path);
George Liub6151622020-11-23 18:16:18 +0800148 continue;
149 }
150
151 phosphor::led::Layout::Action action = getActionFromString(state);
152 if (action != phosphor::led::Layout::Off)
153 {
154 phosphor::led::Layout::LedAction ledAction{
155 name, action, dutyOn, period, phosphor::led::Layout::On};
156 physicalLEDStatesPriorToLampTest.emplace(ledAction);
157 }
158 }
George Liuc777bef2020-11-23 17:04:21 +0800159}
160
161void LampTest::start()
162{
George Liub6151622020-11-23 18:16:18 +0800163 if (isLampTestRunning)
164 {
165 // reset the timer and then return
166 timer.restart(std::chrono::seconds(LAMP_TEST_TIMEOUT_IN_SECS));
167 return;
168 }
169
George Liu87fd11c2020-11-23 16:40:14 +0800170 // Get paths of all the Physical LED objects
171 physicalLEDPaths = dBusHandler.getSubTreePaths(PHY_LED_PATH, PHY_LED_IFACE);
172
George Liub6151622020-11-23 18:16:18 +0800173 // Get physical LEDs states before lamp test
174 storePhysicalLEDsStates();
175
George Liuc777bef2020-11-23 17:04:21 +0800176 // restart lamp test, it contains initiate or reset the timer.
177 timer.restart(std::chrono::seconds(LAMP_TEST_TIMEOUT_IN_SECS));
George Liub6151622020-11-23 18:16:18 +0800178 isLampTestRunning = true;
George Liu87fd11c2020-11-23 16:40:14 +0800179
George Liuce4d1c52021-01-25 11:32:37 +0800180 // Notify PHYP to start the lamp test
181 doHostLampTest(true);
182
George Liu87fd11c2020-11-23 16:40:14 +0800183 // Set all the Physical action to On for lamp test
184 for (const auto& path : physicalLEDPaths)
185 {
George Liu82150322021-03-03 17:13:13 +0800186 auto iter =
187 std::find_if(skipUpdateLEDs.begin(), skipUpdateLEDs.end(),
188 [&path](const auto& skip) { return skip == path; });
189
190 if (iter != skipUpdateLEDs.end())
191 {
192 // Skip update physical path
193 continue;
194 }
195
George Liu87fd11c2020-11-23 16:40:14 +0800196 manager.drivePhysicalLED(path, Layout::Action::On, 0, 0);
197 }
George Liuc777bef2020-11-23 17:04:21 +0800198}
199
200void LampTest::timeOutHandler()
201{
202 // set the Asserted property of lamp test to false
George Liu87fd11c2020-11-23 16:40:14 +0800203 if (!groupObj)
204 {
George Liue9fb5c62021-07-01 14:05:32 +0800205 lg2::error("the Group object is nullptr");
George Liu87fd11c2020-11-23 16:40:14 +0800206 throw std::runtime_error("the Group object is nullptr");
207 }
208
209 groupObj->asserted(false);
George Liuc777bef2020-11-23 17:04:21 +0800210}
211
George Liu87fd11c2020-11-23 16:40:14 +0800212void LampTest::requestHandler(Group* group, bool value)
George Liuc777bef2020-11-23 17:04:21 +0800213{
George Liu87fd11c2020-11-23 16:40:14 +0800214 if (groupObj == NULL)
215 {
216 groupObj = std::move(group);
217 }
218
George Liuc777bef2020-11-23 17:04:21 +0800219 if (value)
220 {
221 start();
222 }
223 else
224 {
225 stop();
226 }
227}
228
George Liub6151622020-11-23 18:16:18 +0800229void LampTest::restorePhysicalLedStates()
230{
231 // restore physical LEDs states before lamp test
George Liu82150322021-03-03 17:13:13 +0800232 Manager::group ledsDeAssert{};
233 manager.driveLEDs(physicalLEDStatesPriorToLampTest, ledsDeAssert);
George Liub6151622020-11-23 18:16:18 +0800234 physicalLEDStatesPriorToLampTest.clear();
235
236 // restore physical LEDs states during lamp test
237 while (!updatedLEDsDuringLampTest.empty())
238 {
239 auto& [ledsAssert, ledsDeAssert] = updatedLEDsDuringLampTest.front();
240 manager.driveLEDs(ledsAssert, ledsDeAssert);
241 updatedLEDsDuringLampTest.pop();
242 }
243}
244
George Liuce4d1c52021-01-25 11:32:37 +0800245void LampTest::doHostLampTest(bool value)
246{
247 try
248 {
249 PropertyValue assertedValue{value};
250 dBusHandler.setProperty(HOST_LAMP_TEST_OBJECT,
251 "xyz.openbmc_project.Led.Group", "Asserted",
252 assertedValue);
253 }
Patrick Williams7152edc2021-09-02 09:41:54 -0500254 catch (const sdbusplus::exception::exception& e)
George Liuce4d1c52021-01-25 11:32:37 +0800255 {
George Liue9fb5c62021-07-01 14:05:32 +0800256 lg2::error(
257 "Failed to set Asserted property, ERROR = {ERROR}, PATH = {PATH}",
258 "ERROR", e, "PATH", std::string(HOST_LAMP_TEST_OBJECT));
George Liuce4d1c52021-01-25 11:32:37 +0800259 }
260}
261
George Liu82150322021-03-03 17:13:13 +0800262void LampTest::getPhysicalLEDNamesFromJson(const fs::path& path)
263{
264 if (!fs::exists(path) || fs::is_empty(path))
265 {
George Liue9fb5c62021-07-01 14:05:32 +0800266 lg2::info("The file does not exist or is empty, FILE_PATH = {PATH}",
267 "PATH", path);
George Liu82150322021-03-03 17:13:13 +0800268 return;
269 }
270
271 try
272 {
273 std::ifstream jsonFile(path);
274 auto json = Json::parse(jsonFile);
275
276 // define the default JSON as empty
277 const std::vector<std::string> empty{};
278 auto forceLEDs = json.value("forceLEDs", empty);
279 for (auto& member : forceLEDs)
280 {
281 forceUpdateLEDs.push_back(PHY_LED_PATH + member);
282 }
283
284 auto skipLEDs = json.value("skipLEDs", empty);
285 for (auto& member : skipLEDs)
286 {
287 skipUpdateLEDs.push_back(PHY_LED_PATH + member);
288 }
289 }
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