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,
302                      dbusValMaps] = 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