1 /*
2 * Copyright (c) 2011-2015, 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 #include "FixedPointParameterType.h"
31 #include <stdlib.h>
32 #include <sstream>
33 #include <iomanip>
34 #include <assert.h>
35 #include <math.h>
36 #include "Parameter.h"
37 #include "ParameterAccessContext.h"
38 #include "ConfigurationAccessContext.h"
39 #include "Utility.h"
40 #include <errno.h>
41 #include <convert.hpp>
42
43 #define base CParameterType
44
45 using std::string;
46
CFixedPointParameterType(const string & strName)47 CFixedPointParameterType::CFixedPointParameterType(const string &strName) : base(strName)
48 {
49 }
50
getKind() const51 string CFixedPointParameterType::getKind() const
52 {
53 return "FixedPointParameter";
54 }
55
56 // Element properties
showProperties(string & strResult) const57 void CFixedPointParameterType::showProperties(string &strResult) const
58 {
59 base::showProperties(strResult);
60
61 // Notation
62 strResult += "Notation: Q";
63 strResult += std::to_string(_uiIntegral);
64 strResult += ".";
65 strResult += std::to_string(_uiFractional);
66 strResult += "\n";
67 }
68
69 // XML Serialization value space handling
70 // Value space handling for configuration import
handleValueSpaceAttribute(CXmlElement & xmlConfigurableElementSettingsElement,CConfigurationAccessContext & configurationAccessContext) const71 void CFixedPointParameterType::handleValueSpaceAttribute(
72 CXmlElement &xmlConfigurableElementSettingsElement,
73 CConfigurationAccessContext &configurationAccessContext) const
74 {
75 // Direction?
76 if (!configurationAccessContext.serializeOut()) {
77
78 string strValueSpace;
79 xmlConfigurableElementSettingsElement.getAttribute("ValueSpace", strValueSpace);
80 configurationAccessContext.setValueSpaceRaw(strValueSpace == "Raw");
81 } else {
82 // Provide value space only if not the default one
83 if (configurationAccessContext.valueSpaceIsRaw()) {
84
85 xmlConfigurableElementSettingsElement.setAttribute("ValueSpace", "Raw");
86 }
87 }
88 }
89
fromXml(const CXmlElement & xmlElement,CXmlSerializingContext & serializingContext)90 bool CFixedPointParameterType::fromXml(const CXmlElement &xmlElement,
91 CXmlSerializingContext &serializingContext)
92 {
93 // Size
94 size_t sizeInBits = 0;
95 xmlElement.getAttribute("Size", sizeInBits);
96
97 // Q notation
98 xmlElement.getAttribute("Integral", _uiIntegral);
99 xmlElement.getAttribute("Fractional", _uiFractional);
100
101 // Size vs. Q notation integrity check
102 if (sizeInBits < getUtilSizeInBits()) {
103
104 std::string size;
105 xmlElement.getAttribute("Size", size);
106 serializingContext.setError(
107 "Inconsistent Size vs. Q notation for " + getKind() + " " + xmlElement.getPath() +
108 ": Summing (Integral + _uiFractional + 1) should not exceed given Size (" + size + ")");
109
110 return false;
111 }
112
113 // Set the size
114 setSize(sizeInBits / 8);
115
116 return base::fromXml(xmlElement, serializingContext);
117 }
118
toBlackboard(const string & strValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext) const119 bool CFixedPointParameterType::toBlackboard(const string &strValue, uint32_t &uiValue,
120 CParameterAccessContext ¶meterAccessContext) const
121 {
122 bool bValueProvidedAsHexa = utility::isHexadecimal(strValue);
123
124 // Check data integrity
125 if (bValueProvidedAsHexa && !parameterAccessContext.valueSpaceIsRaw()) {
126
127 parameterAccessContext.setError("Hexadecimal values are not supported for " + getKind() +
128 " when selected value space is real:");
129
130 return false;
131 }
132
133 if (parameterAccessContext.valueSpaceIsRaw()) {
134
135 if (bValueProvidedAsHexa) {
136
137 return convertFromHexadecimal(strValue, uiValue, parameterAccessContext);
138 }
139 return convertFromDecimal(strValue, uiValue, parameterAccessContext);
140 }
141 return convertFromQnm(strValue, uiValue, parameterAccessContext);
142 }
143
setOutOfRangeError(const string & strValue,CParameterAccessContext & parameterAccessContext) const144 void CFixedPointParameterType::setOutOfRangeError(
145 const string &strValue, CParameterAccessContext ¶meterAccessContext) const
146 {
147 std::ostringstream stream;
148
149 stream << "Value " << strValue << " standing out of admitted ";
150
151 if (!parameterAccessContext.valueSpaceIsRaw()) {
152
153 // Min/Max computation
154 double dMin = 0;
155 double dMax = 0;
156 getRange(dMin, dMax);
157
158 stream << std::fixed << std::setprecision(_uiFractional) << "real range [" << dMin << ", "
159 << dMax << "]";
160 } else {
161
162 // Min/Max computation
163 int32_t iMax = getMaxValue<uint32_t>();
164 int32_t iMin = -iMax - 1;
165
166 stream << "raw range [";
167
168 if (utility::isHexadecimal(strValue)) {
169
170 stream << std::hex << std::uppercase << std::setw(static_cast<int>(getSize()) * 2)
171 << std::setfill('0');
172
173 // Format Min
174 stream << "0x" << makeEncodable(iMin);
175 // Format Max
176 stream << ", 0x" << makeEncodable(iMax);
177
178 } else {
179
180 stream << iMin << ", " << iMax;
181 }
182
183 stream << "]";
184 }
185 stream << " for " << getKind();
186
187 parameterAccessContext.setError(stream.str());
188 }
189
fromBlackboard(string & strValue,const uint32_t & value,CParameterAccessContext & parameterAccessContext) const190 bool CFixedPointParameterType::fromBlackboard(string &strValue, const uint32_t &value,
191 CParameterAccessContext ¶meterAccessContext) const
192 {
193 // Check encodability
194 assert(isEncodable(value, false));
195
196 // Format
197 std::ostringstream stream;
198
199 // Raw formatting?
200 if (parameterAccessContext.valueSpaceIsRaw()) {
201 // Hexa formatting?
202 if (parameterAccessContext.outputRawFormatIsHex()) {
203 uint32_t data = static_cast<uint32_t>(value);
204
205 stream << "0x" << std::hex << std::uppercase
206 << std::setw(static_cast<int>(getSize() * 2)) << std::setfill('0') << data;
207 } else {
208 int32_t data = value;
209
210 // Sign extend
211 signExtend(data);
212
213 stream << data;
214 }
215 } else {
216 int32_t data = value;
217
218 // Sign extend
219 signExtend(data);
220
221 // Conversion
222 stream << std::fixed << std::setprecision(_uiFractional) << binaryQnmToDouble(data);
223 }
224
225 strValue = stream.str();
226
227 return true;
228 }
229
230 // Value access
toBlackboard(double dUserValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext) const231 bool CFixedPointParameterType::toBlackboard(double dUserValue, uint32_t &uiValue,
232 CParameterAccessContext ¶meterAccessContext) const
233 {
234 // Check that the value is within the allowed range for this type
235 if (!checkValueAgainstRange(dUserValue)) {
236
237 // Illegal value provided
238 parameterAccessContext.setError("Value out of range");
239
240 return false;
241 }
242
243 // Do the conversion
244 int32_t iData = doubleToBinaryQnm(dUserValue);
245
246 // Check integrity
247 assert(isEncodable((uint32_t)iData, true));
248
249 uiValue = iData;
250
251 return true;
252 }
253
fromBlackboard(double & dUserValue,uint32_t uiValue,CParameterAccessContext &) const254 bool CFixedPointParameterType::fromBlackboard(double &dUserValue, uint32_t uiValue,
255 CParameterAccessContext & /*ctx*/) const
256 {
257 int32_t iData = uiValue;
258
259 // Check unsigned value is encodable
260 assert(isEncodable(uiValue, false));
261
262 // Sign extend
263 signExtend(iData);
264
265 dUserValue = binaryQnmToDouble(iData);
266
267 return true;
268 }
269
270 // Util size
getUtilSizeInBits() const271 size_t CFixedPointParameterType::getUtilSizeInBits() const
272 {
273 return _uiIntegral + _uiFractional + 1;
274 }
275
276 // Compute the range for the type (minimum and maximum values)
getRange(double & dMin,double & dMax) const277 void CFixedPointParameterType::getRange(double &dMin, double &dMax) const
278 {
279 dMax = ((1U << (_uiIntegral + _uiFractional)) - 1) / double(1U << _uiFractional);
280 dMin = -((1U << (_uiIntegral + _uiFractional)) / double(1U << _uiFractional));
281 }
282
convertFromHexadecimal(const string & strValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext) const283 bool CFixedPointParameterType::convertFromHexadecimal(
284 const string &strValue, uint32_t &uiValue,
285 CParameterAccessContext ¶meterAccessContext) const
286 {
287 // For hexadecimal representation, we need full 32 bit range conversion.
288 if (!convertTo(strValue, uiValue) || !isEncodable(uiValue, false)) {
289
290 setOutOfRangeError(strValue, parameterAccessContext);
291 return false;
292 }
293 signExtend(reinterpret_cast<int32_t &>(uiValue));
294
295 // check that the data is encodable and can been safely written to the blackboard
296 assert(isEncodable(uiValue, true));
297
298 return true;
299 }
300
convertFromDecimal(const string & strValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext) const301 bool CFixedPointParameterType::convertFromDecimal(
302 const string &strValue, uint32_t &uiValue,
303 CParameterAccessContext ¶meterAccessContext) const
304 {
305 if (!convertTo(strValue, reinterpret_cast<int32_t &>(uiValue)) || !isEncodable(uiValue, true)) {
306
307 setOutOfRangeError(strValue, parameterAccessContext);
308 return false;
309 }
310 return true;
311 }
312
convertFromQnm(const string & strValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext) const313 bool CFixedPointParameterType::convertFromQnm(const string &strValue, uint32_t &uiValue,
314 CParameterAccessContext ¶meterAccessContext) const
315 {
316 double dData = 0;
317
318 if (!convertTo(strValue, dData) || !checkValueAgainstRange(dData)) {
319
320 setOutOfRangeError(strValue, parameterAccessContext);
321 return false;
322 }
323 uiValue = static_cast<uint32_t>(doubleToBinaryQnm(dData));
324
325 // check that the data is encodable and has been safely written to the blackboard
326 assert(isEncodable(uiValue, true));
327
328 return true;
329 }
330
331 // Check that the value is within available range for this type
checkValueAgainstRange(double dValue) const332 bool CFixedPointParameterType::checkValueAgainstRange(double dValue) const
333 {
334 double dMin = 0;
335 double dMax = 0;
336 getRange(dMin, dMax);
337
338 return (dValue <= dMax) && (dValue >= dMin);
339 }
340
341 // Data conversion
doubleToBinaryQnm(double dValue) const342 int32_t CFixedPointParameterType::doubleToBinaryQnm(double dValue) const
343 {
344 // For Qn.m number, multiply by 2^n and round to the nearest integer
345 int32_t iData = static_cast<int32_t>(round(dValue * double(1UL << _uiFractional)));
346 // Left justify
347 // For a Qn.m number, shift 32 - (n + m + 1) bits to the left (the rest of
348 // the bits aren't used)
349 iData <<= getSize() * 8 - getUtilSizeInBits();
350
351 return iData;
352 }
353
binaryQnmToDouble(int32_t iValue) const354 double CFixedPointParameterType::binaryQnmToDouble(int32_t iValue) const
355 {
356 // Unjustify
357 iValue >>= getSize() * 8 - getUtilSizeInBits();
358 return static_cast<double>(iValue) / double(1UL << _uiFractional);
359 }
360
361 // From IXmlSource
toXml(CXmlElement & xmlElement,CXmlSerializingContext & serializingContext) const362 void CFixedPointParameterType::toXml(CXmlElement &xmlElement,
363 CXmlSerializingContext &serializingContext) const
364 {
365 // Size
366 xmlElement.setAttribute("Size", getSize() * 8);
367
368 // Integral
369 xmlElement.setAttribute("Integral", _uiIntegral);
370
371 // Fractional
372 xmlElement.setAttribute("Fractional", _uiFractional);
373
374 base::toXml(xmlElement, serializingContext);
375 }
376