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             break;
62         }
63         case PLDM_EFFECTER_DATA_SIZE_SINT8:
64         {
65             auto rawValue = static_cast<int8_t>(
66                 round(effecterValue - pdr->offset) / pdr->resolution);
67             if (pdr->min_set_table.value_s8 < pdr->max_set_table.value_s8 &&
68                 (rawValue < pdr->min_set_table.value_s8 ||
69                  rawValue > pdr->max_set_table.value_s8))
70             {
71                 rc = PLDM_ERROR_INVALID_DATA;
72             }
73             value = rawValue;
74             break;
75         }
76         case PLDM_EFFECTER_DATA_SIZE_UINT16:
77         {
78             auto rawValue = static_cast<uint16_t>(
79                 round(effecterValue - pdr->offset) / pdr->resolution);
80             if (pdr->min_set_table.value_u16 < pdr->max_set_table.value_u16 &&
81                 (rawValue < pdr->min_set_table.value_u16 ||
82                  rawValue > pdr->max_set_table.value_u16))
83             {
84                 rc = PLDM_ERROR_INVALID_DATA;
85             }
86             value = rawValue;
87             if (propertyType == "uint64_t")
88             {
89                 auto tempValue = std::get<uint16_t>(value);
90                 value = static_cast<uint64_t>(tempValue);
91             }
92             break;
93         }
94         case PLDM_EFFECTER_DATA_SIZE_SINT16:
95         {
96             auto rawValue = static_cast<int16_t>(
97                 round(effecterValue - pdr->offset) / pdr->resolution);
98             if (pdr->min_set_table.value_s16 < pdr->max_set_table.value_s16 &&
99                 (rawValue < pdr->min_set_table.value_s16 ||
100                  rawValue > pdr->max_set_table.value_s16))
101             {
102                 rc = PLDM_ERROR_INVALID_DATA;
103             }
104             value = rawValue;
105             if (propertyType == "uint64_t")
106             {
107                 auto tempValue = std::get<int16_t>(value);
108                 value = static_cast<uint64_t>(tempValue);
109             }
110             break;
111         }
112         case PLDM_EFFECTER_DATA_SIZE_UINT32:
113         {
114             auto rawValue = static_cast<uint32_t>(
115                 round(effecterValue - pdr->offset) / pdr->resolution);
116             if (pdr->min_set_table.value_u32 < pdr->max_set_table.value_u32 &&
117                 (rawValue < pdr->min_set_table.value_u32 ||
118                  rawValue > pdr->max_set_table.value_u32))
119             {
120                 rc = PLDM_ERROR_INVALID_DATA;
121             }
122             value = rawValue;
123             if (propertyType == "uint64_t")
124             {
125                 auto tempValue = std::get<uint32_t>(value);
126                 value = static_cast<uint64_t>(tempValue);
127             }
128             break;
129         }
130         case PLDM_EFFECTER_DATA_SIZE_SINT32:
131         {
132             auto rawValue = static_cast<int32_t>(
133                 round(effecterValue - pdr->offset) / pdr->resolution);
134             if (pdr->min_set_table.value_s32 < pdr->max_set_table.value_s32 &&
135                 (rawValue < pdr->min_set_table.value_s32 ||
136                  rawValue > pdr->max_set_table.value_s32))
137             {
138                 rc = PLDM_ERROR_INVALID_DATA;
139             }
140             value = rawValue;
141             if (propertyType == "uint64_t")
142             {
143                 auto tempValue = std::get<int32_t>(value);
144                 value = static_cast<uint64_t>(tempValue);
145             }
146             break;
147         }
148     }
149 
150     return {rc, std::make_optional(std::move(value))};
151 }
152 
153 /** @brief Function to convert the D-Bus value by PDR factor and effecter value.
154  *  @param[in] pdr - The structure of pldm_numeric_effecter_value_pdr.
155  *  @param[in] effecterDataSize - effecter value size.
156  *  @param[in,out] effecterValue - effecter value.
157  *  @param[in] propertyType - type of the D-Bus property.
158  *
159  *  @return std::pair<int, std::optional<PropertyValue>> - rc:Success or
160  *          failure, PropertyValue: The value to be set
161  */
162 std::pair<int, std::optional<pldm::utils::PropertyValue>>
163     convertToDbusValue(const pldm_numeric_effecter_value_pdr* pdr,
164                        uint8_t effecterDataSize, uint8_t* effecterValue,
165                        std::string propertyType)
166 {
167     if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_UINT8)
168     {
169         uint8_t currentValue = *(reinterpret_cast<uint8_t*>(&effecterValue[0]));
170         return getEffecterRawValue<uint8_t>(pdr, currentValue, propertyType);
171     }
172     else if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_SINT8)
173     {
174         int8_t currentValue = *(reinterpret_cast<int8_t*>(&effecterValue[0]));
175         return getEffecterRawValue<int8_t>(pdr, currentValue, propertyType);
176     }
177     else if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_UINT16)
178     {
179         uint16_t currentValue =
180             *(reinterpret_cast<uint16_t*>(&effecterValue[0]));
181         return getEffecterRawValue<uint16_t>(pdr, currentValue, propertyType);
182     }
183     else if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_SINT16)
184     {
185         int16_t currentValue = *(reinterpret_cast<int16_t*>(&effecterValue[0]));
186         return getEffecterRawValue<int16_t>(pdr, currentValue, propertyType);
187     }
188     else if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_UINT32)
189     {
190         uint32_t currentValue =
191             *(reinterpret_cast<uint32_t*>(&effecterValue[0]));
192         return getEffecterRawValue<uint32_t>(pdr, currentValue, propertyType);
193     }
194     else if (effecterDataSize == PLDM_EFFECTER_DATA_SIZE_SINT32)
195     {
196         int32_t currentValue = *(reinterpret_cast<int32_t*>(&effecterValue[0]));
197         return getEffecterRawValue<int32_t>(pdr, currentValue, propertyType);
198     }
199     else
200     {
201         std::cerr << "Wrong field effecterDataSize...\n";
202         return {PLDM_ERROR, {}};
203     }
204 }
205 
206 /** @brief Function to set the effecter value requested by pldm requester
207  *  @tparam[in] DBusInterface - DBus interface type
208  *  @tparam[in] Handler - pldm::responder::platform::Handler
209  *  @param[in] dBusIntf - The interface object of DBusInterface
210  *  @param[in] handler - The interface object of
211  *             pldm::responder::platform::Handler
212  *  @param[in] effecterId - Effecter ID sent by the requester to act on
213  *  @param[in] effecterDataSize - The bit width and format of the setting
214  * 				value for the effecter
215  *  @param[in] effecter_value - The setting value of numeric effecter being
216  * 				requested.
217  *  @param[in] effecterValueLength - The setting value length of numeric
218  *              effecter being requested.
219  *  @return - Success or failure in setting the states. Returns failure in
220  * terms of PLDM completion codes if atleast one state fails to be set
221  */
222 template <class DBusInterface, class Handler>
223 int setNumericEffecterValueHandler(const DBusInterface& dBusIntf,
224                                    Handler& handler, uint16_t effecterId,
225                                    uint8_t effecterDataSize,
226                                    uint8_t* effecterValue,
227                                    size_t effecterValueLength)
228 {
229     constexpr auto effecterValueArrayLength = 4;
230     pldm_numeric_effecter_value_pdr* pdr = nullptr;
231 
232     std::unique_ptr<pldm_pdr, decltype(&pldm_pdr_destroy)>
233         numericEffecterPdrRepo(pldm_pdr_init(), pldm_pdr_destroy);
234     pldm::responder::pdr_utils::Repo numericEffecterPDRs(
235         numericEffecterPdrRepo.get());
236     pldm::responder::pdr::getRepoByType(handler.getRepo(), numericEffecterPDRs,
237                                         PLDM_NUMERIC_EFFECTER_PDR);
238     if (numericEffecterPDRs.empty())
239     {
240         std::cerr << "The Numeric Effecter PDR repo is empty." << std::endl;
241         return PLDM_ERROR;
242     }
243 
244     // Get the pdr structure of pldm_numeric_effecter_value_pdr according
245     // to the effecterId
246     pldm::responder::pdr_utils::PdrEntry pdrEntry{};
247     auto pdrRecord = numericEffecterPDRs.getFirstRecord(pdrEntry);
248     while (pdrRecord)
249     {
250         pdr = reinterpret_cast<pldm_numeric_effecter_value_pdr*>(pdrEntry.data);
251         if (pdr->effecter_id != effecterId)
252         {
253             pdr = nullptr;
254             pdrRecord = numericEffecterPDRs.getNextRecord(pdrRecord, pdrEntry);
255             continue;
256         }
257 
258         break;
259     }
260 
261     if (!pdr)
262     {
263         return PLDM_PLATFORM_INVALID_EFFECTER_ID;
264     }
265 
266     if (effecterValueLength != effecterValueArrayLength)
267     {
268         std::cerr << "effecter data size is incorrect.\n";
269         return PLDM_ERROR_INVALID_DATA;
270     }
271 
272     try
273     {
274         const auto& [dbusMappings, dbusValMaps] =
275             handler.getDbusObjMaps(effecterId);
276         pldm::utils::DBusMapping dbusMapping{
277             dbusMappings[0].objectPath, dbusMappings[0].interface,
278             dbusMappings[0].propertyName, dbusMappings[0].propertyType};
279 
280         // convert to dbus effectervalue according to the factor
281         auto [rc, dbusValue] = convertToDbusValue(
282             pdr, effecterDataSize, effecterValue, dbusMappings[0].propertyType);
283         if (rc != PLDM_SUCCESS)
284         {
285             return rc;
286         }
287         try
288         {
289 
290             dBusIntf.setDbusProperty(dbusMapping, dbusValue.value());
291         }
292         catch (const std::exception& e)
293         {
294             std::cerr << "Error setting property, ERROR=" << e.what()
295                       << " PROPERTY=" << dbusMapping.propertyName
296                       << " INTERFACE=" << dbusMapping.interface << " PATH="
297                       << dbusMapping.objectPath << "\n";
298             return PLDM_ERROR;
299         }
300     }
301     catch (const std::out_of_range& e)
302     {
303         std::cerr << "Unknown effecter ID : " << effecterId << e.what() << '\n';
304         return PLDM_ERROR;
305     }
306 
307     return PLDM_SUCCESS;
308 }
309 
310 } // namespace platform_numeric_effecter
311 } // namespace responder
312 } // namespace pldm
313