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 ¶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
setOutOfRangeError(const string & strValue,CParameterAccessContext & parameterAccessContext) const176 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
fromBlackboard(string & strValue,const uint32_t & uiValue,CParameterAccessContext & parameterAccessContext) const205 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
toBlackboard(double dUserValue,uint32_t & uiValue,CParameterAccessContext & parameterAccessContext) const234 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
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