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>>
getEffecterRawValue(const pldm_numeric_effecter_value_pdr * pdr,T & effecterValue,std::string propertyType)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(const pldm_numeric_effecter_value_pdr * pdr,uint8_t effecterDataSize,uint8_t * effecterValue,std::string propertyType)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("Unknown Effecter Size {SIZE}", "SIZE", 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 at least one state fails to be set
246 */
247 template <class DBusInterface, class Handler>
setNumericEffecterValueHandler(const DBusInterface & dBusIntf,Handler & handler,uint16_t effecterId,uint8_t effecterDataSize,uint8_t * effecterValue,size_t effecterValueLength)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("Incorrect effecter data size {SIZE}", "SIZE",
299 effecterValueLength);
300 return PLDM_ERROR_INVALID_DATA;
301 }
302
303 try
304 {
305 const auto& [dbusMappings,
306 dbusValMaps] = handler.getDbusObjMaps(effecterId);
307 pldm::utils::DBusMapping dbusMapping{
308 dbusMappings[0].objectPath, dbusMappings[0].interface,
309 dbusMappings[0].propertyName, dbusMappings[0].propertyType};
310
311 // convert to dbus effectervalue according to the factor
312 auto [rc, dbusValue] = convertToDbusValue(
313 pdr, effecterDataSize, effecterValue, dbusMappings[0].propertyType);
314 if (rc != PLDM_SUCCESS)
315 {
316 return rc;
317 }
318 try
319 {
320 dBusIntf.setDbusProperty(dbusMapping, dbusValue.value());
321 }
322 catch (const std::exception& e)
323 {
324 error(
325 "Failed to set property '{PROPERTY}', interface '{INTERFACE}' and path '{PATH}', error - {ERROR}",
326 "PROPERTY", dbusMapping.propertyName, "INTERFACE",
327 dbusMapping.interface, "PATH", dbusMapping.objectPath, "ERROR",
328 e);
329 return PLDM_ERROR;
330 }
331 }
332 catch (const std::out_of_range& e)
333 {
334 error("Unknown effecter ID '{EFFECTERID}', error - {ERROR}",
335 "EFFECTERID", effecterId, "ERROR", e);
336 return PLDM_ERROR;
337 }
338
339 return PLDM_SUCCESS;
340 }
341
342 /** @brief Function to convert the D-Bus value based on effecter data size
343 * and create the response for getNumericEffecterValue request.
344 * @param[in] PropertyValue - D-Bus Value
345 * @param[in] effecterDataSize - effecter value size.
346 * @param[in,out] responsePtr - Response of getNumericEffecterValue.
347 * @param[in] responsePayloadLength - response length.
348 * @param[in] instanceId - instance id for response
349 *
350 * @return PLDM_SUCCESS/PLDM_ERROR
351 */
352 template <typename T>
getEffecterValue(T propertyValue,uint8_t effecterDataSize,pldm_msg * responsePtr,size_t responsePayloadLength,uint8_t instanceId)353 int getEffecterValue(T propertyValue, uint8_t effecterDataSize,
354 pldm_msg* responsePtr, size_t responsePayloadLength,
355 uint8_t instanceId)
356 {
357 switch (effecterDataSize)
358 {
359 case PLDM_EFFECTER_DATA_SIZE_UINT8:
360 {
361 uint8_t value = static_cast<uint8_t>(propertyValue);
362 return (encode_get_numeric_effecter_value_resp(
363 instanceId, PLDM_SUCCESS, effecterDataSize,
364 EFFECTER_OPER_STATE_ENABLED_NOUPDATEPENDING, &value, &value,
365 responsePtr, responsePayloadLength));
366 }
367 case PLDM_EFFECTER_DATA_SIZE_SINT8:
368 {
369 int8_t value = static_cast<int8_t>(propertyValue);
370 return (encode_get_numeric_effecter_value_resp(
371 instanceId, PLDM_SUCCESS, effecterDataSize,
372 EFFECTER_OPER_STATE_ENABLED_NOUPDATEPENDING,
373 reinterpret_cast<uint8_t*>(&value),
374 reinterpret_cast<uint8_t*>(&value), responsePtr,
375 responsePayloadLength));
376 }
377 case PLDM_EFFECTER_DATA_SIZE_UINT16:
378 {
379 uint16_t value = static_cast<uint16_t>(propertyValue);
380 return (encode_get_numeric_effecter_value_resp(
381 instanceId, PLDM_SUCCESS, effecterDataSize,
382 EFFECTER_OPER_STATE_ENABLED_NOUPDATEPENDING,
383 reinterpret_cast<uint8_t*>(&value),
384 reinterpret_cast<uint8_t*>(&value), responsePtr,
385 responsePayloadLength));
386 }
387 case PLDM_EFFECTER_DATA_SIZE_SINT16:
388 {
389 int16_t value = static_cast<int16_t>(propertyValue);
390 return (encode_get_numeric_effecter_value_resp(
391 instanceId, PLDM_SUCCESS, effecterDataSize,
392 EFFECTER_OPER_STATE_ENABLED_NOUPDATEPENDING,
393 reinterpret_cast<uint8_t*>(&value),
394 reinterpret_cast<uint8_t*>(&value), responsePtr,
395 responsePayloadLength));
396 }
397 case PLDM_EFFECTER_DATA_SIZE_UINT32:
398 {
399 uint32_t value = static_cast<uint32_t>(propertyValue);
400 return (encode_get_numeric_effecter_value_resp(
401 instanceId, PLDM_SUCCESS, effecterDataSize,
402 EFFECTER_OPER_STATE_ENABLED_NOUPDATEPENDING,
403 reinterpret_cast<uint8_t*>(&value),
404 reinterpret_cast<uint8_t*>(&value), responsePtr,
405 responsePayloadLength));
406 }
407 case PLDM_EFFECTER_DATA_SIZE_SINT32:
408 {
409 int32_t value = static_cast<int32_t>(propertyValue);
410 return (encode_get_numeric_effecter_value_resp(
411 instanceId, PLDM_SUCCESS, effecterDataSize,
412 EFFECTER_OPER_STATE_ENABLED_NOUPDATEPENDING,
413 reinterpret_cast<uint8_t*>(&value),
414 reinterpret_cast<uint8_t*>(&value), responsePtr,
415 responsePayloadLength));
416 }
417 default:
418 {
419 error("Unknown Effecter Size {SIZE}", "SIZE", effecterDataSize);
420 return PLDM_ERROR;
421 }
422 }
423 }
424
425 /** @brief Function to convert the D-Bus value to the effector data size value
426 * @param[in] PropertyType - String contains the dataType of the Dbus value.
427 * @param[in] PropertyValue - Variant contains the D-Bus Value
428 * @param[in] effecterDataSize - effecter value size.
429 * @param[in,out] responsePtr - Response of getNumericEffecterValue.
430 * @param[in] responsePayloadLength - response length.
431 * @param[in] instanceId - instance id for response
432 *
433 * @return PLDM_SUCCESS/PLDM_ERROR
434 */
getNumericEffecterValueHandler(const std::string & propertyType,pldm::utils::PropertyValue propertyValue,uint8_t effecterDataSize,pldm_msg * responsePtr,size_t responsePayloadLength,uint8_t instanceId)435 int getNumericEffecterValueHandler(const std::string& propertyType,
436 pldm::utils::PropertyValue propertyValue,
437 uint8_t effecterDataSize,
438 pldm_msg* responsePtr,
439 size_t responsePayloadLength,
440 uint8_t instanceId)
441 {
442 if (propertyType == "uint8_t")
443 {
444 uint8_t propVal = std::get<uint8_t>(propertyValue);
445 return getEffecterValue<uint8_t>(propVal, effecterDataSize, responsePtr,
446 responsePayloadLength, instanceId);
447 }
448 else if (propertyType == "uint16_t")
449 {
450 uint16_t propVal = std::get<uint16_t>(propertyValue);
451 return getEffecterValue<uint16_t>(propVal, effecterDataSize,
452 responsePtr, responsePayloadLength,
453 instanceId);
454 }
455 else if (propertyType == "uint32_t")
456 {
457 uint32_t propVal = std::get<uint32_t>(propertyValue);
458 return getEffecterValue<uint32_t>(propVal, effecterDataSize,
459 responsePtr, responsePayloadLength,
460 instanceId);
461 }
462 else if (propertyType == "uint64_t")
463 {
464 uint64_t propVal = std::get<uint64_t>(propertyValue);
465 return getEffecterValue<uint64_t>(propVal, effecterDataSize,
466 responsePtr, responsePayloadLength,
467 instanceId);
468 }
469 else
470 {
471 error("Property type '{TYPE}' not supported", "TYPE", 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>
getNumericEffecterData(const DBusInterface & dBusIntf,Handler & handler,uint16_t effecterId,uint8_t & effecterDataSize,std::string & propertyType,pldm::utils::PropertyValue & propertyValue)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("Failed to find numeric effecter ID {EFFECTERID}", "EFFECTERID",
533 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 "Failed to do dbus mapping or the dbus query for the effecter ID '{EFFECTERID}', error - {ERROR}",
559 "EFFECTERID", effecterId, "ERROR", e);
560 error(
561 "Dbus Details path [{PATH}], interface [{INTERFACE}] and property [{PROPERTY}]",
562 "PATH", dbusMapping.objectPath, "INTERFACE", dbusMapping.interface,
563 "PROPERTY", dbusMapping.propertyName);
564 return PLDM_ERROR;
565 }
566
567 return PLDM_SUCCESS;
568 }
569
570 } // namespace platform_numeric_effecter
571 } // namespace responder
572 } // namespace pldm
573