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