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 47 CFixedPointParameterType::CFixedPointParameterType(const string& strName) : base(strName), _uiIntegral(0), _uiFractional(0) 48 { 49 } 50 51 string CFixedPointParameterType::getKind() const 52 { 53 return "FixedPointParameter"; 54 } 55 56 // Element properties 57 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 71 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 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 116 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 140 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 184 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 225 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 247 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 265 uint32_t CFixedPointParameterType::getUtilSizeInBits() const 266 { 267 return _uiIntegral + _uiFractional + 1; 268 } 269 270 // Compute the range for the type (minimum and maximum values) 271 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 277 bool CFixedPointParameterType::isHexadecimal(const string& strValue) const 278 { 279 return !strValue.compare(0, 2, "0x"); 280 } 281 282 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 300 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 314 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 333 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 343 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 356 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 364 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