/*
|
* 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 <sstream>
|
#include <iomanip>
|
#include "ParameterAccessContext.h"
|
#include "ConfigurationAccessContext.h"
|
#include <limits>
|
#include <climits>
|
#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<float>(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<decltype(uiValue)>(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<uint32_t>(_fMin);
|
auto uiMax = utility::binaryCopy<uint32_t>(_fMax);
|
|
if (utility::isHexadecimal(strValue)) {
|
|
ostrStream << std::showbase << std::hex << std::setw(static_cast<int>(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<int>(getSize() * 2))
|
<< std::setfill('0');
|
}
|
|
ostrStream << uiValue;
|
} else {
|
|
// Move from "raw memory" value space to real space
|
auto fValue = utility::binaryCopy<float>(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<float>(dUserValue);
|
uiValue = utility::binaryCopy<decltype(uiValue)>(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<float>(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<float>::max()) ||
|
(dValue > std::numeric_limits<float>::max())) {
|
return false;
|
}
|
|
return checkValueAgainstRange(static_cast<float>(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);
|
}
|