Home | History | Annotate | Download | only in parameter
      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)
     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 += 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
     71 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 
     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 
    119 bool CFixedPointParameterType::toBlackboard(const string &strValue, uint32_t &uiValue,
    120                                             CParameterAccessContext &parameterAccessContext) 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 
    144 void CFixedPointParameterType::setOutOfRangeError(
    145     const string &strValue, CParameterAccessContext &parameterAccessContext) 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 
    190 bool CFixedPointParameterType::fromBlackboard(string &strValue, const uint32_t &value,
    191                                               CParameterAccessContext &parameterAccessContext) 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
    231 bool CFixedPointParameterType::toBlackboard(double dUserValue, uint32_t &uiValue,
    232                                             CParameterAccessContext &parameterAccessContext) 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 
    254 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
    271 size_t CFixedPointParameterType::getUtilSizeInBits() const
    272 {
    273     return _uiIntegral + _uiFractional + 1;
    274 }
    275 
    276 // Compute the range for the type (minimum and maximum values)
    277 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 
    283 bool CFixedPointParameterType::convertFromHexadecimal(
    284     const string &strValue, uint32_t &uiValue,
    285     CParameterAccessContext &parameterAccessContext) 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 
    301 bool CFixedPointParameterType::convertFromDecimal(
    302     const string &strValue, uint32_t &uiValue,
    303     CParameterAccessContext &parameterAccessContext) 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 
    313 bool CFixedPointParameterType::convertFromQnm(const string &strValue, uint32_t &uiValue,
    314                                               CParameterAccessContext &parameterAccessContext) 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
    332 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
    342 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 
    354 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
    362 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