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