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