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 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 238 exec::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(false, true, value); 323 co_return completionCode; 324 case PLDM_SENSOR_FAILED: 325 sensor->updateReading(true, false, 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 364