1 #pragma once 2 3 #include "common/utils.hpp" 4 #include "libpldmresponder/pdr.hpp" 5 #include "pdr_utils.hpp" 6 #include "pldmd/handler.hpp" 7 8 #include <libpldm/platform.h> 9 #include <libpldm/states.h> 10 11 #include <phosphor-logging/lg2.hpp> 12 13 #include <cmath> 14 #include <cstdint> 15 #include <map> 16 #include <optional> 17 18 PHOSPHOR_LOG2_USING; 19 20 namespace pldm 21 { 22 namespace responder 23 { 24 namespace platform_numeric_effecter 25 { 26 /** @brief Function to get the effecter value by PDR factor coefficient, etc. 27 * @param[in] pdr - The structure of pldm_numeric_effecter_value_pdr. 28 * @param[in] effecterValue - effecter value. 29 * @param[in] propertyType - type of the D-Bus property. 30 * 31 * @return - std::pair<int, std::optional<PropertyValue>> - rc:Success or 32 * failure, PropertyValue: The value to be set 33 */ 34 template <typename T> 35 std::pair<int, std::optional<pldm::utils::PropertyValue>> 36 getEffecterRawValue(const pldm_numeric_effecter_value_pdr* pdr, 37 T& effecterValue, std::string propertyType) 38 { 39 // X = Round [ (Y - B) / m ] 40 // refer to DSP0248_1.2.0 27.8 41 int rc = 0; 42 pldm::utils::PropertyValue value; 43 switch (pdr->effecter_data_size) 44 { 45 case PLDM_EFFECTER_DATA_SIZE_UINT8: 46 { 47 auto rawValue = static_cast<uint8_t>( 48 round(effecterValue - pdr->offset) / pdr->resolution); 49 if (pdr->min_settable.value_u8 < pdr->max_settable.value_u8 && 50 (rawValue < pdr->min_settable.value_u8 || 51 rawValue > pdr->max_settable.value_u8)) 52 { 53 rc = PLDM_ERROR_INVALID_DATA; 54 } 55 value = rawValue; 56 if (propertyType == "uint64_t") 57 { 58 auto tempValue = std::get<uint8_t>(value); 59 value = static_cast<uint64_t>(tempValue); 60 } 61 else if (propertyType == "uint32_t") 62 { 63 auto tempValue = std::get<uint8_t>(value); 64 value = static_cast<uint32_t>(tempValue); 65 } 66 break; 67 } 68 case PLDM_EFFECTER_DATA_SIZE_SINT8: 69 { 70 auto rawValue = static_cast<int8_t>( 71 round(effecterValue - pdr->offset) / pdr->resolution); 72 if (pdr->min_settable.value_s8 < pdr->max_settable.value_s8 && 73 (rawValue < pdr->min_settable.value_s8 || 74 rawValue > pdr->max_settable.value_s8)) 75 { 76 rc = PLDM_ERROR_INVALID_DATA; 77 } 78 value = rawValue; 79 break; 80 } 81 case PLDM_EFFECTER_DATA_SIZE_UINT16: 82 { 83 auto rawValue = static_cast<uint16_t>( 84 round(effecterValue - pdr->offset) / pdr->resolution); 85 if (pdr->min_settable.value_u16 < pdr->max_settable.value_u16 && 86 (rawValue < pdr->min_settable.value_u16 || 87 rawValue > pdr->max_settable.value_u16)) 88 { 89 rc = PLDM_ERROR_INVALID_DATA; 90 } 91 value = rawValue; 92 if (propertyType == "uint64_t") 93 { 94 auto tempValue = std::get<uint16_t>(value); 95 value = static_cast<uint64_t>(tempValue); 96 } 97 else if (propertyType == "uint32_t") 98 { 99 auto tempValue = std::get<uint16_t>(value); 100 value = static_cast<uint32_t>(tempValue); 101 } 102 break; 103 } 104 case PLDM_EFFECTER_DATA_SIZE_SINT16: 105 { 106 auto rawValue = static_cast<int16_t>( 107 round(effecterValue - pdr->offset) / pdr->resolution); 108 if (pdr->min_settable.value_s16 < pdr->max_settable.value_s16 && 109 (rawValue < pdr->min_settable.value_s16 || 110 rawValue > pdr->max_settable.value_s16)) 111 { 112 rc = PLDM_ERROR_INVALID_DATA; 113 } 114 value = rawValue; 115 if (propertyType == "uint64_t") 116 { 117 auto tempValue = std::get<int16_t>(value); 118 value = static_cast<uint64_t>(tempValue); 119 } 120 else if (propertyType == "uint32_t") 121 { 122 auto tempValue = std::get<int16_t>(value); 123 value = static_cast<uint32_t>(tempValue); 124 } 125 break; 126 } 127 case PLDM_EFFECTER_DATA_SIZE_UINT32: 128 { 129 auto rawValue = static_cast<uint32_t>( 130 round(effecterValue - pdr->offset) / pdr->resolution); 131 if (pdr->min_settable.value_u32 < pdr->max_settable.value_u32 && 132 (rawValue < pdr->min_settable.value_u32 || 133 rawValue > pdr->max_settable.value_u32)) 134 { 135 rc = PLDM_ERROR_INVALID_DATA; 136 } 137 value = rawValue; 138 if (propertyType == "uint64_t") 139 { 140 auto tempValue = std::get<uint32_t>(value); 141 value = static_cast<uint64_t>(tempValue); 142 } 143 else if (propertyType == "uint32_t") 144 { 145 auto tempValue = std::get<uint32_t>(value); 146 value = static_cast<uint32_t>(tempValue); 147 } 148 break; 149 } 150 case PLDM_EFFECTER_DATA_SIZE_SINT32: 151 { 152 auto rawValue = static_cast<int32_t>( 153 round(effecterValue - pdr->offset) / pdr->resolution); 154 if (pdr->min_settable.value_s32 < pdr->max_settable.value_s32 && 155 (rawValue < pdr->min_settable.value_s32 || 156 rawValue > pdr->max_settable.value_s32)) 157 { 158 rc = PLDM_ERROR_INVALID_DATA; 159 } 160 value = rawValue; 161 if (propertyType == "uint64_t") 162 { 163 auto tempValue = std::get<int32_t>(value); 164 value = static_cast<uint64_t>(tempValue); 165 } 166 else if (propertyType == "uint32_t") 167 { 168 auto tempValue = std::get<int32_t>(value); 169 value = static_cast<uint32_t>(tempValue); 170 } 171 break; 172 } 173 } 174 175 return {rc, std::make_optional(std::move(value))}; 176 } 177 178 /** @brief Function to convert the D-Bus value by PDR factor and effecter value. 179 * @param[in] pdr - The structure of pldm_numeric_effecter_value_pdr. 180 * @param[in] effecterDataSize - effecter value size. 181 * @param[in,out] effecterValue - effecter value. 182 * @param[in] propertyType - type of the D-Bus property. 183 * 184 * @return std::pair<int, std::optional<PropertyValue>> - rc:Success or 185 * failure, PropertyValue: The value to be set 186 */ 187 std::pair<int, std::optional<pldm::utils::PropertyValue>> convertToDbusValue( 188 const pldm_numeric_effecter_value_pdr* pdr, uint8_t effecterDataSize, 189 uint8_t* effecterValue, std::string propertyType) 190 { 191 if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_UINT8) 192 { 193 uint8_t currentValue = *(reinterpret_cast<uint8_t*>(&effecterValue[0])); 194 return getEffecterRawValue<uint8_t>(pdr, currentValue, propertyType); 195 } 196 else if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_SINT8) 197 { 198 int8_t currentValue = *(reinterpret_cast<int8_t*>(&effecterValue[0])); 199 return getEffecterRawValue<int8_t>(pdr, currentValue, propertyType); 200 } 201 else if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_UINT16) 202 { 203 uint16_t currentValue = 204 *(reinterpret_cast<uint16_t*>(&effecterValue[0])); 205 return getEffecterRawValue<uint16_t>(pdr, currentValue, propertyType); 206 } 207 else if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_SINT16) 208 { 209 int16_t currentValue = *(reinterpret_cast<int16_t*>(&effecterValue[0])); 210 return getEffecterRawValue<int16_t>(pdr, currentValue, propertyType); 211 } 212 else if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_UINT32) 213 { 214 uint32_t currentValue = 215 *(reinterpret_cast<uint32_t*>(&effecterValue[0])); 216 return getEffecterRawValue<uint32_t>(pdr, currentValue, propertyType); 217 } 218 else if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_SINT32) 219 { 220 int32_t currentValue = *(reinterpret_cast<int32_t*>(&effecterValue[0])); 221 return getEffecterRawValue<int32_t>(pdr, currentValue, propertyType); 222 } 223 else 224 { 225 error("Unknown Effecter Size {SIZE}", "SIZE", effecterDataSize); 226 return {PLDM_ERROR, {}}; 227 } 228 } 229 230 /** @brief Function to set the effecter value requested by pldm requester 231 * @tparam[in] DBusInterface - DBus interface type 232 * @tparam[in] Handler - pldm::responder::platform::Handler 233 * @param[in] dBusIntf - The interface object of DBusInterface 234 * @param[in] handler - The interface object of 235 * pldm::responder::platform::Handler 236 * @param[in] effecterId - Effecter ID sent by the requester to act on 237 * @param[in] effecterDataSize - The bit width and format of the setting 238 * value for the effecter 239 * @param[in] effecter_value - The setting value of numeric effecter being 240 * requested. 241 * @param[in] effecterValueLength - The setting value length of numeric 242 * effecter being requested. 243 * @return - Success or failure in setting the states. Returns failure in 244 * terms of PLDM completion codes if at least one state fails to be set 245 */ 246 template <class DBusInterface, class Handler> 247 int setNumericEffecterValueHandler( 248 const DBusInterface& dBusIntf, Handler& handler, uint16_t effecterId, 249 uint8_t effecterDataSize, uint8_t* effecterValue, 250 size_t effecterValueLength) 251 { 252 constexpr auto effecterValueArrayLength = 4; 253 pldm_numeric_effecter_value_pdr* pdr = nullptr; 254 255 std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> 256 numericEffecterPdrRepo(pldm_pdr_init(), pldm_pdr_destroy); 257 if (!numericEffecterPdrRepo) 258 { 259 error("Failed to instantiate numeric effecter PDR repository"); 260 return PLDM_ERROR; 261 } 262 pldm::responder::pdr_utils::Repo numericEffecterPDRs( 263 numericEffecterPdrRepo.get()); 264 pldm::responder::pdr::getRepoByType(handler.getRepo(), numericEffecterPDRs, 265 PLDM_NUMERIC_EFFECTER_PDR); 266 if (numericEffecterPDRs.empty()) 267 { 268 error("The Numeric Effecter PDR repo is empty."); 269 return PLDM_ERROR; 270 } 271 272 // Get the pdr structure of pldm_numeric_effecter_value_pdr according 273 // to the effecterId 274 pldm::responder::pdr_utils::PdrEntry pdrEntry{}; 275 auto pdrRecord = numericEffecterPDRs.getFirstRecord(pdrEntry); 276 while (pdrRecord) 277 { 278 pdr = reinterpret_cast<pldm_numeric_effecter_value_pdr*>(pdrEntry.data); 279 if (pdr->effecter_id != effecterId) 280 { 281 pdr = nullptr; 282 pdrRecord = numericEffecterPDRs.getNextRecord(pdrRecord, pdrEntry); 283 continue; 284 } 285 286 break; 287 } 288 289 if (!pdr) 290 { 291 return PLDM_PLATFORM_INVALID_EFFECTER_ID; 292 } 293 294 if (effecterValueLength != effecterValueArrayLength) 295 { 296 error("Incorrect effecter data size {SIZE}", "SIZE", 297 effecterValueLength); 298 return PLDM_ERROR_INVALID_DATA; 299 } 300 301 try 302 { 303 const auto& [dbusMappings, dbusValMaps] = 304 handler.getDbusObjMaps(effecterId); 305 pldm::utils::DBusMapping dbusMapping{ 306 dbusMappings[0].objectPath, dbusMappings[0].interface, 307 dbusMappings[0].propertyName, dbusMappings[0].propertyType}; 308 309 // convert to dbus effectervalue according to the factor 310 auto [rc, dbusValue] = convertToDbusValue( 311 pdr, effecterDataSize, effecterValue, dbusMappings[0].propertyType); 312 if (rc != PLDM_SUCCESS) 313 { 314 return rc; 315 } 316 try 317 { 318 dBusIntf.setDbusProperty(dbusMapping, dbusValue.value()); 319 } 320 catch (const std::exception& e) 321 { 322 error( 323 "Failed to set property '{PROPERTY}', interface '{INTERFACE}' and path '{PATH}', error - {ERROR}", 324 "PROPERTY", dbusMapping.propertyName, "INTERFACE", 325 dbusMapping.interface, "PATH", dbusMapping.objectPath, "ERROR", 326 e); 327 return PLDM_ERROR; 328 } 329 } 330 catch (const std::out_of_range& e) 331 { 332 error("Unknown effecter ID '{EFFECTERID}', error - {ERROR}", 333 "EFFECTERID", effecterId, "ERROR", e); 334 return PLDM_ERROR; 335 } 336 337 return PLDM_SUCCESS; 338 } 339 340 /** @brief Function to convert the D-Bus value based on effecter data size 341 * and create the response for getNumericEffecterValue request. 342 * @param[in] PropertyValue - D-Bus Value 343 * @param[in] effecterDataSize - effecter value size. 344 * @param[in,out] responsePtr - Response of getNumericEffecterValue. 345 * @param[in] responsePayloadLength - response length. 346 * @param[in] instanceId - instance id for response 347 * 348 * @return PLDM_SUCCESS/PLDM_ERROR 349 */ 350 template <typename T> 351 int getEffecterValue(T propertyValue, uint8_t effecterDataSize, 352 pldm_msg* responsePtr, size_t responsePayloadLength, 353 uint8_t instanceId) 354 { 355 switch (effecterDataSize) 356 { 357 case PLDM_EFFECTER_DATA_SIZE_UINT8: 358 { 359 uint8_t value = static_cast<uint8_t>(propertyValue); 360 return (encode_get_numeric_effecter_value_resp( 361 instanceId, PLDM_SUCCESS, effecterDataSize, 362 EFFECTER_OPER_STATE_ENABLED_NOUPDATEPENDING, &value, &value, 363 responsePtr, responsePayloadLength)); 364 } 365 case PLDM_EFFECTER_DATA_SIZE_SINT8: 366 { 367 int8_t value = static_cast<int8_t>(propertyValue); 368 return (encode_get_numeric_effecter_value_resp( 369 instanceId, PLDM_SUCCESS, effecterDataSize, 370 EFFECTER_OPER_STATE_ENABLED_NOUPDATEPENDING, 371 reinterpret_cast<uint8_t*>(&value), 372 reinterpret_cast<uint8_t*>(&value), responsePtr, 373 responsePayloadLength)); 374 } 375 case PLDM_EFFECTER_DATA_SIZE_UINT16: 376 { 377 uint16_t value = static_cast<uint16_t>(propertyValue); 378 return (encode_get_numeric_effecter_value_resp( 379 instanceId, PLDM_SUCCESS, effecterDataSize, 380 EFFECTER_OPER_STATE_ENABLED_NOUPDATEPENDING, 381 reinterpret_cast<uint8_t*>(&value), 382 reinterpret_cast<uint8_t*>(&value), responsePtr, 383 responsePayloadLength)); 384 } 385 case PLDM_EFFECTER_DATA_SIZE_SINT16: 386 { 387 int16_t value = static_cast<int16_t>(propertyValue); 388 return (encode_get_numeric_effecter_value_resp( 389 instanceId, PLDM_SUCCESS, effecterDataSize, 390 EFFECTER_OPER_STATE_ENABLED_NOUPDATEPENDING, 391 reinterpret_cast<uint8_t*>(&value), 392 reinterpret_cast<uint8_t*>(&value), responsePtr, 393 responsePayloadLength)); 394 } 395 case PLDM_EFFECTER_DATA_SIZE_UINT32: 396 { 397 uint32_t value = static_cast<uint32_t>(propertyValue); 398 return (encode_get_numeric_effecter_value_resp( 399 instanceId, PLDM_SUCCESS, effecterDataSize, 400 EFFECTER_OPER_STATE_ENABLED_NOUPDATEPENDING, 401 reinterpret_cast<uint8_t*>(&value), 402 reinterpret_cast<uint8_t*>(&value), responsePtr, 403 responsePayloadLength)); 404 } 405 case PLDM_EFFECTER_DATA_SIZE_SINT32: 406 { 407 int32_t value = static_cast<int32_t>(propertyValue); 408 return (encode_get_numeric_effecter_value_resp( 409 instanceId, PLDM_SUCCESS, effecterDataSize, 410 EFFECTER_OPER_STATE_ENABLED_NOUPDATEPENDING, 411 reinterpret_cast<uint8_t*>(&value), 412 reinterpret_cast<uint8_t*>(&value), responsePtr, 413 responsePayloadLength)); 414 } 415 default: 416 { 417 error("Unknown Effecter Size {SIZE}", "SIZE", effecterDataSize); 418 return PLDM_ERROR; 419 } 420 } 421 } 422 423 /** @brief Function to convert the D-Bus value to the effector data size value 424 * @param[in] PropertyType - String contains the dataType of the Dbus value. 425 * @param[in] PropertyValue - Variant contains the D-Bus Value 426 * @param[in] effecterDataSize - effecter value size. 427 * @param[in,out] responsePtr - Response of getNumericEffecterValue. 428 * @param[in] responsePayloadLength - response length. 429 * @param[in] instanceId - instance id for response 430 * 431 * @return PLDM_SUCCESS/PLDM_ERROR 432 */ 433 int getNumericEffecterValueHandler( 434 const std::string& propertyType, pldm::utils::PropertyValue propertyValue, 435 uint8_t effecterDataSize, pldm_msg* responsePtr, 436 size_t responsePayloadLength, uint8_t instanceId) 437 { 438 if (propertyType == "uint8_t") 439 { 440 uint8_t propVal = std::get<uint8_t>(propertyValue); 441 return getEffecterValue<uint8_t>(propVal, effecterDataSize, responsePtr, 442 responsePayloadLength, instanceId); 443 } 444 else if (propertyType == "uint16_t") 445 { 446 uint16_t propVal = std::get<uint16_t>(propertyValue); 447 return getEffecterValue<uint16_t>(propVal, effecterDataSize, 448 responsePtr, responsePayloadLength, 449 instanceId); 450 } 451 else if (propertyType == "uint32_t") 452 { 453 uint32_t propVal = std::get<uint32_t>(propertyValue); 454 return getEffecterValue<uint32_t>(propVal, effecterDataSize, 455 responsePtr, responsePayloadLength, 456 instanceId); 457 } 458 else if (propertyType == "uint64_t") 459 { 460 uint64_t propVal = std::get<uint64_t>(propertyValue); 461 return getEffecterValue<uint64_t>(propVal, effecterDataSize, 462 responsePtr, responsePayloadLength, 463 instanceId); 464 } 465 else 466 { 467 error("Property type '{TYPE}' not supported", "TYPE", propertyType); 468 } 469 return PLDM_ERROR; 470 } 471 472 /** @brief Function to get the effecter details as data size, D-Bus property 473 * type, D-Bus Value 474 * @tparam[in] DBusInterface - DBus interface type 475 * @tparam[in] Handler - pldm::responder::platform::Handler 476 * @param[in] dBusIntf - The interface object of DBusInterface 477 * @param[in] handler - The interface object of 478 * pldm::responder::platform::Handler 479 * @param[in] effecterId - Effecter ID sent by the requester to act on 480 * @param[in] effecterDataSize - The bit width and format of the setting 481 * value for the effecter 482 * @param[in] propertyType - The data type of the D-Bus value 483 * @param[in] propertyValue - The value of numeric effecter being 484 * requested. 485 * @return - Success or failure in getting the D-Bus property or the 486 * effecterId not found in the PDR repo 487 */ 488 template <class DBusInterface, class Handler> 489 int getNumericEffecterData(const DBusInterface& dBusIntf, Handler& handler, 490 uint16_t effecterId, uint8_t& effecterDataSize, 491 std::string& propertyType, 492 pldm::utils::PropertyValue& propertyValue) 493 { 494 pldm_numeric_effecter_value_pdr* pdr = nullptr; 495 496 std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> 497 numericEffecterPdrRepo(pldm_pdr_init(), pldm_pdr_destroy); 498 pldm::responder::pdr_utils::Repo numericEffecterPDRs( 499 numericEffecterPdrRepo.get()); 500 pldm::responder::pdr::getRepoByType(handler.getRepo(), numericEffecterPDRs, 501 PLDM_NUMERIC_EFFECTER_PDR); 502 if (numericEffecterPDRs.empty()) 503 { 504 error("The Numeric Effecter PDR repo is empty."); 505 return PLDM_ERROR; 506 } 507 508 // Get the pdr structure of pldm_numeric_effecter_value_pdr according 509 // to the effecterId 510 pldm::responder::pdr_utils::PdrEntry pdrEntry{}; 511 auto pdrRecord = numericEffecterPDRs.getFirstRecord(pdrEntry); 512 513 while (pdrRecord) 514 { 515 pdr = reinterpret_cast<pldm_numeric_effecter_value_pdr*>(pdrEntry.data); 516 if (pdr->effecter_id != effecterId) 517 { 518 pdr = nullptr; 519 pdrRecord = numericEffecterPDRs.getNextRecord(pdrRecord, pdrEntry); 520 continue; 521 } 522 effecterDataSize = pdr->effecter_data_size; 523 break; 524 } 525 526 if (!pdr) 527 { 528 error("Failed to find numeric effecter ID {EFFECTERID}", "EFFECTERID", 529 effecterId); 530 return PLDM_PLATFORM_INVALID_EFFECTER_ID; 531 } 532 533 pldm::utils::DBusMapping dbusMapping{}; 534 try 535 { 536 const auto& [dbusMappings, dbusValMaps] = 537 handler.getDbusObjMaps(effecterId); 538 if (dbusMappings.size() > 0) 539 { 540 dbusMapping = { 541 dbusMappings[0].objectPath, dbusMappings[0].interface, 542 dbusMappings[0].propertyName, dbusMappings[0].propertyType}; 543 544 propertyValue = dBusIntf.getDbusPropertyVariant( 545 dbusMapping.objectPath.c_str(), 546 dbusMapping.propertyName.c_str(), 547 dbusMapping.interface.c_str()); 548 propertyType = dbusMappings[0].propertyType; 549 } 550 } 551 catch (const std::exception& e) 552 { 553 error( 554 "Failed to do dbus mapping or the dbus query for the effecter ID '{EFFECTERID}', error - {ERROR}", 555 "EFFECTERID", effecterId, "ERROR", e); 556 error( 557 "Dbus Details path [{PATH}], interface [{INTERFACE}] and property [{PROPERTY}]", 558 "PATH", dbusMapping.objectPath, "INTERFACE", dbusMapping.interface, 559 "PROPERTY", dbusMapping.propertyName); 560 return PLDM_ERROR; 561 } 562 563 return PLDM_SUCCESS; 564 } 565 566 } // namespace platform_numeric_effecter 567 } // namespace responder 568 } // namespace pldm 569