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