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 } // namespace pfw
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 = {nullptr, &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 != nullptr);
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 != nullptr and logger->logCb == nullptr) {
171 return; // There is no callback, do not log => do not add a logger
172 }
173 mLogger = logger != nullptr ? *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 == nullptr) {
184 return status.failure("Criterion name is NULL");
185 }
186 if (criterion.values == nullptr) {
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 != nullptr);
198 // Add criterion values
199 for (size_t valueIndex = 0; criterion.values[valueIndex] != nullptr; ++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 != nullptr) {
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 auto it = criteria.find(name);
253 return it == criteria.end() ? nullptr : 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 == nullptr) {
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 == nullptr) {
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 == nullptr) {
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 == nullptr) {
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 == nullptr) {
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 ¶meter;
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 == nullptr) {
310 status.failure("The parameter framework is not started, "
311 "while trying to bind parameter \"" +
312 string(path) + "\")");
313 return nullptr;
314 }
315
316 CParameterHandle *paramHandle;
317 paramHandle = handle->pfw->createParameterHandle(path, status.msg());
318 if (paramHandle == nullptr) {
319 return nullptr;
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 = nullptr;
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