1 /*
2  * Copyright (c) 2011-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, DATA, 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 "ArrayParameter.h"
31 #include <sstream> // for istringstream
32 #include "Tokenizer.h"
33 #include "ParameterType.h"
34 #include "ParameterAccessContext.h"
35 #include "ConfigurationAccessContext.h"
36 #include "ParameterBlackboard.h"
37 #include "Utility.h"
38 #include <assert.h>
39 
40 #define base CParameter
41 
42 using std::string;
43 
CArrayParameter(const string & strName,const CTypeElement * pTypeElement)44 CArrayParameter::CArrayParameter(const string &strName, const CTypeElement *pTypeElement)
45     : base(strName, pTypeElement)
46 {
47 }
48 
getFootPrint() const49 size_t CArrayParameter::getFootPrint() const
50 {
51     return getSize() * getArrayLength();
52 }
53 
54 // Array length
getArrayLength() const55 size_t CArrayParameter::getArrayLength() const
56 {
57     return getTypeElement()->getArrayLength();
58 }
59 
60 // Element properties
showProperties(string & strResult) const61 void CArrayParameter::showProperties(string &strResult) const
62 {
63     base::showProperties(strResult);
64 
65     // Array length
66     strResult += "Array length: ";
67     strResult += std::to_string(getArrayLength());
68     strResult += "\n";
69 }
70 
71 // User set/get
accessValue(CPathNavigator & pathNavigator,string & strValue,bool bSet,CParameterAccessContext & parameterAccessContext) const72 bool CArrayParameter::accessValue(CPathNavigator &pathNavigator, string &strValue, bool bSet,
73                                   CParameterAccessContext &parameterAccessContext) const
74 {
75     size_t index;
76 
77     if (!getIndex(pathNavigator, index, parameterAccessContext)) {
78 
79         return false;
80     }
81 
82     if (bSet) {
83         // Set
84         if (index == (size_t)-1) {
85 
86             // No index provided, start with 0
87             index = 0;
88         }
89 
90         // Actually set values
91         if (!setValues(index, getOffset() - parameterAccessContext.getBaseOffset(), strValue,
92                        parameterAccessContext)) {
93             return false;
94         }
95 
96         // Synchronize
97         if (!sync(parameterAccessContext)) {
98 
99             appendParameterPathToError(parameterAccessContext);
100             return false;
101         }
102     } else {
103         // Get
104         if (index == (size_t)-1) {
105 
106             // Whole array requested
107             strValue = getValues(getOffset() - parameterAccessContext.getBaseOffset(),
108                                  parameterAccessContext);
109 
110         } else {
111             // Scalar requested
112             CParameter::doGetValue(strValue, getOffset() + index * getSize(),
113                                    parameterAccessContext);
114         }
115     }
116 
117     return true;
118 }
119 
120 /// Actual parameter access
121 // String access
doSetValue(const string & value,size_t offset,CParameterAccessContext & parameterAccessContext) const122 bool CArrayParameter::doSetValue(const string &value, size_t offset,
123                                  CParameterAccessContext &parameterAccessContext) const
124 {
125     return setValues(0, offset, value, parameterAccessContext);
126 }
127 
doGetValue(string & value,size_t offset,CParameterAccessContext & parameterAccessContext) const128 void CArrayParameter::doGetValue(string &value, size_t offset,
129                                  CParameterAccessContext &parameterAccessContext) const
130 {
131     // Whole array requested
132     value = getValues(offset, parameterAccessContext);
133 }
134 
135 // Boolean
access(std::vector<bool> & abValues,bool bSet,CParameterAccessContext & parameterAccessContext) const136 bool CArrayParameter::access(std::vector<bool> &abValues, bool bSet,
137                              CParameterAccessContext &parameterAccessContext) const
138 {
139     return accessValues(abValues, bSet, parameterAccessContext);
140 }
141 
142 // Integer
access(std::vector<uint32_t> & auiValues,bool bSet,CParameterAccessContext & parameterAccessContext) const143 bool CArrayParameter::access(std::vector<uint32_t> &auiValues, bool bSet,
144                              CParameterAccessContext &parameterAccessContext) const
145 {
146     return accessValues(auiValues, bSet, parameterAccessContext);
147 }
148 
149 // Signed Integer Access
access(std::vector<int32_t> & aiValues,bool bSet,CParameterAccessContext & parameterAccessContext) const150 bool CArrayParameter::access(std::vector<int32_t> &aiValues, bool bSet,
151                              CParameterAccessContext &parameterAccessContext) const
152 {
153     return accessValues(aiValues, bSet, parameterAccessContext);
154 }
155 
156 // Double Access
access(std::vector<double> & adValues,bool bSet,CParameterAccessContext & parameterAccessContext) const157 bool CArrayParameter::access(std::vector<double> &adValues, bool bSet,
158                              CParameterAccessContext &parameterAccessContext) const
159 {
160     return accessValues(adValues, bSet, parameterAccessContext);
161 }
162 
163 // String Access
access(std::vector<string> & astrValues,bool bSet,CParameterAccessContext & parameterAccessContext) const164 bool CArrayParameter::access(std::vector<string> &astrValues, bool bSet,
165                              CParameterAccessContext &parameterAccessContext) const
166 {
167     return accessValues(astrValues, bSet, parameterAccessContext);
168 }
169 
170 // Dump
logValue(CParameterAccessContext & context) const171 string CArrayParameter::logValue(CParameterAccessContext &context) const
172 {
173     // Dump values
174     return getValues(0, context);
175 }
176 
177 // Used for simulation and virtual subsystems
setDefaultValues(CParameterAccessContext & parameterAccessContext) const178 void CArrayParameter::setDefaultValues(CParameterAccessContext &parameterAccessContext) const
179 {
180     // Get default value from type
181     uint32_t uiDefaultValue =
182         static_cast<const CParameterType *>(getTypeElement())->getDefaultValue();
183 
184     // Write blackboard
185     CParameterBlackboard *pBlackboard = parameterAccessContext.getParameterBlackboard();
186 
187     // Process
188     size_t valueIndex;
189     size_t size = getSize();
190     size_t offset = getOffset();
191     size_t arrayLength = getArrayLength();
192 
193     for (valueIndex = 0; valueIndex < arrayLength; valueIndex++) {
194 
195         // Beware this code works on little endian architectures only!
196         pBlackboard->writeInteger(&uiDefaultValue, size, offset);
197 
198         offset += size;
199     }
200 }
201 
202 // Index from path
getIndex(CPathNavigator & pathNavigator,size_t & index,CParameterAccessContext & parameterAccessContext) const203 bool CArrayParameter::getIndex(CPathNavigator &pathNavigator, size_t &index,
204                                CParameterAccessContext &parameterAccessContext) const
205 {
206     index = (size_t)-1;
207 
208     string *pStrChildName = pathNavigator.next();
209 
210     if (pStrChildName) {
211 
212         // Check index is numeric
213         std::istringstream iss(*pStrChildName);
214 
215         iss >> index;
216 
217         if (!iss) {
218 
219             parameterAccessContext.setError("Expected numerical expression as last item in " +
220                                             pathNavigator.getCurrentPath());
221 
222             return false;
223         }
224 
225         if (index >= getArrayLength()) {
226             std::ostringstream oss;
227 
228             oss << "Provided index out of range (max is " << getArrayLength() - 1 << ")";
229 
230             parameterAccessContext.setError(oss.str());
231 
232             return false;
233         }
234 
235         // Check no other item provided in path
236         pStrChildName = pathNavigator.next();
237 
238         if (pStrChildName) {
239 
240             // Should be leaf element
241             parameterAccessContext.setError("Path not found: " + pathNavigator.getCurrentPath());
242 
243             return false;
244         }
245     }
246 
247     return true;
248 }
249 
250 // Common set value processing
setValues(size_t uiStartIndex,size_t offset,const string & strValue,CParameterAccessContext & parameterAccessContext) const251 bool CArrayParameter::setValues(size_t uiStartIndex, size_t offset, const string &strValue,
252                                 CParameterAccessContext &parameterAccessContext) const
253 {
254     // Deal with value(s)
255     Tokenizer tok(strValue, Tokenizer::defaultDelimiters + ",");
256 
257     std::vector<string> astrValues = tok.split();
258     size_t nbValues = astrValues.size();
259 
260     // Check number of provided values
261     if (nbValues + uiStartIndex > getArrayLength()) {
262 
263         // Out of bounds
264         parameterAccessContext.setError("Too many values provided");
265 
266         return false;
267     }
268 
269     // Process
270     size_t valueIndex;
271     size_t size = getSize();
272     offset += uiStartIndex * size;
273 
274     for (valueIndex = 0; valueIndex < nbValues; valueIndex++) {
275 
276         if (!doSet(astrValues[valueIndex], offset, parameterAccessContext)) {
277 
278             // Append parameter path to error
279             parameterAccessContext.appendToError(" " + getPath() + "/" +
280                                                  std::to_string(valueIndex + uiStartIndex));
281 
282             return false;
283         }
284 
285         offset += size;
286     }
287     return true;
288 }
289 
290 // Common get value processing
getValues(size_t offset,CParameterAccessContext & parameterAccessContext) const291 string CArrayParameter::getValues(size_t offset,
292                                   CParameterAccessContext &parameterAccessContext) const
293 {
294     size_t size = getSize();
295     size_t arrayLength = getArrayLength();
296 
297     string output;
298 
299     bool bFirst = true;
300 
301     for (size_t valueIndex = 0; valueIndex < arrayLength; valueIndex++) {
302         string strReadValue;
303 
304         doGet(strReadValue, offset, parameterAccessContext);
305 
306         if (!bFirst) {
307 
308             output += " ";
309         } else {
310 
311             bFirst = false;
312         }
313 
314         output += strReadValue;
315 
316         offset += size;
317     }
318 
319     return output;
320 }
321 
322 // Generic Access
323 template <typename type>
accessValues(std::vector<type> & values,bool bSet,CParameterAccessContext & parameterAccessContext) const324 bool CArrayParameter::accessValues(std::vector<type> &values, bool bSet,
325                                    CParameterAccessContext &parameterAccessContext) const
326 {
327     if (bSet) {
328 
329         // Set Value
330         if (!setValues(values, parameterAccessContext)) {
331 
332             appendParameterPathToError(parameterAccessContext);
333             return false;
334         }
335         if (!sync(parameterAccessContext)) {
336 
337             appendParameterPathToError(parameterAccessContext);
338             return false;
339         }
340     } else {
341         // Get Value
342         if (!getValues(values, parameterAccessContext)) {
343 
344             appendParameterPathToError(parameterAccessContext);
345             return false;
346         }
347     }
348     return true;
349 }
350 
351 template <typename type>
setValues(const std::vector<type> & values,CParameterAccessContext & parameterAccessContext) const352 bool CArrayParameter::setValues(const std::vector<type> &values,
353                                 CParameterAccessContext &parameterAccessContext) const
354 {
355     size_t nbValues = getArrayLength();
356     size_t size = getSize();
357     size_t offset = getOffset();
358 
359     assert(values.size() == nbValues);
360 
361     // Process
362     for (size_t valueIndex = 0; valueIndex < nbValues; valueIndex++) {
363 
364         if (!doSet(values[valueIndex], offset, parameterAccessContext)) {
365 
366             return false;
367         }
368 
369         offset += size;
370     }
371 
372     return true;
373 }
374 
375 template <typename type>
getValues(std::vector<type> & values,CParameterAccessContext & parameterAccessContext) const376 bool CArrayParameter::getValues(std::vector<type> &values,
377                                 CParameterAccessContext &parameterAccessContext) const
378 {
379     size_t nbValues = getArrayLength();
380     size_t size = getSize();
381     size_t offset = getOffset();
382 
383     values.clear();
384 
385     for (size_t valueIndex = 0; valueIndex < nbValues; valueIndex++) {
386         type readValue;
387 
388         if (!doGet(readValue, offset, parameterAccessContext)) {
389 
390             return false;
391         }
392 
393         values.push_back(readValue);
394 
395         offset += size;
396     }
397     return true;
398 }
399 
400 template <typename type>
doSet(type value,size_t offset,CParameterAccessContext & parameterAccessContext) const401 bool CArrayParameter::doSet(type value, size_t offset,
402                             CParameterAccessContext &parameterAccessContext) const
403 {
404     uint32_t uiData;
405 
406     if (!static_cast<const CParameterType *>(getTypeElement())
407              ->toBlackboard(value, uiData, parameterAccessContext)) {
408 
409         return false;
410     }
411     // Write blackboard
412     CParameterBlackboard *pBlackboard = parameterAccessContext.getParameterBlackboard();
413 
414     // Beware this code works on little endian architectures only!
415     pBlackboard->writeInteger(&uiData, getSize(), offset);
416 
417     return true;
418 }
419 
420 template <typename type>
doGet(type & value,size_t offset,CParameterAccessContext & parameterAccessContext) const421 bool CArrayParameter::doGet(type &value, size_t offset,
422                             CParameterAccessContext &parameterAccessContext) const
423 {
424     uint32_t uiData = 0;
425 
426     // Read blackboard
427     const CParameterBlackboard *pBlackboard = parameterAccessContext.getParameterBlackboard();
428 
429     // Beware this code works on little endian architectures only!
430     pBlackboard->readInteger(&uiData, getSize(), offset);
431 
432     return static_cast<const CParameterType *>(getTypeElement())
433         ->fromBlackboard(value, uiData, parameterAccessContext);
434 }
435