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