1 #pragma once 2 3 #include "config.h" 4 5 #include "libpldm/platform.h" 6 #include "libpldm/states.h" 7 8 #include "common/utils.hpp" 9 #include "libpldmresponder/pdr.hpp" 10 #include "pdr_utils.hpp" 11 #include "pldmd/handler.hpp" 12 13 #include <math.h> 14 #include <stdint.h> 15 16 #include <map> 17 #include <optional> 18 19 using namespace pldm::responder::pdr; 20 using namespace pldm::utils; 21 22 namespace pldm 23 { 24 namespace responder 25 { 26 namespace platform_numeric_effecter 27 { 28 29 /** @brief Function to get the effecter value by PDR factor coefficient, etc. 30 * @param[in] pdr - The structure of pldm_numeric_effecter_value_pdr. 31 * @tparam[in] effecterValue - effecter value. 32 * 33 * @return - std::pair<int, std::optional<PropertyValue>> - rc:Success or 34 * failure, PropertyValue: The value to be set 35 */ 36 template <typename T> 37 std::pair<int, std::optional<PropertyValue>> 38 getEffecterRawValue(const pldm_numeric_effecter_value_pdr* pdr, 39 T& effecterValue) 40 { 41 // X = Round [ (Y - B) / m ] 42 // refer to DSP0248_1.2.0 27.8 43 int rc = 0; 44 PropertyValue value; 45 switch (pdr->effecter_data_size) 46 { 47 case PLDM_EFFECTER_DATA_SIZE_UINT8: 48 { 49 auto rawValue = static_cast<uint8_t>( 50 round(effecterValue - pdr->offset) / pdr->resolution); 51 if (pdr->min_set_table.value_u8 < pdr->max_set_table.value_u8 && 52 (rawValue < pdr->min_set_table.value_u8 || 53 rawValue > pdr->max_set_table.value_u8)) 54 { 55 rc = PLDM_ERROR_INVALID_DATA; 56 } 57 value = rawValue; 58 break; 59 } 60 case PLDM_EFFECTER_DATA_SIZE_SINT8: 61 { 62 auto rawValue = static_cast<int8_t>( 63 round(effecterValue - pdr->offset) / pdr->resolution); 64 if (pdr->min_set_table.value_s8 < pdr->max_set_table.value_s8 && 65 (rawValue < pdr->min_set_table.value_s8 || 66 rawValue > pdr->max_set_table.value_s8)) 67 { 68 rc = PLDM_ERROR_INVALID_DATA; 69 } 70 value = rawValue; 71 break; 72 } 73 case PLDM_EFFECTER_DATA_SIZE_UINT16: 74 { 75 auto rawValue = static_cast<uint16_t>( 76 round(effecterValue - pdr->offset) / pdr->resolution); 77 if (pdr->min_set_table.value_u16 < pdr->max_set_table.value_u16 && 78 (rawValue < pdr->min_set_table.value_u16 || 79 rawValue > pdr->max_set_table.value_u16)) 80 { 81 rc = PLDM_ERROR_INVALID_DATA; 82 } 83 value = rawValue; 84 break; 85 } 86 case PLDM_EFFECTER_DATA_SIZE_SINT16: 87 { 88 auto rawValue = static_cast<int16_t>( 89 round(effecterValue - pdr->offset) / pdr->resolution); 90 if (pdr->min_set_table.value_s16 < pdr->max_set_table.value_s16 && 91 (rawValue < pdr->min_set_table.value_s16 || 92 rawValue > pdr->max_set_table.value_s16)) 93 { 94 rc = PLDM_ERROR_INVALID_DATA; 95 } 96 value = rawValue; 97 break; 98 } 99 case PLDM_EFFECTER_DATA_SIZE_UINT32: 100 { 101 auto rawValue = static_cast<uint32_t>( 102 round(effecterValue - pdr->offset) / pdr->resolution); 103 if (pdr->min_set_table.value_u32 < pdr->max_set_table.value_u32 && 104 (rawValue < pdr->min_set_table.value_u32 || 105 rawValue > pdr->max_set_table.value_u32)) 106 { 107 rc = PLDM_ERROR_INVALID_DATA; 108 } 109 value = rawValue; 110 break; 111 } 112 case PLDM_EFFECTER_DATA_SIZE_SINT32: 113 { 114 auto rawValue = static_cast<int32_t>( 115 round(effecterValue - pdr->offset) / pdr->resolution); 116 if (pdr->min_set_table.value_s32 < pdr->max_set_table.value_s32 && 117 (rawValue < pdr->min_set_table.value_s32 || 118 rawValue > pdr->max_set_table.value_s32)) 119 { 120 rc = PLDM_ERROR_INVALID_DATA; 121 } 122 value = rawValue; 123 break; 124 } 125 } 126 127 return {rc, std::make_optional(std::move(value))}; 128 } 129 130 /** @brief Function to convert the D-Bus value by PDR factor and effecter value. 131 * @param[in] pdr - The structure of pldm_numeric_effecter_value_pdr. 132 * @param[in] effecterDataSize - effecter value size. 133 * @param[in,out] effecterValue - effecter value. 134 * 135 * @return std::pair<int, std::optional<PropertyValue>> - rc:Success or 136 * failure, PropertyValue: The value to be set 137 */ 138 std::pair<int, std::optional<PropertyValue>> 139 convertToDbusValue(const pldm_numeric_effecter_value_pdr* pdr, 140 uint8_t effecterDataSize, uint8_t* effecterValue) 141 { 142 if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_UINT8) 143 { 144 uint8_t currentValue = *(reinterpret_cast<uint8_t*>(&effecterValue[0])); 145 return getEffecterRawValue<uint8_t>(pdr, currentValue); 146 } 147 else if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_SINT8) 148 { 149 int8_t currentValue = *(reinterpret_cast<int8_t*>(&effecterValue[0])); 150 return getEffecterRawValue<int8_t>(pdr, currentValue); 151 } 152 else if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_UINT16) 153 { 154 uint16_t currentValue = 155 *(reinterpret_cast<uint16_t*>(&effecterValue[0])); 156 return getEffecterRawValue<uint16_t>(pdr, currentValue); 157 } 158 else if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_SINT16) 159 { 160 int16_t currentValue = *(reinterpret_cast<int16_t*>(&effecterValue[0])); 161 return getEffecterRawValue<int16_t>(pdr, currentValue); 162 } 163 else if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_UINT32) 164 { 165 uint32_t currentValue = 166 *(reinterpret_cast<uint32_t*>(&effecterValue[0])); 167 return getEffecterRawValue<uint32_t>(pdr, currentValue); 168 } 169 else if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_SINT32) 170 { 171 int32_t currentValue = *(reinterpret_cast<int32_t*>(&effecterValue[0])); 172 return getEffecterRawValue<int32_t>(pdr, currentValue); 173 } 174 else 175 { 176 std::cerr << "Wrong field effecterDataSize...\n"; 177 return {PLDM_ERROR, {}}; 178 } 179 } 180 181 /** @brief Function to set the effecter value requested by pldm requester 182 * @tparam[in] DBusInterface - DBus interface type 183 * @tparam[in] Handler - pldm::responder::platform::Handler 184 * @param[in] dBusIntf - The interface object of DBusInterface 185 * @param[in] handler - The interface object of 186 * pldm::responder::platform::Handler 187 * @param[in] effecterId - Effecter ID sent by the requester to act on 188 * @param[in] effecterDataSize - The bit width and format of the setting 189 * value for the effecter 190 * @param[in] effecter_value - The setting value of numeric effecter being 191 * requested. 192 * @param[in] effecterValueLength - The setting value length of numeric 193 * effecter being requested. 194 * @return - Success or failure in setting the states. Returns failure in 195 * terms of PLDM completion codes if atleast one state fails to be set 196 */ 197 template <class DBusInterface, class Handler> 198 int setNumericEffecterValueHandler(const DBusInterface& dBusIntf, 199 Handler& handler, uint16_t effecterId, 200 uint8_t effecterDataSize, 201 uint8_t* effecterValue, 202 size_t effecterValueLength) 203 { 204 constexpr auto effecterValueArrayLength = 4; 205 pldm_numeric_effecter_value_pdr* pdr = nullptr; 206 207 std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)> 208 numericEffecterPdrRepo(pldm_pdr_init(), pldm_pdr_destroy); 209 Repo numericEffecterPDRs(numericEffecterPdrRepo.get()); 210 getRepoByType(handler.getRepo(), numericEffecterPDRs, 211 PLDM_NUMERIC_EFFECTER_PDR); 212 if (numericEffecterPDRs.empty()) 213 { 214 std::cerr << "The Numeric Effecter PDR repo is empty." << std::endl; 215 return PLDM_ERROR; 216 } 217 218 // Get the pdr structure of pldm_numeric_effecter_value_pdr according 219 // to the effecterId 220 PdrEntry pdrEntry{}; 221 auto pdrRecord = numericEffecterPDRs.getFirstRecord(pdrEntry); 222 while (pdrRecord) 223 { 224 pdr = reinterpret_cast<pldm_numeric_effecter_value_pdr*>(pdrEntry.data); 225 if (pdr->effecter_id != effecterId) 226 { 227 pdr = nullptr; 228 pdrRecord = numericEffecterPDRs.getNextRecord(pdrRecord, pdrEntry); 229 continue; 230 } 231 232 break; 233 } 234 235 if (!pdr) 236 { 237 return PLDM_PLATFORM_INVALID_EFFECTER_ID; 238 } 239 240 if (effecterValueLength != effecterValueArrayLength) 241 { 242 std::cerr << "effecter data size is incorrect.\n"; 243 return PLDM_ERROR_INVALID_DATA; 244 } 245 246 // convert to dbus effectervalue according to the factor 247 auto [rc, dbusValue] = 248 convertToDbusValue(pdr, effecterDataSize, effecterValue); 249 if (rc != PLDM_SUCCESS) 250 { 251 return rc; 252 } 253 254 const auto& [dbusMappings, dbusValMaps] = 255 handler.getDbusObjMaps(effecterId); 256 DBusMapping dbusMapping{ 257 dbusMappings[0].objectPath, dbusMappings[0].interface, 258 dbusMappings[0].propertyName, dbusMappings[0].propertyType}; 259 try 260 { 261 dBusIntf.setDbusProperty(dbusMapping, dbusValue.value()); 262 } 263 catch (const std::exception& e) 264 { 265 std::cerr << "Error setting property, ERROR=" << e.what() 266 << " PROPERTY=" << dbusMapping.propertyName << " INTERFACE=" 267 << dbusMapping.interface << " PATH=" << dbusMapping.objectPath 268 << "\n"; 269 return PLDM_ERROR; 270 } 271 272 return PLDM_SUCCESS; 273 } 274 275 } // namespace platform_numeric_effecter 276 } // namespace responder 277 } // namespace pldm 278