xref: /openbmc/pldm/platform-mc/sensor_manager.cpp (revision fdf61cc310dfe7bb56d007bf1026635081f44aca)
1 #include "sensor_manager.hpp"
2 
3 #include "manager.hpp"
4 #include "terminus_manager.hpp"
5 
6 #include <phosphor-logging/lg2.hpp>
7 
8 #include <exception>
9 
10 namespace pldm
11 {
12 namespace platform_mc
13 {
14 
SensorManager(sdeventplus::Event & event,TerminusManager & terminusManager,TerminiMapper & termini,Manager * manager)15 SensorManager::SensorManager(sdeventplus::Event& event,
16                              TerminusManager& terminusManager,
17                              TerminiMapper& termini, Manager* manager) :
18     event(event), terminusManager(terminusManager), termini(termini),
19     pollingTime(SENSOR_POLLING_TIME), manager(manager)
20 {}
21 
startPolling(pldm_tid_t tid)22 void SensorManager::startPolling(pldm_tid_t tid)
23 {
24     if (!termini.contains(tid))
25     {
26         return;
27     }
28 
29     /* tid already initializes roundRobinSensors list */
30     if (sensorPollTimers.contains(tid))
31     {
32         lg2::info("Terminus ID {TID}: sensor poll timer already exists.", "TID",
33                   tid);
34         return;
35     }
36 
37     roundRobinSensorItMap[tid] = 0;
38 
39     updateAvailableState(tid, true);
40 
41     sensorPollTimers[tid] = std::make_unique<sdbusplus::Timer>(
42         event.get(),
43         std::bind_front(&SensorManager::doSensorPolling, this, tid));
44 
45     startSensorPollTimer(tid);
46 }
47 
startSensorPollTimer(pldm_tid_t tid)48 void SensorManager::startSensorPollTimer(pldm_tid_t tid)
49 {
50     try
51     {
52         if (sensorPollTimers[tid] && !sensorPollTimers[tid]->isRunning())
53         {
54             sensorPollTimers[tid]->start(
55                 duration_cast<std::chrono::milliseconds>(
56                     std::chrono::milliseconds(pollingTime)),
57                 true);
58         }
59     }
60     catch (const std::exception& e)
61     {
62         lg2::error(
63             "Terminus ID {TID}: Failed to start sensor polling timer. Exception: {EXCEPTION}",
64             "TID", tid, "EXCEPTION", e);
65         return;
66     }
67 }
68 
disableTerminusSensors(pldm_tid_t tid)69 void SensorManager::disableTerminusSensors(pldm_tid_t tid)
70 {
71     if (!termini.contains(tid))
72     {
73         return;
74     }
75 
76     // numeric sensor
77     auto terminus = termini[tid];
78     if (!terminus)
79     {
80         return;
81     }
82 
83     for (auto& sensor : terminus->numericSensors)
84     {
85         sensor->updateReading(true, false,
86                               std::numeric_limits<double>::quiet_NaN());
87     }
88 }
89 
stopPolling(pldm_tid_t tid)90 void SensorManager::stopPolling(pldm_tid_t tid)
91 {
92     /* Stop polling timer */
93     if (sensorPollTimers.contains(tid))
94     {
95         sensorPollTimers[tid]->stop();
96         sensorPollTimers.erase(tid);
97     }
98 
99     roundRobinSensorItMap.erase(tid);
100 
101     if (doSensorPollingTaskHandles.contains(tid))
102     {
103         auto& [scope, rcOpt] = doSensorPollingTaskHandles[tid];
104         scope.request_stop();
105         doSensorPollingTaskHandles.erase(tid);
106     }
107 
108     availableState.erase(tid);
109 }
110 
doSensorPolling(pldm_tid_t tid)111 void SensorManager::doSensorPolling(pldm_tid_t tid)
112 {
113     auto it = doSensorPollingTaskHandles.find(tid);
114     if (it != doSensorPollingTaskHandles.end())
115     {
116         auto& [scope, rcOpt] = it->second;
117         if (!rcOpt.has_value())
118         {
119             return;
120         }
121         doSensorPollingTaskHandles.erase(tid);
122     }
123 
124     auto& [scope, rcOpt] =
125         doSensorPollingTaskHandles
126             .emplace(std::piecewise_construct, std::forward_as_tuple(tid),
127                      std::forward_as_tuple())
128             .first->second;
129     scope.spawn(
130         stdexec::just() | stdexec::let_value([this, &rcOpt,
131                                               tid] -> exec::task<void> {
132             auto res =
133                 co_await stdexec::stopped_as_optional(doSensorPollingTask(tid));
134             if (res.has_value())
135             {
136                 rcOpt = *res;
137             }
138             else
139             {
140                 lg2::info("Stopped polling for Terminus ID {TID}", "TID", tid);
141                 try
142                 {
143                     if (sensorPollTimers.contains(tid) &&
144                         sensorPollTimers[tid] &&
145                         sensorPollTimers[tid]->isRunning())
146                     {
147                         sensorPollTimers[tid]->stop();
148                     }
149                 }
150                 catch (const std::exception& e)
151                 {
152                     lg2::error(
153                         "Terminus ID {TID}: Failed to stop polling timer. Exception: {EXCEPTION}",
154                         "TID", tid, "EXCEPTION", e);
155                 }
156                 rcOpt = PLDM_SUCCESS;
157             }
158         }),
159         exec::default_task_context<void>(exec::inline_scheduler{}));
160 }
161 
doSensorPollingTask(pldm_tid_t tid)162 exec::task<int> SensorManager::doSensorPollingTask(pldm_tid_t tid)
163 {
164     uint64_t t0 = 0;
165     uint64_t t1 = 0;
166     uint64_t elapsed = 0;
167     uint64_t pollingTimeInUsec = pollingTime * 1000;
168     uint8_t rc = PLDM_SUCCESS;
169 
170     do
171     {
172         if ((!sensorPollTimers.contains(tid)) ||
173             (sensorPollTimers[tid] && !sensorPollTimers[tid]->isRunning()))
174         {
175             co_return PLDM_ERROR;
176         }
177 
178         sd_event_now(event.get(), CLOCK_MONOTONIC, &t0);
179 
180         /**
181          * Terminus is not available for PLDM request.
182          * The terminus manager will trigger recovery process to recovery the
183          * communication between the local terminus and the remote terminus.
184          * The sensor polling should be stopped while recovering the
185          * communication.
186          */
187         if (!getAvailableState(tid))
188         {
189             lg2::info(
190                 "Terminus ID {TID} is not available for PLDM request from {NOW}.",
191                 "TID", tid, "NOW", pldm::utils::getCurrentSystemTime());
192             co_await stdexec::just_stopped();
193         }
194 
195         if (!termini.contains(tid))
196         {
197             co_return PLDM_SUCCESS;
198         }
199 
200         auto& terminus = termini[tid];
201         if (!terminus)
202         {
203             lg2::info(
204                 "Terminus ID {TID} does not have a valid Terminus object {NOW}.",
205                 "TID", tid, "NOW", pldm::utils::getCurrentSystemTime());
206             co_return PLDM_ERROR;
207         }
208 
209         if (manager && terminus->pollEvent)
210         {
211             co_await manager->pollForPlatformEvent(
212                 tid, terminus->pollEventId, terminus->pollDataTransferHandle);
213         }
214 
215         if (manager && (!terminus->pollEvent))
216         {
217             co_await manager->oemPollForPlatformEvent(tid);
218         }
219 
220         sd_event_now(event.get(), CLOCK_MONOTONIC, &t1);
221 
222         auto& numericSensors = terminus->numericSensors;
223         auto toBeUpdated = numericSensors.size();
224 
225         if (!roundRobinSensorItMap.contains(tid))
226         {
227             lg2::info(
228                 "Terminus ID {TID} does not have a round robin sensor iteration {NOW}.",
229                 "TID", tid, "NOW", pldm::utils::getCurrentSystemTime());
230             co_return PLDM_ERROR;
231         }
232         auto& sensorIt = roundRobinSensorItMap[tid];
233 
234         while (((t1 - t0) < pollingTimeInUsec) && (toBeUpdated > 0))
235         {
236             if (!getAvailableState(tid))
237             {
238                 lg2::info(
239                     "Terminus ID {TID} is not available for PLDM request from {NOW}.",
240                     "TID", tid, "NOW", pldm::utils::getCurrentSystemTime());
241                 co_await stdexec::just_stopped();
242             }
243 
244             if (sensorIt >= numericSensors.size())
245             {
246                 sensorIt = 0;
247             }
248 
249             auto sensor = numericSensors[sensorIt];
250 
251             sd_event_now(event.get(), CLOCK_MONOTONIC, &t1);
252             elapsed = t1 - sensor->timeStamp;
253             if ((sensor->updateTime <= elapsed) || (!sensor->timeStamp))
254             {
255                 rc = co_await getSensorReading(sensor);
256 
257                 if ((!sensorPollTimers.contains(tid)) ||
258                     (sensorPollTimers[tid] &&
259                      !sensorPollTimers[tid]->isRunning()))
260                 {
261                     co_return PLDM_ERROR;
262                 }
263                 sd_event_now(event.get(), CLOCK_MONOTONIC, &t1);
264                 if (rc == PLDM_SUCCESS)
265                 {
266                     sensor->timeStamp = t1;
267                 }
268                 else
269                 {
270                     lg2::error(
271                         "Failed to get sensor value for terminus {TID}, error: {RC}",
272                         "TID", tid, "RC", rc);
273                 }
274             }
275 
276             toBeUpdated--;
277             sensorIt++;
278 
279             sd_event_now(event.get(), CLOCK_MONOTONIC, &t1);
280         }
281 
282         sd_event_now(event.get(), CLOCK_MONOTONIC, &t1);
283     } while ((t1 - t0) >= pollingTimeInUsec);
284 
285     co_return PLDM_SUCCESS;
286 }
287 
getSensorReading(std::shared_ptr<NumericSensor> sensor)288 exec::task<int> SensorManager::getSensorReading(
289     std::shared_ptr<NumericSensor> sensor)
290 {
291     if (!sensor)
292     {
293         lg2::error("Call `getSensorReading` with null `sensor` pointer.");
294         co_return PLDM_ERROR_INVALID_DATA;
295     }
296 
297     auto tid = sensor->tid;
298     auto sensorId = sensor->sensorId;
299     Request request(sizeof(pldm_msg_hdr) + PLDM_GET_SENSOR_READING_REQ_BYTES);
300     auto requestMsg = new (request.data()) pldm_msg;
301     auto rc = encode_get_sensor_reading_req(0, sensorId, false, requestMsg);
302     if (rc)
303     {
304         lg2::error(
305             "Failed to encode request GetSensorReading for terminus ID {TID}, sensor Id {ID}, error {RC}.",
306             "TID", tid, "ID", sensorId, "RC", rc);
307         co_return rc;
308     }
309 
310     if (!getAvailableState(tid))
311     {
312         lg2::info(
313             "Terminus ID {TID} is not available for PLDM request from {NOW}.",
314             "TID", tid, "NOW", pldm::utils::getCurrentSystemTime());
315         co_await stdexec::just_stopped();
316     }
317 
318     const pldm_msg* responseMsg = nullptr;
319     size_t responseLen = 0;
320     rc = co_await terminusManager.sendRecvPldmMsg(tid, request, &responseMsg,
321                                                   &responseLen);
322     if (rc)
323     {
324         lg2::error(
325             "Failed to send GetSensorReading message for terminus {TID}, sensor Id {ID}, error {RC}",
326             "TID", tid, "ID", sensorId, "RC", rc);
327         co_return rc;
328     }
329 
330     if ((!sensorPollTimers.contains(tid)) ||
331         (sensorPollTimers[tid] && !sensorPollTimers[tid]->isRunning()))
332     {
333         co_return PLDM_ERROR;
334     }
335 
336     uint8_t completionCode = PLDM_SUCCESS;
337     uint8_t sensorDataSize = PLDM_SENSOR_DATA_SIZE_SINT32;
338     uint8_t sensorOperationalState = 0;
339     uint8_t sensorEventMessageEnable = 0;
340     uint8_t presentState = 0;
341     uint8_t previousState = 0;
342     uint8_t eventState = 0;
343     union_sensor_data_size presentReading;
344     rc = decode_get_sensor_reading_resp(
345         responseMsg, responseLen, &completionCode, &sensorDataSize,
346         &sensorOperationalState, &sensorEventMessageEnable, &presentState,
347         &previousState, &eventState,
348         reinterpret_cast<uint8_t*>(&presentReading));
349     if (rc)
350     {
351         lg2::error(
352             "Failed to decode response GetSensorReading for terminus ID {TID}, sensor Id {ID}, error {RC}.",
353             "TID", tid, "ID", sensorId, "RC", rc);
354         sensor->handleErrGetSensorReading();
355         co_return rc;
356     }
357 
358     if (completionCode != PLDM_SUCCESS)
359     {
360         lg2::error(
361             "Error : GetSensorReading for terminus ID {TID}, sensor Id {ID}, complete code {CC}.",
362             "TID", tid, "ID", sensorId, "CC", completionCode);
363         co_return completionCode;
364     }
365 
366     double value = std::numeric_limits<double>::quiet_NaN();
367     switch (sensorOperationalState)
368     {
369         case PLDM_SENSOR_ENABLED:
370             break;
371         case PLDM_SENSOR_DISABLED:
372             sensor->updateReading(false, true, value);
373             co_return completionCode;
374         case PLDM_SENSOR_FAILED:
375             sensor->updateReading(true, false, value);
376             co_return completionCode;
377         case PLDM_SENSOR_UNAVAILABLE:
378         default:
379             sensor->updateReading(false, false, value);
380             co_return completionCode;
381     }
382 
383     switch (sensorDataSize)
384     {
385         case PLDM_SENSOR_DATA_SIZE_UINT8:
386             value = static_cast<double>(presentReading.value_u8);
387             break;
388         case PLDM_SENSOR_DATA_SIZE_SINT8:
389             value = static_cast<double>(presentReading.value_s8);
390             break;
391         case PLDM_SENSOR_DATA_SIZE_UINT16:
392             value = static_cast<double>(presentReading.value_u16);
393             break;
394         case PLDM_SENSOR_DATA_SIZE_SINT16:
395             value = static_cast<double>(presentReading.value_s16);
396             break;
397         case PLDM_SENSOR_DATA_SIZE_UINT32:
398             value = static_cast<double>(presentReading.value_u32);
399             break;
400         case PLDM_SENSOR_DATA_SIZE_SINT32:
401             value = static_cast<double>(presentReading.value_s32);
402             break;
403         default:
404             value = std::numeric_limits<double>::quiet_NaN();
405             break;
406     }
407 
408     sensor->updateReading(true, true, value);
409     co_return completionCode;
410 }
411 
412 } // namespace platform_mc
413 } // namespace pldm
414