/* * Copyright (c) 2014-2015, Intel Corporation * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation and/or * other materials provided with the distribution. * * 3. Neither the name of the copyright holder nor the names of its contributors * may be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, Value, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "FloatingPointParameterType.h" #include #include #include "ParameterAccessContext.h" #include "ConfigurationAccessContext.h" #include #include #include "convert.hpp" #include "Utility.h" #include "BinaryCopy.hpp" using std::string; CFloatingPointParameterType::CFloatingPointParameterType(const string &strName) : base(strName) { } string CFloatingPointParameterType::getKind() const { return "FloatingPointParameter"; } // Element properties void CFloatingPointParameterType::showProperties(string &strResult) const { base::showProperties(strResult); strResult += "Min:" + std::to_string(_fMin) + "\n" + "Max:" + std::to_string(_fMax) + "\n"; } void CFloatingPointParameterType::handleValueSpaceAttribute( CXmlElement &xmlConfigurableElementSettingsElement, CConfigurationAccessContext &configurationAccessContext) const { if (!configurationAccessContext.serializeOut()) { string strValueSpace; if (xmlConfigurableElementSettingsElement.getAttribute("ValueSpace", strValueSpace)) { configurationAccessContext.setValueSpaceRaw(strValueSpace == "Raw"); } else { configurationAccessContext.setValueSpaceRaw(false); } } else { // Set the value space only if it is raw (i.e. not the default one) if (configurationAccessContext.valueSpaceIsRaw()) { xmlConfigurableElementSettingsElement.setAttribute("ValueSpace", "Raw"); } } } bool CFloatingPointParameterType::fromXml(const CXmlElement &xmlElement, CXmlSerializingContext &serializingContext) { // Size. The XSD fixes it to 32 size_t sizeInBits = 32; xmlElement.getAttribute("Size", sizeInBits); // Size support check: only floats are supported // (e.g. doubles are not supported) if (sizeInBits != sizeof(float) * CHAR_BIT) { serializingContext.setError("Unsupported size (" + std::to_string(sizeInBits) + ") for " + getKind() + " " + xmlElement.getPath() + ". For now, only 32 is supported."); return false; } setSize(sizeInBits / CHAR_BIT); xmlElement.getAttribute("Min", _fMin); xmlElement.getAttribute("Max", _fMax); if (_fMin > _fMax) { serializingContext.setError("Min (" + std::to_string(_fMin) + ") can't be greater than Max (" + std::to_string(_fMax) + ")"); return false; } return base::fromXml(xmlElement, serializingContext); } bool CFloatingPointParameterType::toBlackboard( const string &strValue, uint32_t &uiValue, CParameterAccessContext ¶meterAccessContext) const { // Check Value integrity if (utility::isHexadecimal(strValue) && !parameterAccessContext.valueSpaceIsRaw()) { parameterAccessContext.setError("Hexadecimal values are not supported for " + getKind() + " when selected value space is real: " + strValue); return false; } if (parameterAccessContext.valueSpaceIsRaw()) { // Raw value: interpret the user input as the memory content of the // parameter if (!convertTo(strValue, uiValue)) { parameterAccessContext.setError("Value '" + strValue + "' is invalid"); return false; } auto fData = utility::binaryCopy(uiValue); // Check against NaN or infinity if (!std::isfinite(fData)) { parameterAccessContext.setError("Value " + strValue + " is not a finite number"); return false; } if (!checkValueAgainstRange(fData)) { setOutOfRangeError(strValue, parameterAccessContext); return false; } return true; } else { float fValue = 0.0f; // Interpret the user input as float if (!convertTo(strValue, fValue)) { parameterAccessContext.setError("Value " + strValue + " is invalid"); return false; } if (!checkValueAgainstRange(fValue)) { setOutOfRangeError(strValue, parameterAccessContext); return false; } // Move to the "raw memory" value space uiValue = utility::binaryCopy(fValue); return true; } } void CFloatingPointParameterType::setOutOfRangeError( const string &strValue, CParameterAccessContext ¶meterAccessContext) const { // error message buffer std::ostringstream ostrStream; ostrStream << "Value " << strValue << " standing out of admitted "; if (!parameterAccessContext.valueSpaceIsRaw()) { ostrStream << "real range [" << _fMin << ", " << _fMax << "]"; } else { auto uiMin = utility::binaryCopy(_fMin); auto uiMax = utility::binaryCopy(_fMax); if (utility::isHexadecimal(strValue)) { ostrStream << std::showbase << std::hex << std::setw(static_cast(getSize() * 2)) << std::setfill('0'); } ostrStream << "raw range [" << uiMin << ", " << uiMax << "]"; } ostrStream << " for " << getKind(); parameterAccessContext.setError(ostrStream.str()); } bool CFloatingPointParameterType::fromBlackboard( string &strValue, const uint32_t &uiValue, CParameterAccessContext ¶meterAccessContext) const { std::ostringstream ostrStream; if (parameterAccessContext.valueSpaceIsRaw()) { if (parameterAccessContext.outputRawFormatIsHex()) { ostrStream << std::showbase << std::hex << std::setw(static_cast(getSize() * 2)) << std::setfill('0'); } ostrStream << uiValue; } else { // Move from "raw memory" value space to real space auto fValue = utility::binaryCopy(uiValue); ostrStream << fValue; } strValue = ostrStream.str(); return true; } // Value access bool CFloatingPointParameterType::toBlackboard( double dUserValue, uint32_t &uiValue, CParameterAccessContext ¶meterAccessContext) const { if (!checkValueAgainstRange(dUserValue)) { parameterAccessContext.setError("Value out of range"); return false; } // Cast is fine because dValue has been checked against the value range float fValue = static_cast(dUserValue); uiValue = utility::binaryCopy(fValue); return true; } bool CFloatingPointParameterType::fromBlackboard(double &dUserValue, uint32_t uiValue, CParameterAccessContext & /*ctx*/) const { // Move from "raw memory" value space to real space auto fValue = utility::binaryCopy(uiValue); dUserValue = fValue; return true; } bool CFloatingPointParameterType::checkValueAgainstRange(double dValue) const { // Check that dValue can safely be cast to a float // (otherwise, behaviour is undefined) if ((dValue < -std::numeric_limits::max()) || (dValue > std::numeric_limits::max())) { return false; } return checkValueAgainstRange(static_cast(dValue)); } bool CFloatingPointParameterType::checkValueAgainstRange(float fValue) const { return fValue <= _fMax && fValue >= _fMin; } void CFloatingPointParameterType::toXml(CXmlElement &xmlElement, CXmlSerializingContext &serializingContext) const { xmlElement.setAttribute("Size", getSize() * CHAR_BIT); xmlElement.setAttribute("Min", _fMin); xmlElement.setAttribute("Max", _fMax); base::toXml(xmlElement, serializingContext); }