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), _uiIntegral(0), _uiFractional(0)
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 += CUtility::toString(_uiIntegral);
64 strResult += ".";
65 strResult += CUtility::toString(_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(CXmlElement& xmlConfigurableElementSettingsElement, CConfigurationAccessContext& configurationAccessContext) const
72 {
73 // Direction?
74 if (!configurationAccessContext.serializeOut()) {
75
76 // Get Value space from XML
77 if (xmlConfigurableElementSettingsElement.hasAttribute("ValueSpace")) {
78
79 configurationAccessContext.setValueSpaceRaw(xmlConfigurableElementSettingsElement.getAttributeBoolean("ValueSpace", "Raw"));
80 } else {
81
82 configurationAccessContext.setValueSpaceRaw(false);
83 }
84 } else {
85 // Provide value space only if not the default one
86 if (configurationAccessContext.valueSpaceIsRaw()) {
87
88 xmlConfigurableElementSettingsElement.setAttributeString("ValueSpace", "Raw");
89 }
90 }
91 }
92
fromXml(const CXmlElement & xmlElement,CXmlSerializingContext & serializingContext)93 bool CFixedPointParameterType::fromXml(const CXmlElement& xmlElement, CXmlSerializingContext& serializingContext)
94 {
95 // Size
96 uint32_t uiSizeInBits = xmlElement.getAttributeInteger("Size");
97
98 // Q notation
99 _uiIntegral = xmlElement.getAttributeInteger("Integral");
100 _uiFractional = xmlElement.getAttributeInteger("Fractional");
101
102 // Size vs. Q notation integrity check
103 if (uiSizeInBits < getUtilSizeInBits()) {
104
105 serializingContext.setError("Inconsistent Size vs. Q notation for " + getKind() + " " + xmlElement.getPath() + ": Summing (Integral + _uiFractional + 1) should not exceed given Size (" + xmlElement.getAttributeString("Size") + ")");
106
107 return false;
108 }
109
110 // Set the size
111 setSize(uiSizeInBits / 8);
112
113 return base::fromXml(xmlElement, serializingContext);
114 }
115
toBlackboard(const string & strValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext) const116 bool CFixedPointParameterType::toBlackboard(const string& strValue, uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const
117 {
118 bool bValueProvidedAsHexa = isHexadecimal(strValue);
119
120 // Check data integrity
121 if (bValueProvidedAsHexa && !parameterAccessContext.valueSpaceIsRaw()) {
122
123 parameterAccessContext.setError("Hexadecimal values are not supported for " + getKind() + " when selected value space is real:");
124
125 return false;
126 }
127
128 if (parameterAccessContext.valueSpaceIsRaw()) {
129
130 if (bValueProvidedAsHexa) {
131
132 return convertFromHexadecimal(strValue, uiValue, parameterAccessContext);
133
134 }
135 return convertFromDecimal(strValue, uiValue, parameterAccessContext);
136 }
137 return convertFromQnm(strValue, uiValue, parameterAccessContext);
138 }
139
setOutOfRangeError(const string & strValue,CParameterAccessContext & parameterAccessContext) const140 void CFixedPointParameterType::setOutOfRangeError(const string& strValue, CParameterAccessContext& parameterAccessContext) const
141 {
142 std::ostringstream strStream;
143
144 strStream << "Value " << strValue << " standing out of admitted ";
145
146 if (!parameterAccessContext.valueSpaceIsRaw()) {
147
148 // Min/Max computation
149 double dMin = 0;
150 double dMax = 0;
151 getRange(dMin, dMax);
152
153 strStream << std::fixed << std::setprecision(_uiFractional)
154 << "real range [" << dMin << ", " << dMax << "]";
155 } else {
156
157 // Min/Max computation
158 int32_t iMax = getMaxValue<uint32_t>();
159 int32_t iMin = -iMax - 1;
160
161 strStream << "raw range [";
162
163 if (isHexadecimal(strValue)) {
164
165 // Format Min
166 strStream << "0x" << std::hex << std::uppercase <<
167 std::setw(getSize() * 2) << std::setfill('0') << makeEncodable(iMin);
168 // Format Max
169 strStream << ", 0x" << std::hex << std::uppercase <<
170 std::setw(getSize() * 2) << std::setfill('0') << makeEncodable(iMax);
171
172 } else {
173
174 strStream << iMin << ", " << iMax;
175 }
176
177 strStream << "]";
178 }
179 strStream << " for " << getKind();
180
181 parameterAccessContext.setError(strStream.str());
182 }
183
fromBlackboard(string & strValue,const uint32_t & uiValue,CParameterAccessContext & parameterAccessContext) const184 bool CFixedPointParameterType::fromBlackboard(string& strValue, const uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const
185 {
186 int32_t iData = uiValue;
187
188 // Check encodability
189 assert(isEncodable((uint32_t)iData, false));
190
191 // Format
192 std::ostringstream strStream;
193
194 // Raw formatting?
195 if (parameterAccessContext.valueSpaceIsRaw()) {
196
197 // Hexa formatting?
198 if (parameterAccessContext.outputRawFormatIsHex()) {
199
200 strStream << "0x" << std::hex << std::uppercase << std::setw(getSize()*2) << std::setfill('0') << (uint32_t)iData;
201 } else {
202
203 // Sign extend
204 signExtend(iData);
205
206 strStream << iData;
207 }
208 } else {
209
210 // Sign extend
211 signExtend(iData);
212
213 // Conversion
214 double dData = binaryQnmToDouble(iData);
215
216 strStream << std::fixed << std::setprecision(_uiFractional) << dData;
217 }
218
219 strValue = strStream.str();
220
221 return true;
222 }
223
224 // Value access
toBlackboard(double dUserValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext) const225 bool CFixedPointParameterType::toBlackboard(double dUserValue, uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const
226 {
227 // Check that the value is within the allowed range for this type
228 if (!checkValueAgainstRange(dUserValue)) {
229
230 // Illegal value provided
231 parameterAccessContext.setError("Value out of range");
232
233 return false;
234 }
235
236 // Do the conversion
237 int32_t iData = doubleToBinaryQnm(dUserValue);
238
239 // Check integrity
240 assert(isEncodable((uint32_t)iData, true));
241
242 uiValue = iData;
243
244 return true;
245 }
246
fromBlackboard(double & dUserValue,uint32_t uiValue,CParameterAccessContext & parameterAccessContext) const247 bool CFixedPointParameterType::fromBlackboard(double& dUserValue, uint32_t uiValue, CParameterAccessContext& parameterAccessContext) const
248 {
249 (void)parameterAccessContext;
250
251 int32_t iData = uiValue;
252
253 // Check unsigned value is encodable
254 assert(isEncodable(uiValue, false));
255
256 // Sign extend
257 signExtend(iData);
258
259 dUserValue = binaryQnmToDouble(iData);
260
261 return true;
262 }
263
264 // Util size
getUtilSizeInBits() const265 uint32_t CFixedPointParameterType::getUtilSizeInBits() const
266 {
267 return _uiIntegral + _uiFractional + 1;
268 }
269
270 // Compute the range for the type (minimum and maximum values)
getRange(double & dMin,double & dMax) const271 void CFixedPointParameterType::getRange(double& dMin, double& dMax) const
272 {
273 dMax = (double)((1UL << (_uiIntegral + _uiFractional)) - 1) / (1UL << _uiFractional);
274 dMin = -(double)(1UL << (_uiIntegral + _uiFractional)) / (1UL << _uiFractional);
275 }
276
isHexadecimal(const string & strValue) const277 bool CFixedPointParameterType::isHexadecimal(const string& strValue) const
278 {
279 return !strValue.compare(0, 2, "0x");
280 }
281
convertFromHexadecimal(const string & strValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext) const282 bool CFixedPointParameterType::convertFromHexadecimal(const string& strValue, uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const
283 {
284 // For hexadecimal representation, we need full 32 bit range conversion.
285 uint32_t uiData;
286 if (!convertTo(strValue, uiData) || !isEncodable(uiData, false)) {
287
288 setOutOfRangeError(strValue, parameterAccessContext);
289 return false;
290 }
291 signExtend((int32_t&)uiData);
292
293 // check that the data is encodable and can been safely written to the blackboard
294 assert(isEncodable(uiData, true));
295 uiValue = uiData;
296
297 return true;
298 }
299
convertFromDecimal(const string & strValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext) const300 bool CFixedPointParameterType::convertFromDecimal(const string& strValue, uint32_t& uiValue, CParameterAccessContext& parameterAccessContext) const
301 {
302 int32_t iData;
303
304 if (!convertTo(strValue, iData) || !isEncodable((uint32_t)iData, true)) {
305
306 setOutOfRangeError(strValue, parameterAccessContext);
307 return false;
308 }
309 uiValue = static_cast<uint32_t>(iData);
310
311 return true;
312 }
313
convertFromQnm(const string & strValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext) const314 bool CFixedPointParameterType::convertFromQnm(const string& strValue, uint32_t& uiValue,
315 CParameterAccessContext& parameterAccessContext) const
316 {
317 double dData;
318
319 if (!convertTo(strValue, dData) || !checkValueAgainstRange(dData)) {
320
321 setOutOfRangeError(strValue, parameterAccessContext);
322 return false;
323 }
324 uiValue = static_cast<uint32_t>(doubleToBinaryQnm(dData));
325
326 // check that the data is encodable and has been safely written to the blackboard
327 assert(isEncodable(uiValue, true));
328
329 return true;
330 }
331
332 // Check that the value is within available range for this type
checkValueAgainstRange(double dValue) const333 bool CFixedPointParameterType::checkValueAgainstRange(double dValue) const
334 {
335 double dMin = 0;
336 double dMax = 0;
337 getRange(dMin, dMax);
338
339 return (dValue <= dMax) && (dValue >= dMin);
340 }
341
342 // Data conversion
doubleToBinaryQnm(double dValue) const343 int32_t CFixedPointParameterType::doubleToBinaryQnm(double dValue) const
344 {
345 // For Qn.m number, multiply by 2^n and round to the nearest integer
346 int32_t iData = static_cast<int32_t>(round(dValue * (1UL << _uiFractional)));
347 // Left justify
348 // For a Qn.m number, shift 32 - (n + m + 1) bits to the left (the rest of
349 // the bits aren't used)
350 iData <<= getSize() * 8 - getUtilSizeInBits();
351
352 return iData;
353 }
354
355
binaryQnmToDouble(int32_t iValue) const356 double CFixedPointParameterType::binaryQnmToDouble(int32_t iValue) const
357 {
358 // Unjustify
359 iValue >>= getSize() * 8 - getUtilSizeInBits();
360 return static_cast<double>(iValue) / (1UL << _uiFractional);
361 }
362
363 // From IXmlSource
toXml(CXmlElement & xmlElement,CXmlSerializingContext & serializingContext) const364 void CFixedPointParameterType::toXml(CXmlElement& xmlElement, CXmlSerializingContext& serializingContext) const
365 {
366 // Size
367 xmlElement.setAttributeString("Size", CUtility::toString(getSize() * 8));
368
369 // Integral
370 xmlElement.setAttributeString("Integral", CUtility::toString(_uiIntegral));
371
372 // Fractional
373 xmlElement.setAttributeString("Fractional", CUtility::toString(_uiFractional));
374
375 base::toXml(xmlElement, serializingContext);
376 }
377