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