1 /*
2  * Copyright (c) 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 
31 #include "ParameterFramework.h"
32 #include <ParameterMgrPlatformConnector.h>
33 
34 #include <NonCopyable.hpp>
35 
36 #include <iostream>
37 #include <limits>
38 #include <string>
39 #include <map>
40 
41 #include <cassert>
42 #include <cstring>
43 #include <cstdlib>
44 
45 using std::string;
46 
47 /** Rename long pfw types to short ones in pfw namespace. */
48 namespace pfw
49 {
50 typedef ISelectionCriterionInterface Criterion;
51 typedef std::map<string, Criterion *> Criteria;
52 typedef CParameterMgrPlatformConnector Pfw;
53 }
54 
55 /** Class to abstract the boolean+string status api. */
56 class Status
57 {
58 public:
59     /** Fail without an instance of status. */
failure()60     static bool failure() { return false; }
61     /** Fail with the given error msg. */
failure(const string & msg)62     bool failure(const string &msg)
63     {
64         mMsg = msg;
65         return false;
66     }
67     /** Success (no error message). */
success()68     bool success()
69     {
70         mMsg.clear();
71         return true;
72     }
73 
74     /** Forward a status operation.
75       * @param[in] success the operaton status to forward
76       *                    or forward a previous failure if omitted
77       */
forward(bool success=false)78     bool forward(bool success = false)
79     {
80         if (success) {
81             mMsg.clear();
82         }
83         return success;
84     }
85     /** Error message accessors.
86       *
87       * Pfw api requires to provide a reference to a string in order
88       * for it to log. This function provide a reference to a string that
89       * will be added to the error message on failure.
90       */
msg()91     string &msg() { return mMsg; }
92 private:
93     string mMsg;
94 };
95 
96 ///////////////////////////////
97 ///////////// Log /////////////
98 ///////////////////////////////
99 
100 /** Default log callback. Log to cout or cerr depending on level. */
defaultLogCb(void *,PfwLogLevel level,const char * logLine)101 static void defaultLogCb(void *, PfwLogLevel level, const char *logLine)
102 {
103     switch (level) {
104     case pfwLogInfo:
105         std::cout << logLine << std::endl;
106         break;
107     case pfwLogWarning:
108         std::cerr << logLine << std::endl;
109         break;
110     };
111 }
112 
113 static PfwLogger defaultLogger = {NULL, &defaultLogCb};
114 
115 class LogWrapper : public CParameterMgrPlatformConnector::ILogger
116 {
117 public:
LogWrapper(const PfwLogger & logger)118     LogWrapper(const PfwLogger &logger) : mLogger(logger) {}
LogWrapper()119     LogWrapper() : mLogger() {}
~LogWrapper()120     virtual ~LogWrapper() {}
121 private:
info(const string & msg)122     void info(const string &msg) override { log(pfwLogInfo, msg); }
123 
warning(const string & msg)124     void warning(const string &msg) override { log(pfwLogWarning, msg); }
125 
log(PfwLogLevel level,const string & strLog)126     void log(PfwLogLevel level, const string &strLog)
127     {
128         // A LogWrapper should NOT be register to the pfw (thus log called)
129         // if logCb is NULL.
130         assert(mLogger.logCb != NULL);
131         mLogger.logCb(mLogger.userCtx, level, strLog.c_str());
132     }
133 
134     PfwLogger mLogger;
135 };
136 
137 ///////////////////////////////
138 ///////////// Core ////////////
139 ///////////////////////////////
140 
141 struct PfwHandler_ : private utility::NonCopyable
142 {
143     void setLogger(const PfwLogger *logger);
144     bool createCriteria(const PfwCriterion criteria[], size_t criterionNb);
145 
146     pfw::Criteria criteria;
147     pfw::Pfw *pfw = nullptr;
148     /** Status of the last called function.
149       * Is mutable because even a const function can fail.
150       */
151     mutable Status lastStatus;
152 
153 private:
154     LogWrapper mLogger;
155 };
156 
pfwCreate()157 PfwHandler *pfwCreate()
158 {
159     return new PfwHandler();
160 }
161 
pfwDestroy(PfwHandler * handle)162 void pfwDestroy(PfwHandler *handle)
163 {
164     delete handle->pfw;
165     delete handle;
166 }
167 
setLogger(const PfwLogger * logger)168 void PfwHandler::setLogger(const PfwLogger *logger)
169 {
170     if (logger != NULL and logger->logCb == NULL) {
171         return; // There is no callback, do not log => do not add a logger
172     }
173     mLogger = logger != NULL ? *logger : defaultLogger;
174     pfw->setLogger(&mLogger);
175 }
176 
createCriteria(const PfwCriterion criteriaArray[],size_t criterionNb)177 bool PfwHandler::createCriteria(const PfwCriterion criteriaArray[], size_t criterionNb)
178 {
179     Status &status = lastStatus;
180     // Add criteria
181     for (size_t criterionIndex = 0; criterionIndex < criterionNb; ++criterionIndex) {
182         const PfwCriterion &criterion = criteriaArray[criterionIndex];
183         if (criterion.name == NULL) {
184             return status.failure("Criterion name is NULL");
185         }
186         if (criterion.values == NULL) {
187             return status.failure("Criterion values is NULL");
188         }
189         // Check that the criterion does not exist
190         if (criteria.find(criterion.name) != criteria.end()) {
191             return status.failure("Criterion \"" + string(criterion.name) + "\" already exist");
192         }
193 
194         // Create criterion type
195         ISelectionCriterionTypeInterface *type =
196             pfw->createSelectionCriterionType(criterion.inclusive);
197         assert(type != NULL);
198         // Add criterion values
199         for (size_t valueIndex = 0; criterion.values[valueIndex] != NULL; ++valueIndex) {
200             int value;
201             if (criterion.inclusive) {
202                 // Check that (int)1 << valueIndex would not overflow (UB)
203                 if (std::numeric_limits<int>::max() >> valueIndex == 0) {
204                     return status.failure("Too many values for criterion " +
205                                           string(criterion.name));
206                 }
207                 value = 1 << valueIndex;
208             } else {
209                 value = static_cast<int>(valueIndex);
210             }
211             const char *valueName = criterion.values[valueIndex];
212             string error;
213             if (not type->addValuePair(value, valueName, error)) {
214                 return status.failure("Could not add value " + string(valueName) +
215                                       " to criterion " + criterion.name + ": " + error);
216             }
217         }
218         // Create criterion and add it to the pfw
219         criteria[criterion.name] = pfw->createSelectionCriterion(criterion.name, type);
220     }
221     return status.success();
222 }
223 
pfwStart(PfwHandler * handle,const char * configPath,const PfwCriterion criteria[],size_t criterionNb,const PfwLogger * logger)224 bool pfwStart(PfwHandler *handle, const char *configPath, const PfwCriterion criteria[],
225               size_t criterionNb, const PfwLogger *logger)
226 {
227     // Check that the api is correctly used
228     Status &status = handle->lastStatus;
229 
230     if (handle->pfw != NULL) {
231         return status.failure("Can not start an already started parameter framework");
232     }
233     // Create a pfw
234     handle->pfw = new CParameterMgrPlatformConnector(configPath);
235 
236     handle->setLogger(logger);
237 
238     if (not handle->createCriteria(criteria, criterionNb)) {
239         return status.failure();
240     }
241 
242     return status.forward(handle->pfw->start(status.msg()));
243 }
244 
pfwGetLastError(const PfwHandler * handle)245 const char *pfwGetLastError(const PfwHandler *handle)
246 {
247     return handle->lastStatus.msg().c_str();
248 }
249 
getCriterion(const pfw::Criteria & criteria,const string & name)250 static pfw::Criterion *getCriterion(const pfw::Criteria &criteria, const string &name)
251 {
252     pfw::Criteria::const_iterator it = criteria.find(name);
253     return it == criteria.end() ? NULL : it->second;
254 }
255 
pfwSetCriterion(PfwHandler * handle,const char name[],int value)256 bool pfwSetCriterion(PfwHandler *handle, const char name[], int value)
257 {
258     Status &status = handle->lastStatus;
259     if (handle->pfw == NULL) {
260         return status.failure("Can not set criterion \"" + string(name) +
261                               "\" as the parameter framework is not started.");
262     }
263     pfw::Criterion *criterion = getCriterion(handle->criteria, name);
264     if (criterion == NULL) {
265         return status.failure("Can not set criterion " + string(name) + " as does not exist");
266     }
267     criterion->setCriterionState(value);
268     return status.success();
269 }
pfwGetCriterion(const PfwHandler * handle,const char name[],int * value)270 bool pfwGetCriterion(const PfwHandler *handle, const char name[], int *value)
271 {
272     Status &status = handle->lastStatus;
273     if (handle->pfw == NULL) {
274         return status.failure("Can not get criterion \"" + string(name) +
275                               "\" as the parameter framework is not started.");
276     }
277     pfw::Criterion *criterion = getCriterion(handle->criteria, name);
278     if (criterion == NULL) {
279         return status.failure("Can not get criterion " + string(name) + " as it does not exist");
280     }
281     *value = criterion->getCriterionState();
282     return status.success();
283 }
284 
pfwApplyConfigurations(const PfwHandler * handle)285 bool pfwApplyConfigurations(const PfwHandler *handle)
286 {
287     Status &status = handle->lastStatus;
288     if (handle->pfw == NULL) {
289         return status.failure("Can not commit criteria "
290                               "as the parameter framework is not started.");
291     }
292     handle->pfw->applyConfigurations();
293     return status.success();
294 }
295 
296 ///////////////////////////////
297 /////// Parameter access //////
298 ///////////////////////////////
299 
300 struct PfwParameterHandler_
301 {
302     PfwHandler &pfw;
303     CParameterHandle &parameter;
304 };
305 
pfwBindParameter(PfwHandler * handle,const char path[])306 PfwParameterHandler *pfwBindParameter(PfwHandler *handle, const char path[])
307 {
308     Status &status = handle->lastStatus;
309     if (handle->pfw == NULL) {
310         status.failure("The parameter framework is not started, "
311                        "while trying to bind parameter \"" +
312                        string(path) + "\")");
313         return NULL;
314     }
315 
316     CParameterHandle *paramHandle;
317     paramHandle = handle->pfw->createParameterHandle(path, status.msg());
318     if (paramHandle == NULL) {
319         return NULL;
320     }
321 
322     status.success();
323     PfwParameterHandler publicHandle = {*handle, *paramHandle};
324     return new PfwParameterHandler(publicHandle);
325 }
326 
pfwUnbindParameter(PfwParameterHandler * handle)327 void pfwUnbindParameter(PfwParameterHandler *handle)
328 {
329     delete &handle->parameter;
330     delete handle;
331 }
332 
pfwGetIntParameter(const PfwParameterHandler * handle,int32_t * value)333 bool pfwGetIntParameter(const PfwParameterHandler *handle, int32_t *value)
334 {
335     Status &status = handle->pfw.lastStatus;
336     return status.forward(handle->parameter.getAsSignedInteger(*value, status.msg()));
337 }
pfwSetIntParameter(PfwParameterHandler * handle,int32_t value)338 bool pfwSetIntParameter(PfwParameterHandler *handle, int32_t value)
339 {
340     Status &status = handle->pfw.lastStatus;
341     return status.forward(handle->parameter.setAsSignedInteger(value, status.msg()));
342 }
343 
pfwGetStringParameter(const PfwParameterHandler * handle,char * value[])344 bool pfwGetStringParameter(const PfwParameterHandler *handle, char *value[])
345 {
346     Status &status = handle->pfw.lastStatus;
347     *value = NULL;
348     string retValue;
349     bool success = handle->parameter.getAsString(retValue, status.msg());
350     if (not success) {
351         return status.forward();
352     }
353 
354     *value = strdup(retValue.c_str());
355     return status.success();
356 }
357 
pfwSetStringParameter(PfwParameterHandler * handle,const char value[])358 bool pfwSetStringParameter(PfwParameterHandler *handle, const char value[])
359 {
360     Status &status = handle->pfw.lastStatus;
361     return status.forward(handle->parameter.setAsString(value, status.msg()));
362 }
363 
pfwFree(void * ptr)364 void pfwFree(void *ptr)
365 {
366     std::free(ptr);
367 }
368