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 #include <math.h> 11 #include <stdint.h> 12 13 #include <phosphor-logging/lg2.hpp> 14 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>> 188 convertToDbusValue(const pldm_numeric_effecter_value_pdr* pdr, 189 uint8_t effecterDataSize, uint8_t* effecterValue, 190 std::string propertyType) 191 { 192 if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_UINT8) 193 { 194 uint8_t currentValue = *(reinterpret_cast<uint8_t*>(&effecterValue[0])); 195 return getEffecterRawValue<uint8_t>(pdr, currentValue, propertyType); 196 } 197 else if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_SINT8) 198 { 199 int8_t currentValue = *(reinterpret_cast<int8_t*>(&effecterValue[0])); 200 return getEffecterRawValue<int8_t>(pdr, currentValue, propertyType); 201 } 202 else if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_UINT16) 203 { 204 uint16_t currentValue = 205 *(reinterpret_cast<uint16_t*>(&effecterValue[0])); 206 return getEffecterRawValue<uint16_t>(pdr, currentValue, propertyType); 207 } 208 else if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_SINT16) 209 { 210 int16_t currentValue = *(reinterpret_cast<int16_t*>(&effecterValue[0])); 211 return getEffecterRawValue<int16_t>(pdr, currentValue, propertyType); 212 } 213 else if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_UINT32) 214 { 215 uint32_t currentValue = 216 *(reinterpret_cast<uint32_t*>(&effecterValue[0])); 217 return getEffecterRawValue<uint32_t>(pdr, currentValue, propertyType); 218 } 219 else if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_SINT32) 220 { 221 int32_t currentValue = *(reinterpret_cast<int32_t*>(&effecterValue[0])); 222 return getEffecterRawValue<int32_t>(pdr, currentValue, propertyType); 223 } 224 else 225 { 226 error("Wrong field effecterDataSize..."); 227 return {PLDM_ERROR, {}}; 228 } 229 } 230 231 /** @brief Function to set the effecter value requested by pldm requester 232 * @tparam[in] DBusInterface - DBus interface type 233 * @tparam[in] Handler - pldm::responder::platform::Handler 234 * @param[in] dBusIntf - The interface object of DBusInterface 235 * @param[in] handler - The interface object of 236 * pldm::responder::platform::Handler 237 * @param[in] effecterId - Effecter ID sent by the requester to act on 238 * @param[in] effecterDataSize - The bit width and format of the setting 239 * value for the effecter 240 * @param[in] effecter_value - The setting value of numeric effecter being 241 * requested. 242 * @param[in] effecterValueLength - The setting value length of numeric 243 * effecter being requested. 244 * @return - Success or failure in setting the states. Returns failure in 245 * terms of PLDM completion codes if atleast one state fails to be set 246 */ 247 template <class DBusInterface, class Handler> 248 int setNumericEffecterValueHandler(const DBusInterface& dBusIntf, 249 Handler& handler, uint16_t effecterId, 250 uint8_t effecterDataSize, 251 uint8_t* effecterValue, 252 size_t effecterValueLength) 253 { 254 constexpr auto effecterValueArrayLength = 4; 255 pldm_numeric_effecter_value_pdr* pdr = nullptr; 256 257 std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> 258 numericEffecterPdrRepo(pldm_pdr_init(), pldm_pdr_destroy); 259 if (!numericEffecterPdrRepo) 260 { 261 error("Failed to instantiate numeric effecter PDR repository"); 262 return PLDM_ERROR; 263 } 264 pldm::responder::pdr_utils::Repo numericEffecterPDRs( 265 numericEffecterPdrRepo.get()); 266 pldm::responder::pdr::getRepoByType(handler.getRepo(), numericEffecterPDRs, 267 PLDM_NUMERIC_EFFECTER_PDR); 268 if (numericEffecterPDRs.empty()) 269 { 270 error("The Numeric Effecter PDR repo is empty."); 271 return PLDM_ERROR; 272 } 273 274 // Get the pdr structure of pldm_numeric_effecter_value_pdr according 275 // to the effecterId 276 pldm::responder::pdr_utils::PdrEntry pdrEntry{}; 277 auto pdrRecord = numericEffecterPDRs.getFirstRecord(pdrEntry); 278 while (pdrRecord) 279 { 280 pdr = reinterpret_cast<pldm_numeric_effecter_value_pdr*>(pdrEntry.data); 281 if (pdr->effecter_id != effecterId) 282 { 283 pdr = nullptr; 284 pdrRecord = numericEffecterPDRs.getNextRecord(pdrRecord, pdrEntry); 285 continue; 286 } 287 288 break; 289 } 290 291 if (!pdr) 292 { 293 return PLDM_PLATFORM_INVALID_EFFECTER_ID; 294 } 295 296 if (effecterValueLength != effecterValueArrayLength) 297 { 298 error("effecter data size is incorrect."); 299 return PLDM_ERROR_INVALID_DATA; 300 } 301 302 try 303 { 304 const auto& [dbusMappings, 305 dbusValMaps] = handler.getDbusObjMaps(effecterId); 306 pldm::utils::DBusMapping dbusMapping{ 307 dbusMappings[0].objectPath, dbusMappings[0].interface, 308 dbusMappings[0].propertyName, dbusMappings[0].propertyType}; 309 310 // convert to dbus effectervalue according to the factor 311 auto [rc, dbusValue] = convertToDbusValue( 312 pdr, effecterDataSize, effecterValue, dbusMappings[0].propertyType); 313 if (rc != PLDM_SUCCESS) 314 { 315 return rc; 316 } 317 try 318 { 319 dBusIntf.setDbusProperty(dbusMapping, dbusValue.value()); 320 } 321 catch (const std::exception& e) 322 { 323 error( 324 "Error setting property, ERROR={ERR_EXCEP} PROPERTY={DBUS_PROP} INTERFACE={DBUS_INTF} PATH={DBUS_OBJ_PATH}", 325 "ERR_EXCEP", e.what(), "DBUS_PROP", dbusMapping.propertyName, 326 "DBUS_INTF", dbusMapping.interface, "DBUS_OBJ_PATH", 327 dbusMapping.objectPath.c_str()); 328 return PLDM_ERROR; 329 } 330 } 331 catch (const std::out_of_range& e) 332 { 333 error("Unknown effecter ID : {EFFECTER_ID} {ERR_EXCEP}", "EFFECTER_ID", 334 effecterId, "ERR_EXCEP", e.what()); 335 return PLDM_ERROR; 336 } 337 338 return PLDM_SUCCESS; 339 } 340 341 /** @brief Function to convert the D-Bus value based on effecter data size 342 * and create the response for getNumericEffecterValue request. 343 * @param[in] PropertyValue - D-Bus Value 344 * @param[in] effecterDataSize - effecter value size. 345 * @param[in,out] responsePtr - Response of getNumericEffecterValue. 346 * @param[in] responsePayloadLength - reponse length. 347 * @param[in] instanceId - instance id for response 348 * 349 * @return PLDM_SUCCESS/PLDM_ERROR 350 */ 351 template <typename T> 352 int getEffecterValue(T propertyValue, uint8_t effecterDataSize, 353 pldm_msg* responsePtr, size_t responsePayloadLength, 354 uint8_t instanceId) 355 { 356 switch (effecterDataSize) 357 { 358 case PLDM_EFFECTER_DATA_SIZE_UINT8: 359 { 360 uint8_t value = static_cast<uint8_t>(propertyValue); 361 return (encode_get_numeric_effecter_value_resp( 362 instanceId, PLDM_SUCCESS, effecterDataSize, 363 EFFECTER_OPER_STATE_ENABLED_NOUPDATEPENDING, &value, &value, 364 responsePtr, responsePayloadLength)); 365 } 366 case PLDM_EFFECTER_DATA_SIZE_SINT8: 367 { 368 int8_t value = static_cast<int8_t>(propertyValue); 369 return (encode_get_numeric_effecter_value_resp( 370 instanceId, PLDM_SUCCESS, effecterDataSize, 371 EFFECTER_OPER_STATE_ENABLED_NOUPDATEPENDING, 372 reinterpret_cast<uint8_t*>(&value), 373 reinterpret_cast<uint8_t*>(&value), responsePtr, 374 responsePayloadLength)); 375 } 376 case PLDM_EFFECTER_DATA_SIZE_UINT16: 377 { 378 uint16_t value = static_cast<uint16_t>(propertyValue); 379 return (encode_get_numeric_effecter_value_resp( 380 instanceId, PLDM_SUCCESS, effecterDataSize, 381 EFFECTER_OPER_STATE_ENABLED_NOUPDATEPENDING, 382 reinterpret_cast<uint8_t*>(&value), 383 reinterpret_cast<uint8_t*>(&value), responsePtr, 384 responsePayloadLength)); 385 } 386 case PLDM_EFFECTER_DATA_SIZE_SINT16: 387 { 388 int16_t value = static_cast<int16_t>(propertyValue); 389 return (encode_get_numeric_effecter_value_resp( 390 instanceId, PLDM_SUCCESS, effecterDataSize, 391 EFFECTER_OPER_STATE_ENABLED_NOUPDATEPENDING, 392 reinterpret_cast<uint8_t*>(&value), 393 reinterpret_cast<uint8_t*>(&value), responsePtr, 394 responsePayloadLength)); 395 } 396 case PLDM_EFFECTER_DATA_SIZE_UINT32: 397 { 398 uint32_t value = static_cast<uint32_t>(propertyValue); 399 return (encode_get_numeric_effecter_value_resp( 400 instanceId, PLDM_SUCCESS, effecterDataSize, 401 EFFECTER_OPER_STATE_ENABLED_NOUPDATEPENDING, 402 reinterpret_cast<uint8_t*>(&value), 403 reinterpret_cast<uint8_t*>(&value), responsePtr, 404 responsePayloadLength)); 405 } 406 case PLDM_EFFECTER_DATA_SIZE_SINT32: 407 { 408 int32_t value = static_cast<int32_t>(propertyValue); 409 return (encode_get_numeric_effecter_value_resp( 410 instanceId, PLDM_SUCCESS, effecterDataSize, 411 EFFECTER_OPER_STATE_ENABLED_NOUPDATEPENDING, 412 reinterpret_cast<uint8_t*>(&value), 413 reinterpret_cast<uint8_t*>(&value), responsePtr, 414 responsePayloadLength)); 415 } 416 default: 417 { 418 error("Unknown Effecter Size"); 419 return PLDM_ERROR; 420 } 421 } 422 } 423 424 /** @brief Function to convert the D-Bus value to the effector data size value 425 * @param[in] PropertyType - String contains the dataType of the Dbus value. 426 * @param[in] PropertyValue - Variant contains the D-Bus Value 427 * @param[in] effecterDataSize - effecter value size. 428 * @param[in,out] responsePtr - Response of getNumericEffecterValue. 429 * @param[in] responsePayloadLength - reponse length. 430 * @param[in] instanceId - instance id for response 431 * 432 * @return PLDM_SUCCESS/PLDM_ERROR 433 */ 434 int getNumericEffecterValueHandler(const std::string& propertyType, 435 pldm::utils::PropertyValue propertyValue, 436 uint8_t effecterDataSize, 437 pldm_msg* responsePtr, 438 size_t responsePayloadLength, 439 uint8_t instanceId) 440 { 441 if (propertyType == "uint8_t") 442 { 443 uint8_t propVal = std::get<uint8_t>(propertyValue); 444 return getEffecterValue<uint8_t>(propVal, effecterDataSize, responsePtr, 445 responsePayloadLength, instanceId); 446 } 447 else if (propertyType == "uint16_t") 448 { 449 uint16_t propVal = std::get<uint16_t>(propertyValue); 450 return getEffecterValue<uint16_t>(propVal, effecterDataSize, 451 responsePtr, responsePayloadLength, 452 instanceId); 453 } 454 else if (propertyType == "uint32_t") 455 { 456 uint32_t propVal = std::get<uint32_t>(propertyValue); 457 return getEffecterValue<uint32_t>(propVal, effecterDataSize, 458 responsePtr, responsePayloadLength, 459 instanceId); 460 } 461 else if (propertyType == "uint64_t") 462 { 463 uint64_t propVal = std::get<uint64_t>(propertyValue); 464 return getEffecterValue<uint64_t>(propVal, effecterDataSize, 465 responsePtr, responsePayloadLength, 466 instanceId); 467 } 468 else 469 { 470 error("Property Type [{PROPERTYTYPE}] not supported", "PROPERTYTYPE", 471 propertyType); 472 } 473 return PLDM_ERROR; 474 } 475 476 /** @brief Function to get the effecter details as data size, D-Bus property 477 * type, D-Bus Value 478 * @tparam[in] DBusInterface - DBus interface type 479 * @tparam[in] Handler - pldm::responder::platform::Handler 480 * @param[in] dBusIntf - The interface object of DBusInterface 481 * @param[in] handler - The interface object of 482 * pldm::responder::platform::Handler 483 * @param[in] effecterId - Effecter ID sent by the requester to act on 484 * @param[in] effecterDataSize - The bit width and format of the setting 485 * value for the effecter 486 * @param[in] propertyType - The data type of the D-Bus value 487 * @param[in] propertyValue - The value of numeric effecter being 488 * requested. 489 * @return - Success or failure in getting the D-Bus property or the 490 * effecterId not found in the PDR repo 491 */ 492 template <class DBusInterface, class Handler> 493 int getNumericEffecterData(const DBusInterface& dBusIntf, Handler& handler, 494 uint16_t effecterId, uint8_t& effecterDataSize, 495 std::string& propertyType, 496 pldm::utils::PropertyValue& propertyValue) 497 { 498 pldm_numeric_effecter_value_pdr* pdr = nullptr; 499 500 std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> 501 numericEffecterPdrRepo(pldm_pdr_init(), pldm_pdr_destroy); 502 pldm::responder::pdr_utils::Repo numericEffecterPDRs( 503 numericEffecterPdrRepo.get()); 504 pldm::responder::pdr::getRepoByType(handler.getRepo(), numericEffecterPDRs, 505 PLDM_NUMERIC_EFFECTER_PDR); 506 if (numericEffecterPDRs.empty()) 507 { 508 error("The Numeric Effecter PDR repo is empty."); 509 return PLDM_ERROR; 510 } 511 512 // Get the pdr structure of pldm_numeric_effecter_value_pdr according 513 // to the effecterId 514 pldm::responder::pdr_utils::PdrEntry pdrEntry{}; 515 auto pdrRecord = numericEffecterPDRs.getFirstRecord(pdrEntry); 516 517 while (pdrRecord) 518 { 519 pdr = reinterpret_cast<pldm_numeric_effecter_value_pdr*>(pdrEntry.data); 520 if (pdr->effecter_id != effecterId) 521 { 522 pdr = nullptr; 523 pdrRecord = numericEffecterPDRs.getNextRecord(pdrRecord, pdrEntry); 524 continue; 525 } 526 effecterDataSize = pdr->effecter_data_size; 527 break; 528 } 529 530 if (!pdr) 531 { 532 error("The Numeric Effecter not found EFFECTERID={EFFECTERID}", 533 "EFFECTERID", effecterId); 534 return PLDM_PLATFORM_INVALID_EFFECTER_ID; 535 } 536 537 pldm::utils::DBusMapping dbusMapping{}; 538 try 539 { 540 const auto& [dbusMappings, 541 dbusValMaps] = handler.getDbusObjMaps(effecterId); 542 if (dbusMappings.size() > 0) 543 { 544 dbusMapping = { 545 dbusMappings[0].objectPath, dbusMappings[0].interface, 546 dbusMappings[0].propertyName, dbusMappings[0].propertyType}; 547 548 propertyValue = dBusIntf.getDbusPropertyVariant( 549 dbusMapping.objectPath.c_str(), 550 dbusMapping.propertyName.c_str(), 551 dbusMapping.interface.c_str()); 552 propertyType = dbusMappings[0].propertyType; 553 } 554 } 555 catch (const std::exception& e) 556 { 557 error( 558 "Dbus Mapping or the Dbus query for the Effecter failed for effecter id: {EFFECTER_ID}, {ERR_EXCEP}", 559 "EFFECTER_ID", effecterId, "ERR_EXCEP", e.what()); 560 error( 561 "Dbus Details objPath : [{OBJ_PATH}] interface : [{INTF}], property : [{PROPERTY}]", 562 "OBJ_PATH", dbusMapping.objectPath.c_str(), "INTF", 563 dbusMapping.interface.c_str(), "PROPERTY", 564 dbusMapping.propertyName.c_str()); 565 return PLDM_ERROR; 566 } 567 568 return PLDM_SUCCESS; 569 } 570 571 } // namespace platform_numeric_effecter 572 } // namespace responder 573 } // namespace pldm 574