1 #pragma once
2 
3 #include "config.h"
4 
5 #include "libpldm/platform.h"
6 #include "libpldm/states.h"
7 
8 #include "common/utils.hpp"
9 #include "libpldmresponder/pdr.hpp"
10 #include "pdr_utils.hpp"
11 #include "pldmd/handler.hpp"
12 
13 #include <math.h>
14 #include <stdint.h>
15 
16 #include <map>
17 #include <optional>
18 
19 namespace pldm
20 {
21 namespace responder
22 {
23 namespace platform_numeric_effecter
24 {
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_set_table.value_u8 < pdr->max_set_table.value_u8 &&
50                 (rawValue < pdr->min_set_table.value_u8 ||
51                  rawValue > pdr->max_set_table.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_set_table.value_s8 < pdr->max_set_table.value_s8 &&
73                 (rawValue < pdr->min_set_table.value_s8 ||
74                  rawValue > pdr->max_set_table.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_set_table.value_u16 < pdr->max_set_table.value_u16 &&
86                 (rawValue < pdr->min_set_table.value_u16 ||
87                  rawValue > pdr->max_set_table.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_set_table.value_s16 < pdr->max_set_table.value_s16 &&
109                 (rawValue < pdr->min_set_table.value_s16 ||
110                  rawValue > pdr->max_set_table.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_set_table.value_u32 < pdr->max_set_table.value_u32 &&
132                 (rawValue < pdr->min_set_table.value_u32 ||
133                  rawValue > pdr->max_set_table.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_set_table.value_s32 < pdr->max_set_table.value_s32 &&
155                 (rawValue < pdr->min_set_table.value_s32 ||
156                  rawValue > pdr->max_set_table.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         std::cerr << "Wrong field effecterDataSize...\n";
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     pldm::responder::pdr_utils::Repo numericEffecterPDRs(
260         numericEffecterPdrRepo.get());
261     pldm::responder::pdr::getRepoByType(handler.getRepo(), numericEffecterPDRs,
262                                         PLDM_NUMERIC_EFFECTER_PDR);
263     if (numericEffecterPDRs.empty())
264     {
265         std::cerr << "The Numeric Effecter PDR repo is empty." << std::endl;
266         return PLDM_ERROR;
267     }
268 
269     // Get the pdr structure of pldm_numeric_effecter_value_pdr according
270     // to the effecterId
271     pldm::responder::pdr_utils::PdrEntry pdrEntry{};
272     auto pdrRecord = numericEffecterPDRs.getFirstRecord(pdrEntry);
273     while (pdrRecord)
274     {
275         pdr = reinterpret_cast<pldm_numeric_effecter_value_pdr*>(pdrEntry.data);
276         if (pdr->effecter_id != effecterId)
277         {
278             pdr = nullptr;
279             pdrRecord = numericEffecterPDRs.getNextRecord(pdrRecord, pdrEntry);
280             continue;
281         }
282 
283         break;
284     }
285 
286     if (!pdr)
287     {
288         return PLDM_PLATFORM_INVALID_EFFECTER_ID;
289     }
290 
291     if (effecterValueLength != effecterValueArrayLength)
292     {
293         std::cerr << "effecter data size is incorrect.\n";
294         return PLDM_ERROR_INVALID_DATA;
295     }
296 
297     try
298     {
299         const auto& [dbusMappings, dbusValMaps] =
300             handler.getDbusObjMaps(effecterId);
301         pldm::utils::DBusMapping dbusMapping{
302             dbusMappings[0].objectPath, dbusMappings[0].interface,
303             dbusMappings[0].propertyName, dbusMappings[0].propertyType};
304 
305         // convert to dbus effectervalue according to the factor
306         auto [rc, dbusValue] = convertToDbusValue(
307             pdr, effecterDataSize, effecterValue, dbusMappings[0].propertyType);
308         if (rc != PLDM_SUCCESS)
309         {
310             return rc;
311         }
312         try
313         {
314 
315             dBusIntf.setDbusProperty(dbusMapping, dbusValue.value());
316         }
317         catch (const std::exception& e)
318         {
319             std::cerr << "Error setting property, ERROR=" << e.what()
320                       << " PROPERTY=" << dbusMapping.propertyName
321                       << " INTERFACE=" << dbusMapping.interface << " PATH="
322                       << dbusMapping.objectPath << "\n";
323             return PLDM_ERROR;
324         }
325     }
326     catch (const std::out_of_range& e)
327     {
328         std::cerr << "Unknown effecter ID : " << effecterId << e.what() << '\n';
329         return PLDM_ERROR;
330     }
331 
332     return PLDM_SUCCESS;
333 }
334 
335 } // namespace platform_numeric_effecter
336 } // namespace responder
337 } // namespace pldm
338