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>>
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>>
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("Wrong field 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 atleast one state fails to be set
246  */
247 template <class DBusInterface, class Handler>
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("effecter data size is incorrect.");
299         return PLDM_ERROR_INVALID_DATA;
300     }
301 
302     try
303     {
304         const auto& [dbusMappings,
305                      dbusValMaps] = handler.getDbusObjMaps(effecterId);
306         pldm::utils::DBusMapping dbusMapping{
307             dbusMappings[0].objectPath, dbusMappings[0].interface,
308             dbusMappings[0].propertyName, dbusMappings[0].propertyType};
309 
310         // convert to dbus effectervalue according to the factor
311         auto [rc, dbusValue] = convertToDbusValue(
312             pdr, effecterDataSize, effecterValue, dbusMappings[0].propertyType);
313         if (rc != PLDM_SUCCESS)
314         {
315             return rc;
316         }
317         try
318         {
319             dBusIntf.setDbusProperty(dbusMapping, dbusValue.value());
320         }
321         catch (const std::exception& e)
322         {
323             error(
324                 "Error setting property, ERROR={ERR_EXCEP} PROPERTY={DBUS_PROP} INTERFACE={DBUS_INTF} PATH={DBUS_OBJ_PATH}",
325                 "ERR_EXCEP", e.what(), "DBUS_PROP", dbusMapping.propertyName,
326                 "DBUS_INTF", dbusMapping.interface, "DBUS_OBJ_PATH",
327                 dbusMapping.objectPath.c_str());
328             return PLDM_ERROR;
329         }
330     }
331     catch (const std::out_of_range& e)
332     {
333         error("Unknown effecter ID : {EFFECTER_ID} {ERR_EXCEP}", "EFFECTER_ID",
334               effecterId, "ERR_EXCEP", e.what());
335         return PLDM_ERROR;
336     }
337 
338     return PLDM_SUCCESS;
339 }
340 
341 } // namespace platform_numeric_effecter
342 } // namespace responder
343 } // namespace pldm
344