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