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