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 
CFloatingPointParameterType(const string & strName)43 CFloatingPointParameterType::CFloatingPointParameterType(const string &strName) : base(strName)
44 {
45 }
46 
getKind() const47 string CFloatingPointParameterType::getKind() const
48 {
49     return "FloatingPointParameter";
50 }
51 
52 // Element properties
showProperties(string & strResult) const53 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 
handleValueSpaceAttribute(CXmlElement & xmlConfigurableElementSettingsElement,CConfigurationAccessContext & configurationAccessContext) const60 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 
fromXml(const CXmlElement & xmlElement,CXmlSerializingContext & serializingContext)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 
toBlackboard(const string & strValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext) const116 bool CFloatingPointParameterType::toBlackboard(
117     const string &strValue, uint32_t &uiValue,
118     CParameterAccessContext &parameterAccessContext) 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 
setOutOfRangeError(const string & strValue,CParameterAccessContext & parameterAccessContext) const176 void CFloatingPointParameterType::setOutOfRangeError(
177     const string &strValue, CParameterAccessContext &parameterAccessContext) 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 
fromBlackboard(string & strValue,const uint32_t & uiValue,CParameterAccessContext & parameterAccessContext) const205 bool CFloatingPointParameterType::fromBlackboard(
206     string &strValue, const uint32_t &uiValue,
207     CParameterAccessContext &parameterAccessContext) 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
toBlackboard(double dUserValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext) const234 bool CFloatingPointParameterType::toBlackboard(
235     double dUserValue, uint32_t &uiValue, CParameterAccessContext &parameterAccessContext) 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 
fromBlackboard(double & dUserValue,uint32_t uiValue,CParameterAccessContext &) const249 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 
checkValueAgainstRange(double dValue) const259 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 
checkValueAgainstRange(float fValue) const271 bool CFloatingPointParameterType::checkValueAgainstRange(float fValue) const
272 {
273     return fValue <= _fMax && fValue >= _fMin;
274 }
275 
toXml(CXmlElement & xmlElement,CXmlSerializingContext & serializingContext) const276 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