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 <map>
16 #include <optional>
17 
18 namespace pldm
19 {
20 namespace responder
21 {
22 namespace platform_numeric_effecter
23 {
24 
25 /** @brief Function to get the effecter value by PDR factor coefficient, etc.
26  *  @param[in] pdr - The structure of pldm_numeric_effecter_value_pdr.
27  *  @param[in] effecterValue - effecter value.
28  *  @param[in] propertyType - type of the D-Bus property.
29  *
30  *  @return - std::pair<int, std::optional<PropertyValue>> - rc:Success or
31  *          failure, PropertyValue: The value to be set
32  */
33 template <typename T>
34 std::pair<int, std::optional<pldm::utils::PropertyValue>>
35     getEffecterRawValue(const pldm_numeric_effecter_value_pdr* pdr,
36                         T& effecterValue, std::string propertyType)
37 {
38     // X = Round [ (Y - B) / m ]
39     // refer to DSP0248_1.2.0 27.8
40     int rc = 0;
41     pldm::utils::PropertyValue value;
42     switch (pdr->effecter_data_size)
43     {
44         case PLDM_EFFECTER_DATA_SIZE_UINT8:
45         {
46             auto rawValue = static_cast<uint8_t>(
47                 round(effecterValue - pdr->offset) / pdr->resolution);
48             if (pdr->min_settable.value_u8 < pdr->max_settable.value_u8 &&
49                 (rawValue < pdr->min_settable.value_u8 ||
50                  rawValue > pdr->max_settable.value_u8))
51             {
52                 rc = PLDM_ERROR_INVALID_DATA;
53             }
54             value = rawValue;
55             if (propertyType == "uint64_t")
56             {
57                 auto tempValue = std::get<uint8_t>(value);
58                 value = static_cast<uint64_t>(tempValue);
59             }
60             else if (propertyType == "uint32_t")
61             {
62                 auto tempValue = std::get<uint8_t>(value);
63                 value = static_cast<uint32_t>(tempValue);
64             }
65             break;
66         }
67         case PLDM_EFFECTER_DATA_SIZE_SINT8:
68         {
69             auto rawValue = static_cast<int8_t>(
70                 round(effecterValue - pdr->offset) / pdr->resolution);
71             if (pdr->min_settable.value_s8 < pdr->max_settable.value_s8 &&
72                 (rawValue < pdr->min_settable.value_s8 ||
73                  rawValue > pdr->max_settable.value_s8))
74             {
75                 rc = PLDM_ERROR_INVALID_DATA;
76             }
77             value = rawValue;
78             break;
79         }
80         case PLDM_EFFECTER_DATA_SIZE_UINT16:
81         {
82             auto rawValue = static_cast<uint16_t>(
83                 round(effecterValue - pdr->offset) / pdr->resolution);
84             if (pdr->min_settable.value_u16 < pdr->max_settable.value_u16 &&
85                 (rawValue < pdr->min_settable.value_u16 ||
86                  rawValue > pdr->max_settable.value_u16))
87             {
88                 rc = PLDM_ERROR_INVALID_DATA;
89             }
90             value = rawValue;
91             if (propertyType == "uint64_t")
92             {
93                 auto tempValue = std::get<uint16_t>(value);
94                 value = static_cast<uint64_t>(tempValue);
95             }
96             else if (propertyType == "uint32_t")
97             {
98                 auto tempValue = std::get<uint16_t>(value);
99                 value = static_cast<uint32_t>(tempValue);
100             }
101             break;
102         }
103         case PLDM_EFFECTER_DATA_SIZE_SINT16:
104         {
105             auto rawValue = static_cast<int16_t>(
106                 round(effecterValue - pdr->offset) / pdr->resolution);
107             if (pdr->min_settable.value_s16 < pdr->max_settable.value_s16 &&
108                 (rawValue < pdr->min_settable.value_s16 ||
109                  rawValue > pdr->max_settable.value_s16))
110             {
111                 rc = PLDM_ERROR_INVALID_DATA;
112             }
113             value = rawValue;
114             if (propertyType == "uint64_t")
115             {
116                 auto tempValue = std::get<int16_t>(value);
117                 value = static_cast<uint64_t>(tempValue);
118             }
119             else if (propertyType == "uint32_t")
120             {
121                 auto tempValue = std::get<int16_t>(value);
122                 value = static_cast<uint32_t>(tempValue);
123             }
124             break;
125         }
126         case PLDM_EFFECTER_DATA_SIZE_UINT32:
127         {
128             auto rawValue = static_cast<uint32_t>(
129                 round(effecterValue - pdr->offset) / pdr->resolution);
130             if (pdr->min_settable.value_u32 < pdr->max_settable.value_u32 &&
131                 (rawValue < pdr->min_settable.value_u32 ||
132                  rawValue > pdr->max_settable.value_u32))
133             {
134                 rc = PLDM_ERROR_INVALID_DATA;
135             }
136             value = rawValue;
137             if (propertyType == "uint64_t")
138             {
139                 auto tempValue = std::get<uint32_t>(value);
140                 value = static_cast<uint64_t>(tempValue);
141             }
142             else if (propertyType == "uint32_t")
143             {
144                 auto tempValue = std::get<uint32_t>(value);
145                 value = static_cast<uint32_t>(tempValue);
146             }
147             break;
148         }
149         case PLDM_EFFECTER_DATA_SIZE_SINT32:
150         {
151             auto rawValue = static_cast<int32_t>(
152                 round(effecterValue - pdr->offset) / pdr->resolution);
153             if (pdr->min_settable.value_s32 < pdr->max_settable.value_s32 &&
154                 (rawValue < pdr->min_settable.value_s32 ||
155                  rawValue > pdr->max_settable.value_s32))
156             {
157                 rc = PLDM_ERROR_INVALID_DATA;
158             }
159             value = rawValue;
160             if (propertyType == "uint64_t")
161             {
162                 auto tempValue = std::get<int32_t>(value);
163                 value = static_cast<uint64_t>(tempValue);
164             }
165             else if (propertyType == "uint32_t")
166             {
167                 auto tempValue = std::get<int32_t>(value);
168                 value = static_cast<uint32_t>(tempValue);
169             }
170             break;
171         }
172     }
173 
174     return {rc, std::make_optional(std::move(value))};
175 }
176 
177 /** @brief Function to convert the D-Bus value by PDR factor and effecter value.
178  *  @param[in] pdr - The structure of pldm_numeric_effecter_value_pdr.
179  *  @param[in] effecterDataSize - effecter value size.
180  *  @param[in,out] effecterValue - effecter value.
181  *  @param[in] propertyType - type of the D-Bus property.
182  *
183  *  @return std::pair<int, std::optional<PropertyValue>> - rc:Success or
184  *          failure, PropertyValue: The value to be set
185  */
186 std::pair<int, std::optional<pldm::utils::PropertyValue>>
187     convertToDbusValue(const pldm_numeric_effecter_value_pdr* pdr,
188                        uint8_t effecterDataSize, uint8_t* effecterValue,
189                        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         std::cerr << "Wrong field effecterDataSize...\n";
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 atleast one state fails to be set
245  */
246 template <class DBusInterface, class Handler>
247 int setNumericEffecterValueHandler(const DBusInterface& dBusIntf,
248                                    Handler& handler, uint16_t effecterId,
249                                    uint8_t effecterDataSize,
250                                    uint8_t* effecterValue,
251                                    size_t effecterValueLength)
252 {
253     constexpr auto effecterValueArrayLength = 4;
254     pldm_numeric_effecter_value_pdr* pdr = nullptr;
255 
256     std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)>
257         numericEffecterPdrRepo(pldm_pdr_init(), pldm_pdr_destroy);
258     pldm::responder::pdr_utils::Repo numericEffecterPDRs(
259         numericEffecterPdrRepo.get());
260     pldm::responder::pdr::getRepoByType(handler.getRepo(), numericEffecterPDRs,
261                                         PLDM_NUMERIC_EFFECTER_PDR);
262     if (numericEffecterPDRs.empty())
263     {
264         std::cerr << "The Numeric Effecter PDR repo is empty." << std::endl;
265         return PLDM_ERROR;
266     }
267 
268     // Get the pdr structure of pldm_numeric_effecter_value_pdr according
269     // to the effecterId
270     pldm::responder::pdr_utils::PdrEntry pdrEntry{};
271     auto pdrRecord = numericEffecterPDRs.getFirstRecord(pdrEntry);
272     while (pdrRecord)
273     {
274         pdr = reinterpret_cast<pldm_numeric_effecter_value_pdr*>(pdrEntry.data);
275         if (pdr->effecter_id != effecterId)
276         {
277             pdr = nullptr;
278             pdrRecord = numericEffecterPDRs.getNextRecord(pdrRecord, pdrEntry);
279             continue;
280         }
281 
282         break;
283     }
284 
285     if (!pdr)
286     {
287         return PLDM_PLATFORM_INVALID_EFFECTER_ID;
288     }
289 
290     if (effecterValueLength != effecterValueArrayLength)
291     {
292         std::cerr << "effecter data size is incorrect.\n";
293         return PLDM_ERROR_INVALID_DATA;
294     }
295 
296     try
297     {
298         const auto& [dbusMappings, dbusValMaps] =
299             handler.getDbusObjMaps(effecterId);
300         pldm::utils::DBusMapping dbusMapping{
301             dbusMappings[0].objectPath, dbusMappings[0].interface,
302             dbusMappings[0].propertyName, dbusMappings[0].propertyType};
303 
304         // convert to dbus effectervalue according to the factor
305         auto [rc, dbusValue] = convertToDbusValue(
306             pdr, effecterDataSize, effecterValue, dbusMappings[0].propertyType);
307         if (rc != PLDM_SUCCESS)
308         {
309             return rc;
310         }
311         try
312         {
313             dBusIntf.setDbusProperty(dbusMapping, dbusValue.value());
314         }
315         catch (const std::exception& e)
316         {
317             std::cerr << "Error setting property, ERROR=" << e.what()
318                       << " PROPERTY=" << dbusMapping.propertyName
319                       << " INTERFACE=" << dbusMapping.interface << " PATH="
320                       << dbusMapping.objectPath << "\n";
321             return PLDM_ERROR;
322         }
323     }
324     catch (const std::out_of_range& e)
325     {
326         std::cerr << "Unknown effecter ID : " << effecterId << e.what() << '\n';
327         return PLDM_ERROR;
328     }
329 
330     return PLDM_SUCCESS;
331 }
332 
333 } // namespace platform_numeric_effecter
334 } // namespace responder
335 } // namespace pldm
336