blob: 74e304387bb44985d335603a63c2bab1149da009 [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
184 sd_event_now(event.get(), CLOCK_MONOTONIC, &t1);
185 auto toBeUpdated = roundRobinSensors[tid].size();
186 while (((t1 - t0) < pollingTimeInUsec) && (toBeUpdated > 0))
187 {
188 if (!getAvailableState(tid))
189 {
190 lg2::info(
191 "Terminus ID {TID} is not available for PLDM request from {NOW}.",
192 "TID", tid, "NOW", pldm::utils::getCurrentSystemTime());
193 co_await stdexec::just_stopped();
194 }
195
196 auto sensor = roundRobinSensors[tid].front();
197
198 sd_event_now(event.get(), CLOCK_MONOTONIC, &t1);
199 elapsed = t1 - sensor->timeStamp;
200 if ((sensor->updateTime <= elapsed) || (!sensor->timeStamp))
201 {
202 rc = co_await getSensorReading(sensor);
203
204 if ((!sensorPollTimers.contains(tid)) ||
205 (sensorPollTimers[tid] &&
206 !sensorPollTimers[tid]->isRunning()))
207 {
208 co_return PLDM_ERROR;
209 }
210 sd_event_now(event.get(), CLOCK_MONOTONIC, &t1);
211 if (rc == PLDM_SUCCESS)
212 {
213 sensor->timeStamp = t1;
214 }
215 else
216 {
217 lg2::error(
218 "Failed to get sensor value for terminus {TID}, error: {RC}",
219 "TID", tid, "RC", rc);
220 }
221 }
222
223 toBeUpdated--;
224 if (roundRobinSensors.contains(tid))
225 {
226 roundRobinSensors[tid].pop();
227 roundRobinSensors[tid].push(std::move(sensor));
228 }
229 sd_event_now(event.get(), CLOCK_MONOTONIC, &t1);
230 }
231
232 sd_event_now(event.get(), CLOCK_MONOTONIC, &t1);
233 } while ((t1 - t0) >= pollingTimeInUsec);
234
235 co_return PLDM_SUCCESS;
236}
237
238exec::task<int>
239 SensorManager::getSensorReading(std::shared_ptr<NumericSensor> sensor)
240{
241 if (!sensor)
242 {
243 lg2::error("Call `getSensorReading` with null `sensor` pointer.");
244 co_return PLDM_ERROR_INVALID_DATA;
245 }
246
247 auto tid = sensor->tid;
248 auto sensorId = sensor->sensorId;
249 Request request(sizeof(pldm_msg_hdr) + PLDM_GET_SENSOR_READING_REQ_BYTES);
250 auto requestMsg = reinterpret_cast<pldm_msg*>(request.data());
251 auto rc = encode_get_sensor_reading_req(0, sensorId, false, requestMsg);
252 if (rc)
253 {
254 lg2::error(
255 "Failed to encode request GetSensorReading for terminus ID {TID}, sensor Id {ID}, error {RC}.",
256 "TID", tid, "ID", sensorId, "RC", rc);
257 co_return rc;
258 }
259
260 if (!getAvailableState(tid))
261 {
262 lg2::info(
263 "Terminus ID {TID} is not available for PLDM request from {NOW}.",
264 "TID", tid, "NOW", pldm::utils::getCurrentSystemTime());
265 co_await stdexec::just_stopped();
266 }
267
268 const pldm_msg* responseMsg = nullptr;
269 size_t responseLen = 0;
270 rc = co_await terminusManager.sendRecvPldmMsg(tid, request, &responseMsg,
271 &responseLen);
272 if (rc)
273 {
274 lg2::error(
275 "Failed to send GetSensorReading message for terminus {TID}, sensor Id {ID}, error {RC}",
276 "TID", tid, "ID", sensorId, "RC", rc);
277 co_return rc;
278 }
279
280 if ((!sensorPollTimers.contains(tid)) ||
281 (sensorPollTimers[tid] && !sensorPollTimers[tid]->isRunning()))
282 {
283 co_return PLDM_ERROR;
284 }
285
286 uint8_t completionCode = PLDM_SUCCESS;
287 uint8_t sensorDataSize = PLDM_SENSOR_DATA_SIZE_SINT32;
288 uint8_t sensorOperationalState = 0;
289 uint8_t sensorEventMessageEnable = 0;
290 uint8_t presentState = 0;
291 uint8_t previousState = 0;
292 uint8_t eventState = 0;
293 union_sensor_data_size presentReading;
294 rc = decode_get_sensor_reading_resp(
295 responseMsg, responseLen, &completionCode, &sensorDataSize,
296 &sensorOperationalState, &sensorEventMessageEnable, &presentState,
297 &previousState, &eventState,
298 reinterpret_cast<uint8_t*>(&presentReading));
299 if (rc)
300 {
301 lg2::error(
302 "Failed to decode response GetSensorReading for terminus ID {TID}, sensor Id {ID}, error {RC}.",
303 "TID", tid, "ID", sensorId, "RC", rc);
304 sensor->handleErrGetSensorReading();
305 co_return rc;
306 }
307
308 if (completionCode != PLDM_SUCCESS)
309 {
310 lg2::error(
311 "Error : GetSensorReading for terminus ID {TID}, sensor Id {ID}, complete code {CC}.",
312 "TID", tid, "ID", sensorId, "CC", completionCode);
313 co_return completionCode;
314 }
315
316 double value = std::numeric_limits<double>::quiet_NaN();
317 switch (sensorOperationalState)
318 {
319 case PLDM_SENSOR_ENABLED:
320 break;
321 case PLDM_SENSOR_DISABLED:
322 sensor->updateReading(true, false, value);
323 co_return completionCode;
324 case PLDM_SENSOR_FAILED:
325 sensor->updateReading(false, true, value);
326 co_return completionCode;
327 case PLDM_SENSOR_UNAVAILABLE:
328 default:
329 sensor->updateReading(false, false, value);
330 co_return completionCode;
331 }
332
333 switch (sensorDataSize)
334 {
335 case PLDM_SENSOR_DATA_SIZE_UINT8:
336 value = static_cast<double>(presentReading.value_u8);
337 break;
338 case PLDM_SENSOR_DATA_SIZE_SINT8:
339 value = static_cast<double>(presentReading.value_s8);
340 break;
341 case PLDM_SENSOR_DATA_SIZE_UINT16:
342 value = static_cast<double>(presentReading.value_u16);
343 break;
344 case PLDM_SENSOR_DATA_SIZE_SINT16:
345 value = static_cast<double>(presentReading.value_s16);
346 break;
347 case PLDM_SENSOR_DATA_SIZE_UINT32:
348 value = static_cast<double>(presentReading.value_u32);
349 break;
350 case PLDM_SENSOR_DATA_SIZE_SINT32:
351 value = static_cast<double>(presentReading.value_s32);
352 break;
353 default:
354 value = std::numeric_limits<double>::quiet_NaN();
355 break;
356 }
357
358 sensor->updateReading(true, true, value);
359 co_return completionCode;
360}
361
362} // namespace platform_mc
363} // namespace pldm