| #pragma once |
| |
| #include "common/utils.hpp" |
| #include "libpldmresponder/pdr.hpp" |
| #include "pdr_utils.hpp" |
| #include "pldmd/handler.hpp" |
| |
| #include <libpldm/platform.h> |
| #include <libpldm/states.h> |
| #include <math.h> |
| #include <stdint.h> |
| |
| #include <phosphor-logging/lg2.hpp> |
| |
| #include <map> |
| #include <optional> |
| |
| PHOSPHOR_LOG2_USING; |
| |
| namespace pldm |
| { |
| namespace responder |
| { |
| namespace platform_numeric_effecter |
| { |
| /** @brief Function to get the effecter value by PDR factor coefficient, etc. |
| * @param[in] pdr - The structure of pldm_numeric_effecter_value_pdr. |
| * @param[in] effecterValue - effecter value. |
| * @param[in] propertyType - type of the D-Bus property. |
| * |
| * @return - std::pair<int, std::optional<PropertyValue>> - rc:Success or |
| * failure, PropertyValue: The value to be set |
| */ |
| template <typename T> |
| std::pair<int, std::optional<pldm::utils::PropertyValue>> |
| getEffecterRawValue(const pldm_numeric_effecter_value_pdr* pdr, |
| T& effecterValue, std::string propertyType) |
| { |
| // X = Round [ (Y - B) / m ] |
| // refer to DSP0248_1.2.0 27.8 |
| int rc = 0; |
| pldm::utils::PropertyValue value; |
| switch (pdr->effecter_data_size) |
| { |
| case PLDM_EFFECTER_DATA_SIZE_UINT8: |
| { |
| auto rawValue = static_cast<uint8_t>( |
| round(effecterValue - pdr->offset) / pdr->resolution); |
| if (pdr->min_settable.value_u8 < pdr->max_settable.value_u8 && |
| (rawValue < pdr->min_settable.value_u8 || |
| rawValue > pdr->max_settable.value_u8)) |
| { |
| rc = PLDM_ERROR_INVALID_DATA; |
| } |
| value = rawValue; |
| if (propertyType == "uint64_t") |
| { |
| auto tempValue = std::get<uint8_t>(value); |
| value = static_cast<uint64_t>(tempValue); |
| } |
| else if (propertyType == "uint32_t") |
| { |
| auto tempValue = std::get<uint8_t>(value); |
| value = static_cast<uint32_t>(tempValue); |
| } |
| break; |
| } |
| case PLDM_EFFECTER_DATA_SIZE_SINT8: |
| { |
| auto rawValue = static_cast<int8_t>( |
| round(effecterValue - pdr->offset) / pdr->resolution); |
| if (pdr->min_settable.value_s8 < pdr->max_settable.value_s8 && |
| (rawValue < pdr->min_settable.value_s8 || |
| rawValue > pdr->max_settable.value_s8)) |
| { |
| rc = PLDM_ERROR_INVALID_DATA; |
| } |
| value = rawValue; |
| break; |
| } |
| case PLDM_EFFECTER_DATA_SIZE_UINT16: |
| { |
| auto rawValue = static_cast<uint16_t>( |
| round(effecterValue - pdr->offset) / pdr->resolution); |
| if (pdr->min_settable.value_u16 < pdr->max_settable.value_u16 && |
| (rawValue < pdr->min_settable.value_u16 || |
| rawValue > pdr->max_settable.value_u16)) |
| { |
| rc = PLDM_ERROR_INVALID_DATA; |
| } |
| value = rawValue; |
| if (propertyType == "uint64_t") |
| { |
| auto tempValue = std::get<uint16_t>(value); |
| value = static_cast<uint64_t>(tempValue); |
| } |
| else if (propertyType == "uint32_t") |
| { |
| auto tempValue = std::get<uint16_t>(value); |
| value = static_cast<uint32_t>(tempValue); |
| } |
| break; |
| } |
| case PLDM_EFFECTER_DATA_SIZE_SINT16: |
| { |
| auto rawValue = static_cast<int16_t>( |
| round(effecterValue - pdr->offset) / pdr->resolution); |
| if (pdr->min_settable.value_s16 < pdr->max_settable.value_s16 && |
| (rawValue < pdr->min_settable.value_s16 || |
| rawValue > pdr->max_settable.value_s16)) |
| { |
| rc = PLDM_ERROR_INVALID_DATA; |
| } |
| value = rawValue; |
| if (propertyType == "uint64_t") |
| { |
| auto tempValue = std::get<int16_t>(value); |
| value = static_cast<uint64_t>(tempValue); |
| } |
| else if (propertyType == "uint32_t") |
| { |
| auto tempValue = std::get<int16_t>(value); |
| value = static_cast<uint32_t>(tempValue); |
| } |
| break; |
| } |
| case PLDM_EFFECTER_DATA_SIZE_UINT32: |
| { |
| auto rawValue = static_cast<uint32_t>( |
| round(effecterValue - pdr->offset) / pdr->resolution); |
| if (pdr->min_settable.value_u32 < pdr->max_settable.value_u32 && |
| (rawValue < pdr->min_settable.value_u32 || |
| rawValue > pdr->max_settable.value_u32)) |
| { |
| rc = PLDM_ERROR_INVALID_DATA; |
| } |
| value = rawValue; |
| if (propertyType == "uint64_t") |
| { |
| auto tempValue = std::get<uint32_t>(value); |
| value = static_cast<uint64_t>(tempValue); |
| } |
| else if (propertyType == "uint32_t") |
| { |
| auto tempValue = std::get<uint32_t>(value); |
| value = static_cast<uint32_t>(tempValue); |
| } |
| break; |
| } |
| case PLDM_EFFECTER_DATA_SIZE_SINT32: |
| { |
| auto rawValue = static_cast<int32_t>( |
| round(effecterValue - pdr->offset) / pdr->resolution); |
| if (pdr->min_settable.value_s32 < pdr->max_settable.value_s32 && |
| (rawValue < pdr->min_settable.value_s32 || |
| rawValue > pdr->max_settable.value_s32)) |
| { |
| rc = PLDM_ERROR_INVALID_DATA; |
| } |
| value = rawValue; |
| if (propertyType == "uint64_t") |
| { |
| auto tempValue = std::get<int32_t>(value); |
| value = static_cast<uint64_t>(tempValue); |
| } |
| else if (propertyType == "uint32_t") |
| { |
| auto tempValue = std::get<int32_t>(value); |
| value = static_cast<uint32_t>(tempValue); |
| } |
| break; |
| } |
| } |
| |
| return {rc, std::make_optional(std::move(value))}; |
| } |
| |
| /** @brief Function to convert the D-Bus value by PDR factor and effecter value. |
| * @param[in] pdr - The structure of pldm_numeric_effecter_value_pdr. |
| * @param[in] effecterDataSize - effecter value size. |
| * @param[in,out] effecterValue - effecter value. |
| * @param[in] propertyType - type of the D-Bus property. |
| * |
| * @return std::pair<int, std::optional<PropertyValue>> - rc:Success or |
| * failure, PropertyValue: The value to be set |
| */ |
| std::pair<int, std::optional<pldm::utils::PropertyValue>> |
| convertToDbusValue(const pldm_numeric_effecter_value_pdr* pdr, |
| uint8_t effecterDataSize, uint8_t* effecterValue, |
| std::string propertyType) |
| { |
| if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_UINT8) |
| { |
| uint8_t currentValue = *(reinterpret_cast<uint8_t*>(&effecterValue[0])); |
| return getEffecterRawValue<uint8_t>(pdr, currentValue, propertyType); |
| } |
| else if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_SINT8) |
| { |
| int8_t currentValue = *(reinterpret_cast<int8_t*>(&effecterValue[0])); |
| return getEffecterRawValue<int8_t>(pdr, currentValue, propertyType); |
| } |
| else if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_UINT16) |
| { |
| uint16_t currentValue = |
| *(reinterpret_cast<uint16_t*>(&effecterValue[0])); |
| return getEffecterRawValue<uint16_t>(pdr, currentValue, propertyType); |
| } |
| else if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_SINT16) |
| { |
| int16_t currentValue = *(reinterpret_cast<int16_t*>(&effecterValue[0])); |
| return getEffecterRawValue<int16_t>(pdr, currentValue, propertyType); |
| } |
| else if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_UINT32) |
| { |
| uint32_t currentValue = |
| *(reinterpret_cast<uint32_t*>(&effecterValue[0])); |
| return getEffecterRawValue<uint32_t>(pdr, currentValue, propertyType); |
| } |
| else if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_SINT32) |
| { |
| int32_t currentValue = *(reinterpret_cast<int32_t*>(&effecterValue[0])); |
| return getEffecterRawValue<int32_t>(pdr, currentValue, propertyType); |
| } |
| else |
| { |
| error("Unknown Effecter Size {SIZE}", "SIZE", effecterDataSize); |
| return {PLDM_ERROR, {}}; |
| } |
| } |
| |
| /** @brief Function to set the effecter value requested by pldm requester |
| * @tparam[in] DBusInterface - DBus interface type |
| * @tparam[in] Handler - pldm::responder::platform::Handler |
| * @param[in] dBusIntf - The interface object of DBusInterface |
| * @param[in] handler - The interface object of |
| * pldm::responder::platform::Handler |
| * @param[in] effecterId - Effecter ID sent by the requester to act on |
| * @param[in] effecterDataSize - The bit width and format of the setting |
| * value for the effecter |
| * @param[in] effecter_value - The setting value of numeric effecter being |
| * requested. |
| * @param[in] effecterValueLength - The setting value length of numeric |
| * effecter being requested. |
| * @return - Success or failure in setting the states. Returns failure in |
| * terms of PLDM completion codes if atleast one state fails to be set |
| */ |
| template <class DBusInterface, class Handler> |
| int setNumericEffecterValueHandler(const DBusInterface& dBusIntf, |
| Handler& handler, uint16_t effecterId, |
| uint8_t effecterDataSize, |
| uint8_t* effecterValue, |
| size_t effecterValueLength) |
| { |
| constexpr auto effecterValueArrayLength = 4; |
| pldm_numeric_effecter_value_pdr* pdr = nullptr; |
| |
| std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> |
| numericEffecterPdrRepo(pldm_pdr_init(), pldm_pdr_destroy); |
| if (!numericEffecterPdrRepo) |
| { |
| error("Failed to instantiate numeric effecter PDR repository"); |
| return PLDM_ERROR; |
| } |
| pldm::responder::pdr_utils::Repo numericEffecterPDRs( |
| numericEffecterPdrRepo.get()); |
| pldm::responder::pdr::getRepoByType(handler.getRepo(), numericEffecterPDRs, |
| PLDM_NUMERIC_EFFECTER_PDR); |
| if (numericEffecterPDRs.empty()) |
| { |
| error("The Numeric Effecter PDR repo is empty."); |
| return PLDM_ERROR; |
| } |
| |
| // Get the pdr structure of pldm_numeric_effecter_value_pdr according |
| // to the effecterId |
| pldm::responder::pdr_utils::PdrEntry pdrEntry{}; |
| auto pdrRecord = numericEffecterPDRs.getFirstRecord(pdrEntry); |
| while (pdrRecord) |
| { |
| pdr = reinterpret_cast<pldm_numeric_effecter_value_pdr*>(pdrEntry.data); |
| if (pdr->effecter_id != effecterId) |
| { |
| pdr = nullptr; |
| pdrRecord = numericEffecterPDRs.getNextRecord(pdrRecord, pdrEntry); |
| continue; |
| } |
| |
| break; |
| } |
| |
| if (!pdr) |
| { |
| return PLDM_PLATFORM_INVALID_EFFECTER_ID; |
| } |
| |
| if (effecterValueLength != effecterValueArrayLength) |
| { |
| error("Incorrect effecter data size {SIZE}", "SIZE", |
| effecterValueLength); |
| return PLDM_ERROR_INVALID_DATA; |
| } |
| |
| try |
| { |
| const auto& [dbusMappings, |
| dbusValMaps] = handler.getDbusObjMaps(effecterId); |
| pldm::utils::DBusMapping dbusMapping{ |
| dbusMappings[0].objectPath, dbusMappings[0].interface, |
| dbusMappings[0].propertyName, dbusMappings[0].propertyType}; |
| |
| // convert to dbus effectervalue according to the factor |
| auto [rc, dbusValue] = convertToDbusValue( |
| pdr, effecterDataSize, effecterValue, dbusMappings[0].propertyType); |
| if (rc != PLDM_SUCCESS) |
| { |
| return rc; |
| } |
| try |
| { |
| dBusIntf.setDbusProperty(dbusMapping, dbusValue.value()); |
| } |
| catch (const std::exception& e) |
| { |
| error( |
| "Failed to set property '{PROPERTY}', interface '{INTERFACE}' and path '{PATH}', error - {ERROR}", |
| "PROPERTY", dbusMapping.propertyName, "INTERFACE", |
| dbusMapping.interface, "PATH", dbusMapping.objectPath, "ERROR", |
| e); |
| return PLDM_ERROR; |
| } |
| } |
| catch (const std::out_of_range& e) |
| { |
| error("Unknown effecter ID '{EFFECTERID}', error - {ERROR}", |
| "EFFECTERID", effecterId, "ERROR", e); |
| return PLDM_ERROR; |
| } |
| |
| return PLDM_SUCCESS; |
| } |
| |
| /** @brief Function to convert the D-Bus value based on effecter data size |
| * and create the response for getNumericEffecterValue request. |
| * @param[in] PropertyValue - D-Bus Value |
| * @param[in] effecterDataSize - effecter value size. |
| * @param[in,out] responsePtr - Response of getNumericEffecterValue. |
| * @param[in] responsePayloadLength - reponse length. |
| * @param[in] instanceId - instance id for response |
| * |
| * @return PLDM_SUCCESS/PLDM_ERROR |
| */ |
| template <typename T> |
| int getEffecterValue(T propertyValue, uint8_t effecterDataSize, |
| pldm_msg* responsePtr, size_t responsePayloadLength, |
| uint8_t instanceId) |
| { |
| switch (effecterDataSize) |
| { |
| case PLDM_EFFECTER_DATA_SIZE_UINT8: |
| { |
| uint8_t value = static_cast<uint8_t>(propertyValue); |
| return (encode_get_numeric_effecter_value_resp( |
| instanceId, PLDM_SUCCESS, effecterDataSize, |
| EFFECTER_OPER_STATE_ENABLED_NOUPDATEPENDING, &value, &value, |
| responsePtr, responsePayloadLength)); |
| } |
| case PLDM_EFFECTER_DATA_SIZE_SINT8: |
| { |
| int8_t value = static_cast<int8_t>(propertyValue); |
| return (encode_get_numeric_effecter_value_resp( |
| instanceId, PLDM_SUCCESS, effecterDataSize, |
| EFFECTER_OPER_STATE_ENABLED_NOUPDATEPENDING, |
| reinterpret_cast<uint8_t*>(&value), |
| reinterpret_cast<uint8_t*>(&value), responsePtr, |
| responsePayloadLength)); |
| } |
| case PLDM_EFFECTER_DATA_SIZE_UINT16: |
| { |
| uint16_t value = static_cast<uint16_t>(propertyValue); |
| return (encode_get_numeric_effecter_value_resp( |
| instanceId, PLDM_SUCCESS, effecterDataSize, |
| EFFECTER_OPER_STATE_ENABLED_NOUPDATEPENDING, |
| reinterpret_cast<uint8_t*>(&value), |
| reinterpret_cast<uint8_t*>(&value), responsePtr, |
| responsePayloadLength)); |
| } |
| case PLDM_EFFECTER_DATA_SIZE_SINT16: |
| { |
| int16_t value = static_cast<int16_t>(propertyValue); |
| return (encode_get_numeric_effecter_value_resp( |
| instanceId, PLDM_SUCCESS, effecterDataSize, |
| EFFECTER_OPER_STATE_ENABLED_NOUPDATEPENDING, |
| reinterpret_cast<uint8_t*>(&value), |
| reinterpret_cast<uint8_t*>(&value), responsePtr, |
| responsePayloadLength)); |
| } |
| case PLDM_EFFECTER_DATA_SIZE_UINT32: |
| { |
| uint32_t value = static_cast<uint32_t>(propertyValue); |
| return (encode_get_numeric_effecter_value_resp( |
| instanceId, PLDM_SUCCESS, effecterDataSize, |
| EFFECTER_OPER_STATE_ENABLED_NOUPDATEPENDING, |
| reinterpret_cast<uint8_t*>(&value), |
| reinterpret_cast<uint8_t*>(&value), responsePtr, |
| responsePayloadLength)); |
| } |
| case PLDM_EFFECTER_DATA_SIZE_SINT32: |
| { |
| int32_t value = static_cast<int32_t>(propertyValue); |
| return (encode_get_numeric_effecter_value_resp( |
| instanceId, PLDM_SUCCESS, effecterDataSize, |
| EFFECTER_OPER_STATE_ENABLED_NOUPDATEPENDING, |
| reinterpret_cast<uint8_t*>(&value), |
| reinterpret_cast<uint8_t*>(&value), responsePtr, |
| responsePayloadLength)); |
| } |
| default: |
| { |
| error("Unknown Effecter Size {SIZE}", "SIZE", effecterDataSize); |
| return PLDM_ERROR; |
| } |
| } |
| } |
| |
| /** @brief Function to convert the D-Bus value to the effector data size value |
| * @param[in] PropertyType - String contains the dataType of the Dbus value. |
| * @param[in] PropertyValue - Variant contains the D-Bus Value |
| * @param[in] effecterDataSize - effecter value size. |
| * @param[in,out] responsePtr - Response of getNumericEffecterValue. |
| * @param[in] responsePayloadLength - reponse length. |
| * @param[in] instanceId - instance id for response |
| * |
| * @return PLDM_SUCCESS/PLDM_ERROR |
| */ |
| int getNumericEffecterValueHandler(const std::string& propertyType, |
| pldm::utils::PropertyValue propertyValue, |
| uint8_t effecterDataSize, |
| pldm_msg* responsePtr, |
| size_t responsePayloadLength, |
| uint8_t instanceId) |
| { |
| if (propertyType == "uint8_t") |
| { |
| uint8_t propVal = std::get<uint8_t>(propertyValue); |
| return getEffecterValue<uint8_t>(propVal, effecterDataSize, responsePtr, |
| responsePayloadLength, instanceId); |
| } |
| else if (propertyType == "uint16_t") |
| { |
| uint16_t propVal = std::get<uint16_t>(propertyValue); |
| return getEffecterValue<uint16_t>(propVal, effecterDataSize, |
| responsePtr, responsePayloadLength, |
| instanceId); |
| } |
| else if (propertyType == "uint32_t") |
| { |
| uint32_t propVal = std::get<uint32_t>(propertyValue); |
| return getEffecterValue<uint32_t>(propVal, effecterDataSize, |
| responsePtr, responsePayloadLength, |
| instanceId); |
| } |
| else if (propertyType == "uint64_t") |
| { |
| uint64_t propVal = std::get<uint64_t>(propertyValue); |
| return getEffecterValue<uint64_t>(propVal, effecterDataSize, |
| responsePtr, responsePayloadLength, |
| instanceId); |
| } |
| else |
| { |
| error("Property type '{TYPE}' not supported", "TYPE", propertyType); |
| } |
| return PLDM_ERROR; |
| } |
| |
| /** @brief Function to get the effecter details as data size, D-Bus property |
| * type, D-Bus Value |
| * @tparam[in] DBusInterface - DBus interface type |
| * @tparam[in] Handler - pldm::responder::platform::Handler |
| * @param[in] dBusIntf - The interface object of DBusInterface |
| * @param[in] handler - The interface object of |
| * pldm::responder::platform::Handler |
| * @param[in] effecterId - Effecter ID sent by the requester to act on |
| * @param[in] effecterDataSize - The bit width and format of the setting |
| * value for the effecter |
| * @param[in] propertyType - The data type of the D-Bus value |
| * @param[in] propertyValue - The value of numeric effecter being |
| * requested. |
| * @return - Success or failure in getting the D-Bus property or the |
| * effecterId not found in the PDR repo |
| */ |
| template <class DBusInterface, class Handler> |
| int getNumericEffecterData(const DBusInterface& dBusIntf, Handler& handler, |
| uint16_t effecterId, uint8_t& effecterDataSize, |
| std::string& propertyType, |
| pldm::utils::PropertyValue& propertyValue) |
| { |
| pldm_numeric_effecter_value_pdr* pdr = nullptr; |
| |
| std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> |
| numericEffecterPdrRepo(pldm_pdr_init(), pldm_pdr_destroy); |
| pldm::responder::pdr_utils::Repo numericEffecterPDRs( |
| numericEffecterPdrRepo.get()); |
| pldm::responder::pdr::getRepoByType(handler.getRepo(), numericEffecterPDRs, |
| PLDM_NUMERIC_EFFECTER_PDR); |
| if (numericEffecterPDRs.empty()) |
| { |
| error("The Numeric Effecter PDR repo is empty."); |
| return PLDM_ERROR; |
| } |
| |
| // Get the pdr structure of pldm_numeric_effecter_value_pdr according |
| // to the effecterId |
| pldm::responder::pdr_utils::PdrEntry pdrEntry{}; |
| auto pdrRecord = numericEffecterPDRs.getFirstRecord(pdrEntry); |
| |
| while (pdrRecord) |
| { |
| pdr = reinterpret_cast<pldm_numeric_effecter_value_pdr*>(pdrEntry.data); |
| if (pdr->effecter_id != effecterId) |
| { |
| pdr = nullptr; |
| pdrRecord = numericEffecterPDRs.getNextRecord(pdrRecord, pdrEntry); |
| continue; |
| } |
| effecterDataSize = pdr->effecter_data_size; |
| break; |
| } |
| |
| if (!pdr) |
| { |
| error("Failed to find numeric effecter ID {EFFECTERID}", "EFFECTERID", |
| effecterId); |
| return PLDM_PLATFORM_INVALID_EFFECTER_ID; |
| } |
| |
| pldm::utils::DBusMapping dbusMapping{}; |
| try |
| { |
| const auto& [dbusMappings, |
| dbusValMaps] = handler.getDbusObjMaps(effecterId); |
| if (dbusMappings.size() > 0) |
| { |
| dbusMapping = { |
| dbusMappings[0].objectPath, dbusMappings[0].interface, |
| dbusMappings[0].propertyName, dbusMappings[0].propertyType}; |
| |
| propertyValue = dBusIntf.getDbusPropertyVariant( |
| dbusMapping.objectPath.c_str(), |
| dbusMapping.propertyName.c_str(), |
| dbusMapping.interface.c_str()); |
| propertyType = dbusMappings[0].propertyType; |
| } |
| } |
| catch (const std::exception& e) |
| { |
| error( |
| "Failed to do dbus mapping or the dbus query for the effecter ID '{EFFECTERID}', error - {ERROR}", |
| "EFFECTERID", effecterId, "ERROR", e); |
| error( |
| "Dbus Details path [{PATH}], interface [{INTERFACE}] and property [{PROPERTY}]", |
| "PATH", dbusMapping.objectPath, "INTERFACE", dbusMapping.interface, |
| "PROPERTY", dbusMapping.propertyName); |
| return PLDM_ERROR; |
| } |
| |
| return PLDM_SUCCESS; |
| } |
| |
| } // namespace platform_numeric_effecter |
| } // namespace responder |
| } // namespace pldm |