1 /* 2 * Copyright (c) 2014-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, Value, 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 "FloatingPointParameterType.h" 31 #include <sstream> 32 #include <iomanip> 33 #include "ParameterAccessContext.h" 34 #include "ConfigurationAccessContext.h" 35 #include <limits> 36 #include <climits> 37 #include "convert.hpp" 38 #include "Utility.h" 39 #include "BinaryCopy.hpp" 40 41 using std::string; 42 43 CFloatingPointParameterType::CFloatingPointParameterType(const string &strName) : base(strName) 44 { 45 } 46 47 string CFloatingPointParameterType::getKind() const 48 { 49 return "FloatingPointParameter"; 50 } 51 52 // Element properties 53 void CFloatingPointParameterType::showProperties(string &strResult) const 54 { 55 base::showProperties(strResult); 56 57 strResult += "Min:" + std::to_string(_fMin) + "\n" + "Max:" + std::to_string(_fMax) + "\n"; 58 } 59 60 void CFloatingPointParameterType::handleValueSpaceAttribute( 61 CXmlElement &xmlConfigurableElementSettingsElement, 62 CConfigurationAccessContext &configurationAccessContext) const 63 { 64 if (!configurationAccessContext.serializeOut()) { 65 66 string strValueSpace; 67 68 if (xmlConfigurableElementSettingsElement.getAttribute("ValueSpace", strValueSpace)) { 69 70 configurationAccessContext.setValueSpaceRaw(strValueSpace == "Raw"); 71 } else { 72 73 configurationAccessContext.setValueSpaceRaw(false); 74 } 75 } else { 76 // Set the value space only if it is raw (i.e. not the default one) 77 if (configurationAccessContext.valueSpaceIsRaw()) { 78 79 xmlConfigurableElementSettingsElement.setAttribute("ValueSpace", "Raw"); 80 } 81 } 82 } 83 84 bool CFloatingPointParameterType::fromXml(const CXmlElement &xmlElement, 85 CXmlSerializingContext &serializingContext) 86 { 87 // Size. The XSD fixes it to 32 88 size_t sizeInBits = 32; 89 xmlElement.getAttribute("Size", sizeInBits); 90 91 // Size support check: only floats are supported 92 // (e.g. doubles are not supported) 93 if (sizeInBits != sizeof(float) * CHAR_BIT) { 94 95 serializingContext.setError("Unsupported size (" + std::to_string(sizeInBits) + ") for " + 96 getKind() + " " + xmlElement.getPath() + 97 ". For now, only 32 is supported."); 98 99 return false; 100 } 101 102 setSize(sizeInBits / CHAR_BIT); 103 104 xmlElement.getAttribute("Min", _fMin); 105 xmlElement.getAttribute("Max", _fMax); 106 107 if (_fMin > _fMax) { 108 serializingContext.setError("Min (" + std::to_string(_fMin) + 109 ") can't be greater than Max (" + std::to_string(_fMax) + ")"); 110 return false; 111 } 112 113 return base::fromXml(xmlElement, serializingContext); 114 } 115 116 bool CFloatingPointParameterType::toBlackboard( 117 const string &strValue, uint32_t &uiValue, 118 CParameterAccessContext ¶meterAccessContext) const 119 { 120 // Check Value integrity 121 if (utility::isHexadecimal(strValue) && !parameterAccessContext.valueSpaceIsRaw()) { 122 123 parameterAccessContext.setError("Hexadecimal values are not supported for " + getKind() + 124 " when selected value space is real: " + strValue); 125 126 return false; 127 } 128 129 if (parameterAccessContext.valueSpaceIsRaw()) { 130 // Raw value: interpret the user input as the memory content of the 131 // parameter 132 if (!convertTo(strValue, uiValue)) { 133 134 parameterAccessContext.setError("Value '" + strValue + "' is invalid"); 135 return false; 136 } 137 138 auto fData = utility::binaryCopy<float>(uiValue); 139 140 // Check against NaN or infinity 141 if (!std::isfinite(fData)) { 142 143 parameterAccessContext.setError("Value " + strValue + " is not a finite number"); 144 return false; 145 } 146 147 if (!checkValueAgainstRange(fData)) { 148 149 setOutOfRangeError(strValue, parameterAccessContext); 150 return false; 151 } 152 return true; 153 } else { 154 155 float fValue = 0.0f; 156 157 // Interpret the user input as float 158 if (!convertTo(strValue, fValue)) { 159 160 parameterAccessContext.setError("Value " + strValue + " is invalid"); 161 return false; 162 } 163 164 if (!checkValueAgainstRange(fValue)) { 165 166 setOutOfRangeError(strValue, parameterAccessContext); 167 return false; 168 } 169 170 // Move to the "raw memory" value space 171 uiValue = utility::binaryCopy<decltype(uiValue)>(fValue); 172 return true; 173 } 174 } 175 176 void CFloatingPointParameterType::setOutOfRangeError( 177 const string &strValue, CParameterAccessContext ¶meterAccessContext) const 178 { 179 // error message buffer 180 std::ostringstream ostrStream; 181 182 ostrStream << "Value " << strValue << " standing out of admitted "; 183 184 if (!parameterAccessContext.valueSpaceIsRaw()) { 185 186 ostrStream << "real range [" << _fMin << ", " << _fMax << "]"; 187 } else { 188 189 auto uiMin = utility::binaryCopy<uint32_t>(_fMin); 190 auto uiMax = utility::binaryCopy<uint32_t>(_fMax); 191 192 if (utility::isHexadecimal(strValue)) { 193 194 ostrStream << std::showbase << std::hex << std::setw(static_cast<int>(getSize() * 2)) 195 << std::setfill('0'); 196 } 197 198 ostrStream << "raw range [" << uiMin << ", " << uiMax << "]"; 199 } 200 ostrStream << " for " << getKind(); 201 202 parameterAccessContext.setError(ostrStream.str()); 203 } 204 205 bool CFloatingPointParameterType::fromBlackboard( 206 string &strValue, const uint32_t &uiValue, 207 CParameterAccessContext ¶meterAccessContext) const 208 { 209 std::ostringstream ostrStream; 210 211 if (parameterAccessContext.valueSpaceIsRaw()) { 212 213 if (parameterAccessContext.outputRawFormatIsHex()) { 214 215 ostrStream << std::showbase << std::hex << std::setw(static_cast<int>(getSize() * 2)) 216 << std::setfill('0'); 217 } 218 219 ostrStream << uiValue; 220 } else { 221 222 // Move from "raw memory" value space to real space 223 auto fValue = utility::binaryCopy<float>(uiValue); 224 225 ostrStream << fValue; 226 } 227 228 strValue = ostrStream.str(); 229 230 return true; 231 } 232 233 // Value access 234 bool CFloatingPointParameterType::toBlackboard( 235 double dUserValue, uint32_t &uiValue, CParameterAccessContext ¶meterAccessContext) const 236 { 237 if (!checkValueAgainstRange(dUserValue)) { 238 239 parameterAccessContext.setError("Value out of range"); 240 return false; 241 } 242 243 // Cast is fine because dValue has been checked against the value range 244 float fValue = static_cast<float>(dUserValue); 245 uiValue = utility::binaryCopy<decltype(uiValue)>(fValue); 246 return true; 247 } 248 249 bool CFloatingPointParameterType::fromBlackboard(double &dUserValue, uint32_t uiValue, 250 CParameterAccessContext & /*ctx*/) const 251 { 252 // Move from "raw memory" value space to real space 253 auto fValue = utility::binaryCopy<float>(uiValue); 254 255 dUserValue = fValue; 256 return true; 257 } 258 259 bool CFloatingPointParameterType::checkValueAgainstRange(double dValue) const 260 { 261 // Check that dValue can safely be cast to a float 262 // (otherwise, behaviour is undefined) 263 if ((dValue < -std::numeric_limits<float>::max()) || 264 (dValue > std::numeric_limits<float>::max())) { 265 return false; 266 } 267 268 return checkValueAgainstRange(static_cast<float>(dValue)); 269 } 270 271 bool CFloatingPointParameterType::checkValueAgainstRange(float fValue) const 272 { 273 return fValue <= _fMax && fValue >= _fMin; 274 } 275 276 void CFloatingPointParameterType::toXml(CXmlElement &xmlElement, 277 CXmlSerializingContext &serializingContext) const 278 { 279 xmlElement.setAttribute("Size", getSize() * CHAR_BIT); 280 xmlElement.setAttribute("Min", _fMin); 281 xmlElement.setAttribute("Max", _fMax); 282 283 base::toXml(xmlElement, serializingContext); 284 } 285