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