1 /*
2  * Copyright (c) 2011-2016, Intel Corporation
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this
9  * list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation and/or
13  * other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors
16  * may be used to endorse or promote products derived from this software without
17  * specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 #pragma once
31 
32 #include "BaseIntegerParameterType.h"
33 #include "ParameterAdaptation.h"
34 #include "ParameterAccessContext.h"
35 
36 #include <convert.hpp>
37 
38 #include <type_traits>
39 #include <sstream>
40 #include <string>
41 #include <limits>
42 #include <iomanip>
43 
44 namespace detail
45 {
46 template <bool isSigned, size_t size>
47 struct IntegerTraits
48 {
49     static_assert(size == 8 or size == 16 or size == 32,
50                   "IntegerParameterType size must be 8, 16 or 32.");
51 
52 private:
53     // Assumes that size is either 8, 16 or 32, which is ensured by the static_assert above.
54     using Signed = typename std::conditional<
55         size == 8, int8_t, typename std::conditional<size == 16, int16_t, int32_t>::type>::type;
56     using Unsigned = typename std::make_unsigned<Signed>::type;
57 
58 public:
59     using CType = typename std::conditional<isSigned, Signed, Unsigned>::type;
60 };
61 } // namespace detail
62 
63 template <bool isSigned, size_t bitSize>
64 class CIntegerParameterType : public CBaseIntegerParameterType
65 {
66 private:
67     using Base = CBaseIntegerParameterType;
68     using CType = typename detail::IntegerTraits<isSigned, bitSize>::CType;
69 
70     template <class UserType>
doToBlackboard(UserType userValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext)71     bool doToBlackboard(UserType userValue, uint32_t &uiValue,
72                         CParameterAccessContext &parameterAccessContext) const
73     {
74         {
75             if (userValue < static_cast<UserType>(_min) ||
76                 userValue > static_cast<UserType>(_max)) {
77 
78                 parameterAccessContext.setError("Value out of range");
79                 return false;
80             }
81             // Do assign
82             uiValue = userValue;
83 
84             return true;
85         }
86     }
87 
88 public:
CIntegerParameterType(const std::string & name)89     CIntegerParameterType(const std::string &name) : Base(name){};
90 
91     // From IXmlSink
fromXml(const CXmlElement & xmlElement,CXmlSerializingContext & serializingContext)92     bool fromXml(const CXmlElement &xmlElement, CXmlSerializingContext &serializingContext) override
93     {
94         setSize(bitSize / 8);
95 
96         xmlElement.getAttribute("Min", _min);
97         xmlElement.getAttribute("Max", _max);
98 
99         if (_min > _max) {
100             serializingContext.setError("The range of allowed value is empty (" +
101                                         std::to_string(_min) + " > " + std::to_string(_max) + ").");
102             return false;
103         }
104 
105         // Base
106         return Base::fromXml(xmlElement, serializingContext);
107     }
108 
109     // From IXmlSource
toXml(CXmlElement & xmlElement,CXmlSerializingContext & serializingContext)110     void toXml(CXmlElement &xmlElement, CXmlSerializingContext &serializingContext) const override
111     {
112         xmlElement.setAttribute("Signed", isSigned);
113 
114         xmlElement.setAttribute("Min", _min);
115         xmlElement.setAttribute("Max", _max);
116 
117         xmlElement.setAttribute("Size", bitSize);
118 
119         Base::toXml(xmlElement, serializingContext);
120     }
121 
fromBlackboard(std::string & strValue,const uint32_t & value,CParameterAccessContext & parameterAccessContext)122     bool fromBlackboard(std::string &strValue, const uint32_t &value,
123                         CParameterAccessContext &parameterAccessContext) const override
124     {
125         // Format
126         std::ostringstream stream;
127 
128         // Take care of format
129         if (parameterAccessContext.valueSpaceIsRaw() &&
130             parameterAccessContext.outputRawFormatIsHex()) {
131 
132             // Hexa display with unecessary bits cleared out
133             stream << "0x" << std::hex << std::uppercase
134                    << std::setw(static_cast<int>(getSize() * 2)) << std::setfill('0') << value;
135         } else {
136 
137             if (isSigned) {
138 
139                 int32_t iValue = value;
140 
141                 // Sign extend
142                 signExtend(iValue);
143 
144                 stream << iValue;
145             } else {
146 
147                 stream << value;
148             }
149         }
150 
151         strValue = stream.str();
152 
153         return true;
154     }
155 
156     // Value access
157     // Integer
toBlackboard(uint32_t uiUserValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext)158     bool toBlackboard(uint32_t uiUserValue, uint32_t &uiValue,
159                       CParameterAccessContext &parameterAccessContext) const override
160     {
161         return doToBlackboard(uiUserValue, uiValue, parameterAccessContext);
162     }
163 
164     // Signed Integer
toBlackboard(int32_t iUserValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext)165     bool toBlackboard(int32_t iUserValue, uint32_t &uiValue,
166                       CParameterAccessContext &parameterAccessContext) const override
167     {
168         return doToBlackboard(iUserValue, uiValue, parameterAccessContext);
169     }
170 
171     // Double
toBlackboard(double dUserValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext)172     bool toBlackboard(double dUserValue, uint32_t &uiValue,
173                       CParameterAccessContext &parameterAccessContext) const override
174     {
175         // Check if there's an adaptation object available
176         const CParameterAdaptation *pParameterAdaption = getParameterAdaptation();
177 
178         if (!pParameterAdaption) {
179 
180             // Reject request and let upper class handle the error
181             return Base::toBlackboard(dUserValue, uiValue, parameterAccessContext);
182         }
183 
184         // Do the conversion
185         int64_t iConvertedValue = pParameterAdaption->fromUserValue(dUserValue);
186 
187         if (iConvertedValue < _min || iConvertedValue > _max) {
188 
189             parameterAccessContext.setError("Value out of range");
190 
191             return false;
192         }
193 
194         // Do assign
195         uiValue = (uint32_t)iConvertedValue;
196 
197         return true;
198     }
199 
200     template <class T>
toBlackboard(const std::string & strValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext)201     bool toBlackboard(const std::string &strValue, uint32_t &uiValue,
202                       CParameterAccessContext &parameterAccessContext) const
203     {
204         T intermediate;
205         if (not convertTo(strValue, intermediate)) {
206             std::string strError;
207             strError = "Impossible to convert value " + strValue + " for " + getKind();
208 
209             parameterAccessContext.setError(strError);
210             return false;
211         }
212 
213         CType value = static_cast<CType>(intermediate);
214         if (!checkValueAgainstRange(strValue, intermediate, parameterAccessContext,
215                                     utility::isHexadecimal(strValue))) {
216             return false;
217         }
218         uiValue = (uint32_t)value;
219 
220         return true;
221     }
222 
223     // String
toBlackboard(const std::string & strValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext)224     bool toBlackboard(const std::string &strValue, uint32_t &uiValue,
225                       CParameterAccessContext &parameterAccessContext) const override
226     {
227         if (isSigned and utility::isHexadecimal(strValue)) {
228             using Intermediate = typename std::make_unsigned<CType>::type;
229 
230             return toBlackboard<Intermediate>(strValue, uiValue, parameterAccessContext);
231         } else {
232             return toBlackboard<CType>(strValue, uiValue, parameterAccessContext);
233         }
234     }
235 
fromBlackboard(double & dUserValue,uint32_t uiValue,CParameterAccessContext & parameterAccessContext)236     bool fromBlackboard(double &dUserValue, uint32_t uiValue,
237                         CParameterAccessContext &parameterAccessContext) const override
238     {
239         // Check if there's an adaptation object available
240         const CParameterAdaptation *pParameterAdaption = getParameterAdaptation();
241 
242         if (!pParameterAdaption) {
243 
244             // Reject request and let upper class handle the error
245             return Base::fromBlackboard(dUserValue, uiValue, parameterAccessContext);
246         }
247 
248         int64_t iValueToConvert;
249 
250         // Deal with signed data
251         if (isSigned) {
252 
253             int32_t iValue = uiValue;
254 
255             signExtend(iValue);
256 
257             iValueToConvert = iValue;
258         } else {
259 
260             iValueToConvert = uiValue;
261         }
262 
263         // Do the conversion
264         dUserValue = pParameterAdaption->toUserValue(iValueToConvert);
265 
266         return true;
267     }
268 
269     // Default value handling (simulation only)
getDefaultValue()270     uint32_t getDefaultValue() const override { return _min; }
271 
272     // Element properties
showProperties(std::string & strResult)273     void showProperties(std::string &strResult) const override
274     {
275         Base::showProperties(strResult);
276 
277         std::ostringstream stream;
278         stream << "Signed: " << (isSigned ? "yes" : "no") << "\n"
279                << "Min: " << _min << "\n"
280                << "Max: " << _max << "\n";
281 
282         strResult += stream.str();
283 
284         // Check if there's an adaptation object available
285         const CParameterAdaptation *pParameterAdaption = getParameterAdaptation();
286 
287         if (pParameterAdaption) {
288 
289             // Display adaptation properties
290             strResult += "Adaptation:\n";
291 
292             pParameterAdaption->showProperties(strResult);
293         }
294     }
295 
296     // Integer conversion
toPlainInteger(int iSizeOptimizedData)297     int toPlainInteger(int iSizeOptimizedData) const override
298     {
299         if (isSigned) {
300 
301             signExtend(iSizeOptimizedData);
302         }
303 
304         return Base::toPlainInteger(iSizeOptimizedData);
305     }
306 
307     // Range checking
checkValueAgainstRange(const std::string & strValue,CType value,CParameterAccessContext & parameterAccessContext,bool bHexaValue)308     bool checkValueAgainstRange(const std::string &strValue, CType value,
309                                 CParameterAccessContext &parameterAccessContext,
310                                 bool bHexaValue) const
311     {
312         if (value < _min || value > _max) {
313 
314             std::ostringstream stream;
315 
316             stream << "Value " << strValue << " standing out of admitted range [";
317 
318             if (bHexaValue) {
319 
320                 stream << "0x" << std::hex << std::uppercase
321                        << std::setw(static_cast<int>(getSize() * 2)) << std::setfill('0');
322                 // Format Min
323                 stream << _min;
324                 // Format Max
325                 stream << _max;
326 
327             } else {
328 
329                 stream << _min << ", " << _max;
330             }
331 
332             stream << "] for " << getKind();
333 
334             parameterAccessContext.setError(stream.str());
335 
336             return false;
337         }
338         return true;
339     }
340 
341 private:
342     // Range
343     CType _min{std::numeric_limits<CType>::min()};
344     CType _max{std::numeric_limits<CType>::max()};
345 };
346