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 "IntegerParameterType.h"
     31 #include <stdlib.h>
     32 #include <sstream>
     33 #include <iomanip>
     34 #include "ParameterAccessContext.h"
     35 #include <assert.h>
     36 #include "ParameterAdaptation.h"
     37 #include "Utility.h"
     38 #include <errno.h>
     39 
     40 #define base CParameterType
     41 
     42 using std::string;
     43 using std::ostringstream;
     44 
     45 CIntegerParameterType::CIntegerParameterType(const string &strName) : base(strName)
     46 {
     47 }
     48 
     49 // Kind
     50 string CIntegerParameterType::getKind() const
     51 {
     52     return "IntegerParameter";
     53 }
     54 
     55 // Deal with adaption node
     56 bool CIntegerParameterType::childrenAreDynamic() const
     57 {
     58     return true;
     59 }
     60 
     61 // Element properties
     62 void CIntegerParameterType::showProperties(string &strResult) const
     63 {
     64     base::showProperties(strResult);
     65 
     66     // Sign
     67     strResult += "Signed: ";
     68     strResult += _bSigned ? "yes" : "no";
     69     strResult += "\n";
     70 
     71     // Min
     72     strResult += "Min: ";
     73     strResult += _bSigned ? std::to_string((int32_t)_uiMin) : std::to_string(_uiMin);
     74     strResult += "\n";
     75 
     76     // Max
     77     strResult += "Max: ";
     78     strResult += _bSigned ? std::to_string((int32_t)_uiMax) : std::to_string(_uiMax);
     79     strResult += "\n";
     80 
     81     // Check if there's an adaptation object available
     82     const CParameterAdaptation *pParameterAdaption = getParameterAdaptation();
     83 
     84     if (pParameterAdaption) {
     85 
     86         // Display adaptation properties
     87         strResult += "Adaptation:\n";
     88 
     89         pParameterAdaption->showProperties(strResult);
     90     }
     91 }
     92 
     93 bool CIntegerParameterType::fromXml(const CXmlElement &xmlElement,
     94                                     CXmlSerializingContext &serializingContext)
     95 {
     96     // Sign
     97     xmlElement.getAttribute("Signed", _bSigned);
     98 
     99     // Size in bits
    100     size_t sizeInBits = 0;
    101     xmlElement.getAttribute("Size", sizeInBits);
    102 
    103     // Size
    104     setSize(sizeInBits / 8);
    105 
    106     // Min / Max
    107     // TODO: Make IntegerParameter template
    108     if (_bSigned) {
    109 
    110         // Signed means we have one less util bit
    111         sizeInBits--;
    112 
    113         if (!xmlElement.getAttribute("Min", (int32_t &)_uiMin)) {
    114 
    115             _uiMin = 1U << sizeInBits;
    116         }
    117 
    118         if (!xmlElement.getAttribute("Max", (int32_t &)_uiMax)) {
    119 
    120             _uiMax = (1U << sizeInBits) - 1;
    121         }
    122         signExtend((int32_t &)_uiMin);
    123         signExtend((int32_t &)_uiMax);
    124     } else {
    125         if (!xmlElement.getAttribute("Min", _uiMin)) {
    126 
    127             _uiMin = 0;
    128         }
    129 
    130         if (!xmlElement.getAttribute("Max", _uiMax)) {
    131 
    132             _uiMax = ~0U >> (8 * sizeof(size_t) - sizeInBits);
    133         }
    134     }
    135 
    136     // Base
    137     return base::fromXml(xmlElement, serializingContext);
    138 }
    139 
    140 // Conversion (tuning)
    141 bool CIntegerParameterType::toBlackboard(const string &strValue, uint32_t &uiValue,
    142                                          CParameterAccessContext &parameterAccessContext) const
    143 {
    144     // Hexa
    145     bool bValueProvidedAsHexa = utility::isHexadecimal(strValue);
    146 
    147     // Get integer value from the string provided
    148     int64_t iData;
    149 
    150     if (!convertValueFromString(strValue, iData, parameterAccessContext)) {
    151 
    152         return false;
    153     }
    154 
    155     // Check against Min / Max
    156     if (_bSigned) {
    157 
    158         if (bValueProvidedAsHexa && isEncodable((uint64_t)iData, !bValueProvidedAsHexa)) {
    159 
    160             // Sign extend
    161             signExtend(iData);
    162         }
    163 
    164         if (!checkValueAgainstRange<int64_t>(strValue, iData, (int32_t)_uiMin, (int32_t)_uiMax,
    165                                              parameterAccessContext, bValueProvidedAsHexa)) {
    166 
    167             return false;
    168         }
    169     } else {
    170 
    171         if (!checkValueAgainstRange<uint64_t>(strValue, iData, _uiMin, _uiMax,
    172                                               parameterAccessContext, bValueProvidedAsHexa)) {
    173 
    174             return false;
    175         }
    176     }
    177 
    178     uiValue = (uint32_t)iData;
    179 
    180     return true;
    181 }
    182 
    183 bool CIntegerParameterType::fromBlackboard(string &strValue, const uint32_t &value,
    184                                            CParameterAccessContext &parameterAccessContext) const
    185 {
    186     // Check unsigned value is encodable
    187     assert(isEncodable(value, false));
    188 
    189     // Format
    190     ostringstream stream;
    191 
    192     // Take care of format
    193     if (parameterAccessContext.valueSpaceIsRaw() && parameterAccessContext.outputRawFormatIsHex()) {
    194 
    195         // Hexa display with unecessary bits cleared out
    196         stream << "0x" << std::hex << std::uppercase << std::setw(static_cast<int>(getSize() * 2))
    197                << std::setfill('0') << value;
    198     } else {
    199 
    200         if (_bSigned) {
    201 
    202             int32_t iValue = value;
    203 
    204             // Sign extend
    205             signExtend(iValue);
    206 
    207             stream << iValue;
    208         } else {
    209 
    210             stream << value;
    211         }
    212     }
    213 
    214     strValue = stream.str();
    215 
    216     return true;
    217 }
    218 
    219 // Value access
    220 // Integer
    221 bool CIntegerParameterType::toBlackboard(uint32_t uiUserValue, uint32_t &uiValue,
    222                                          CParameterAccessContext &parameterAccessContext) const
    223 {
    224     if (uiUserValue < _uiMin || uiUserValue > _uiMax) {
    225 
    226         parameterAccessContext.setError("Value out of range");
    227 
    228         return false;
    229     }
    230     // Do assign
    231     uiValue = uiUserValue;
    232 
    233     return true;
    234 }
    235 
    236 bool CIntegerParameterType::fromBlackboard(uint32_t &uiUserValue, uint32_t uiValue,
    237                                            CParameterAccessContext & /*ctx*/) const
    238 {
    239     // Do assign
    240     uiUserValue = uiValue;
    241 
    242     return true;
    243 }
    244 
    245 // Signed Integer
    246 bool CIntegerParameterType::toBlackboard(int32_t iUserValue, uint32_t &uiValue,
    247                                          CParameterAccessContext &parameterAccessContext) const
    248 {
    249     if (iUserValue < (int32_t)_uiMin || iUserValue > (int32_t)_uiMax) {
    250 
    251         parameterAccessContext.setError("Value out of range");
    252 
    253         return false;
    254     }
    255     // Do assign
    256     uiValue = iUserValue;
    257 
    258     return true;
    259 }
    260 
    261 bool CIntegerParameterType::fromBlackboard(int32_t &iUserValue, uint32_t uiValue,
    262                                            CParameterAccessContext & /*ctx*/) const
    263 {
    264     int32_t iValue = uiValue;
    265 
    266     // Sign extend
    267     signExtend(iValue);
    268 
    269     // Do assign
    270     iUserValue = iValue;
    271 
    272     return true;
    273 }
    274 
    275 // Double
    276 bool CIntegerParameterType::toBlackboard(double dUserValue, uint32_t &uiValue,
    277                                          CParameterAccessContext &parameterAccessContext) const
    278 {
    279     // Check if there's an adaptation object available
    280     const CParameterAdaptation *pParameterAdaption = getParameterAdaptation();
    281 
    282     if (!pParameterAdaption) {
    283 
    284         // Reject request and let upper class handle the error
    285         return base::toBlackboard(dUserValue, uiValue, parameterAccessContext);
    286     }
    287 
    288     // Do the conversion
    289     int64_t iConvertedValue = pParameterAdaption->fromUserValue(dUserValue);
    290 
    291     // Check against range
    292     if (_bSigned) {
    293 
    294         if (iConvertedValue < (int32_t)_uiMin || iConvertedValue > (int32_t)_uiMax) {
    295 
    296             parameterAccessContext.setError("Value out of range");
    297 
    298             return false;
    299         }
    300     } else {
    301 
    302         if (iConvertedValue < _uiMin || iConvertedValue > _uiMax) {
    303 
    304             parameterAccessContext.setError("Value out of range");
    305 
    306             return false;
    307         }
    308     }
    309 
    310     // Do assign
    311     uiValue = (uint32_t)iConvertedValue;
    312 
    313     return true;
    314 }
    315 
    316 bool CIntegerParameterType::fromBlackboard(double &dUserValue, uint32_t uiValue,
    317                                            CParameterAccessContext &parameterAccessContext) const
    318 {
    319     // Check if there's an adaptation object available
    320     const CParameterAdaptation *pParameterAdaption = getParameterAdaptation();
    321 
    322     if (!pParameterAdaption) {
    323 
    324         // Reject request and let upper class handle the error
    325         return base::fromBlackboard(dUserValue, uiValue, parameterAccessContext);
    326     }
    327 
    328     int64_t iValueToConvert;
    329 
    330     // Deal with signed data
    331     if (_bSigned) {
    332 
    333         int32_t iValue = uiValue;
    334 
    335         signExtend(iValue);
    336 
    337         iValueToConvert = iValue;
    338     } else {
    339 
    340         iValueToConvert = uiValue;
    341     }
    342 
    343     // Do the conversion
    344     dUserValue = pParameterAdaption->toUserValue(iValueToConvert);
    345 
    346     return true;
    347 }
    348 
    349 // Default value handling (simulation only)
    350 uint32_t CIntegerParameterType::getDefaultValue() const
    351 {
    352     return _uiMin;
    353 }
    354 
    355 int CIntegerParameterType::toPlainInteger(int iSizeOptimizedData) const
    356 {
    357     if (_bSigned) {
    358 
    359         signExtend(iSizeOptimizedData);
    360     }
    361 
    362     return base::toPlainInteger(iSizeOptimizedData);
    363 }
    364 
    365 // Convert value provided by the user as a string into an int64
    366 bool CIntegerParameterType::convertValueFromString(
    367     const string &strValue, int64_t &iData, CParameterAccessContext &parameterAccessContext) const
    368 {
    369 
    370     // Reset errno to check if it is updated during the conversion (strtol/strtoul)
    371     errno = 0;
    372     char *pcStrEnd;
    373 
    374     // Convert the input string
    375     if (_bSigned) {
    376 
    377         iData = strtoll(strValue.c_str(), &pcStrEnd, 0);
    378     } else {
    379 
    380         iData = strtoull(strValue.c_str(), &pcStrEnd, 0);
    381     }
    382 
    383     // Conversion error when the input string does not contain only digits or the number is out of
    384     // range (int32_t type)
    385     if (errno || (*pcStrEnd != '\0')) {
    386 
    387         string strError;
    388         strError = "Impossible to convert value " + strValue + " for " + getKind();
    389 
    390         parameterAccessContext.setError(strError);
    391 
    392         return false;
    393     }
    394 
    395     return true;
    396 }
    397 
    398 // Range checking
    399 template <typename type>
    400 bool CIntegerParameterType::checkValueAgainstRange(const string &strValue, type value,
    401                                                    type minValue, type maxValue,
    402                                                    CParameterAccessContext &parameterAccessContext,
    403                                                    bool bHexaValue) const
    404 {
    405     if (value < minValue || value > maxValue) {
    406 
    407         ostringstream stream;
    408 
    409         stream << "Value " << strValue << " standing out of admitted range [";
    410 
    411         if (bHexaValue) {
    412 
    413             stream << "0x" << std::hex << std::uppercase
    414                    << std::setw(static_cast<int>(getSize() * 2)) << std::setfill('0');
    415             // Format Min
    416             stream << minValue;
    417             // Format Max
    418             stream << maxValue;
    419 
    420         } else {
    421 
    422             stream << minValue << ", " << maxValue;
    423         }
    424 
    425         stream << "] for " << getKind();
    426 
    427         parameterAccessContext.setError(stream.str());
    428 
    429         return false;
    430     }
    431     return true;
    432 }
    433 
    434 // Adaptation element retrieval
    435 const CParameterAdaptation *CIntegerParameterType::getParameterAdaptation() const
    436 {
    437     return static_cast<const CParameterAdaptation *>(findChildOfKind("Adaptation"));
    438 }
    439 
    440 // From IXmlSource
    441 void CIntegerParameterType::toXml(CXmlElement &xmlElement,
    442                                   CXmlSerializingContext &serializingContext) const
    443 {
    444     // Sign
    445     xmlElement.setAttribute("Signed", _bSigned);
    446 
    447     if (_bSigned) {
    448 
    449         // Mininmum
    450         xmlElement.setAttribute("Min", (int32_t)_uiMin);
    451 
    452         // Maximum
    453         xmlElement.setAttribute("Max", (int32_t)_uiMax);
    454 
    455     } else {
    456 
    457         // Minimum
    458         xmlElement.setAttribute("Min", _uiMin);
    459 
    460         // Maximum
    461         xmlElement.setAttribute("Max", _uiMax);
    462     }
    463 
    464     // Size
    465     xmlElement.setAttribute("Size", getSize() * 8);
    466 
    467     base::toXml(xmlElement, serializingContext);
    468 }
    469