summaryrefslogtreecommitdiffstats
path: root/bindings
diff options
context:
space:
mode:
authorKevin Rocard <kevin.rocard@intel.com>2015-02-19 18:18:17 +0100
committerEric Laurent <elaurent@google.com>2015-04-24 13:39:11 -0700
commit46a021d5de6e7448c79f621e0525e920a6206425 (patch)
tree88aab631bf79022ea88cf9a45d8fd1f416d70535 /bindings
parent9ab48db4862975f81cb19cf3f9db06b26194fc34 (diff)
downloadexternal_parameter-framework-46a021d5de6e7448c79f621e0525e920a6206425.zip
external_parameter-framework-46a021d5de6e7448c79f621e0525e920a6206425.tar.gz
external_parameter-framework-46a021d5de6e7448c79f621e0525e920a6206425.tar.bz2
C pfw bindings
The pfw can not currently be used from c code. Add an c api. It does not target a perfect one/one mapping with the c++ one, but rather aim ease of use and type safety (as far as possible in c). Signed-off-by: Kevin Rocard <kevin.rocard@intel.com>
Diffstat (limited to 'bindings')
-rw-r--r--bindings/CMakeLists.txt5
-rw-r--r--bindings/c/CMakeLists.txt60
-rw-r--r--bindings/c/ParameterFramework.cpp397
-rw-r--r--bindings/c/ParameterFramework.h265
-rw-r--r--bindings/c/Test.cpp414
5 files changed, 1141 insertions, 0 deletions
diff --git a/bindings/CMakeLists.txt b/bindings/CMakeLists.txt
index ba59221..446b52f 100644
--- a/bindings/CMakeLists.txt
+++ b/bindings/CMakeLists.txt
@@ -30,3 +30,8 @@ option(PYTHON_BINDINGS "Python library to use the pfw from python" ON)
if(PYTHON_BINDINGS)
add_subdirectory(python)
endif()
+
+option(C_BINDINGS "Python library to use the pfw from python" ON)
+if(C_BINDINGS)
+ add_subdirectory(c)
+endif()
diff --git a/bindings/c/CMakeLists.txt b/bindings/c/CMakeLists.txt
new file mode 100644
index 0000000..b7eeff8
--- /dev/null
+++ b/bindings/c/CMakeLists.txt
@@ -0,0 +1,60 @@
+# Copyright (c) 2015, Intel Corporation
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this
+# list of conditions and the following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation and/or
+# other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its contributors
+# may be used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+add_library(cparameter SHARED ParameterFramework.cpp)
+
+include_directories("${PROJECT_SOURCE_DIR}/parameter/include")
+
+install(FILES ParameterFramework.h
+ DESTINATION "include/parameter/c")
+
+target_link_libraries(cparameter parameter)
+
+if(BUILD_TESTING)
+ # Add catch unit test framework
+ # TODO Use gtest as it is the team recommendation
+ # Unfortunately gtest is very hard to setup as not binary distributed
+ # catch is only one header so it is very easy
+ # Catch can be downloaded from:
+ # https://raw.github.com/philsquared/Catch/master/single_include/catch.hpp
+ # Then append the download folder to the CMAKE_INCLUDE_PATH variable or
+ # copy it in a standard location (/usr/include on most linux distribution).
+ find_path(CATCH_HEADER catch.hpp)
+ include_directories(${CATCH_HEADER})
+
+ # Add unit test
+ add_executable(cparameterUnitTest Test.cpp)
+ # Do not warn about passing a null pointer for arguments marked as requiring
+ # a non-null value by the "nonnull" function attribute.
+ # This is done as the unit tests check that invalid api use result in
+ # proper failure.
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-nonnull")
+
+ target_link_libraries(cparameterUnitTest cparameter)
+ add_test(cparameterUnitTest cparameterUnitTest)
+endif()
diff --git a/bindings/c/ParameterFramework.cpp b/bindings/c/ParameterFramework.cpp
new file mode 100644
index 0000000..efc7d99
--- /dev/null
+++ b/bindings/c/ParameterFramework.cpp
@@ -0,0 +1,397 @@
+/*
+ * Copyright (c) 2015, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ParameterFramework.h"
+#include <ParameterMgrPlatformConnector.h>
+
+#include <iostream>
+#include <limits>
+#include <string>
+#include <map>
+
+#include <cassert>
+#include <cstring>
+#include <cstdlib>
+
+using std::string;
+
+/** Rename long pfw types to short ones in pfw namespace. */
+namespace pfw
+{
+ typedef ISelectionCriterionInterface Criterion;
+ typedef std::map<string, Criterion *> Criteria;
+ typedef CParameterMgrPlatformConnector Pfw;
+}
+
+/** Class to abstract the boolean+string status api. */
+class Status
+{
+public:
+ /** Fail without an instance of status. */
+ static bool failure() { return false; }
+ /** Fail with the given error msg. */
+ bool failure(const string &msg) { mMsg = msg; return false; }
+ /** Success (no error message). */
+ bool success() { mMsg.clear(); return true; }
+
+ /** Forward a status operation.
+ * @param success[in] the operaton status to forward
+ * or forward a previous failure if omitted
+ */
+ bool forward(bool success = false) {
+ if (success) { mMsg.clear(); }
+ return success;
+ }
+ /** Error message accessors.
+ *
+ * Pfw api requires to provide a reference to a string in order
+ * for it to log. This function provide a reference to a string that
+ * will be added to the error message on failure.
+ */
+ string &msg() { return mMsg; }
+private:
+ string mMsg;
+};
+
+///////////////////////////////
+///////////// Log /////////////
+///////////////////////////////
+
+/** Default log callback. Log to cout or cerr depending on level. */
+static void defaultLogCb(void *, PfwLogLevel level, const char *logLine) {
+ switch (level) {
+ case pfwLogInfo:
+ std::cout << logLine << std::endl;
+ break;
+ case pfwLogWarning:
+ std::cerr << logLine << std::endl;
+ break;
+ };
+}
+
+static PfwLogger defaultLogger = { NULL, &defaultLogCb };
+
+class LogWrapper : public CParameterMgrPlatformConnector::ILogger
+{
+public:
+ LogWrapper(const PfwLogger &logger) : mLogger(logger) {}
+ LogWrapper() : mLogger() {}
+ virtual ~LogWrapper() {}
+private:
+ virtual void log(bool bIsWarning, const string &strLog)
+ {
+ // A LogWrapper should NOT be register to the pfw (thus log called)
+ // if logCb is NULL.
+ assert(mLogger.logCb != NULL);
+ mLogger.logCb(mLogger.userCtx,
+ bIsWarning ? pfwLogWarning : pfwLogInfo,
+ strLog.c_str());
+ }
+ PfwLogger mLogger;
+};
+
+///////////////////////////////
+///////////// Core ////////////
+///////////////////////////////
+
+struct PfwHandler_
+{
+ void setLogger(const PfwLogger *logger);
+ bool createCriteria(const PfwCriterion criteria[], size_t criterionNb);
+
+ pfw::Criteria criteria;
+ pfw::Pfw *pfw;
+ /** Status of the last called function.
+ * Is mutable because even a const function can fail.
+ */
+ mutable Status lastStatus;
+private:
+ LogWrapper mLogger;
+};
+
+
+PfwHandler *pfwCreate()
+{
+ return new PfwHandler();
+}
+
+void pfwDestroy(PfwHandler *handle)
+{
+ if(handle != NULL and handle->pfw != NULL) {
+ delete handle->pfw;
+ }
+ delete handle;
+}
+
+void PfwHandler::setLogger(const PfwLogger *logger)
+{
+ if (logger != NULL and logger->logCb == NULL) {
+ return; // There is no callback, do not log => do not add a logger
+ }
+ mLogger = logger != NULL ? *logger : defaultLogger;
+ pfw->setLogger(&mLogger);
+}
+
+
+bool PfwHandler::createCriteria(const PfwCriterion criteriaArray[], size_t criterionNb)
+{
+ Status &status = lastStatus;
+ // Add criteria
+ for (size_t criterionIndex = 0; criterionIndex < criterionNb; ++criterionIndex) {
+ const PfwCriterion &criterion = criteriaArray[criterionIndex];
+ if (criterion.name == NULL) {
+ return status.failure("Criterion name is NULL");
+ }
+ if (criterion.values == NULL) {
+ return status.failure("Criterion values is NULL");
+ }
+ // Check that the criterion does not exist
+ if (criteria.find(criterion.name) != criteria.end()) {
+ return status.failure("Criterion \"" + string(criterion.name) +
+ "\" already exist");
+ }
+
+ // Create criterion type
+ ISelectionCriterionTypeInterface *type =
+ pfw->createSelectionCriterionType(criterion.inclusive);
+ assert(type != NULL);
+ // Add criterion values
+ for (size_t valueIndex = 0; criterion.values[valueIndex] != NULL; ++valueIndex) {
+ int value;
+ if (criterion.inclusive) {
+ // Check that (int)1 << valueIndex would not overflow (UB)
+ if(std::numeric_limits<int>::max() >> valueIndex == 0) {
+ return status.failure("Too many values for criterion " +
+ string(criterion.name));
+ }
+ value = 1 << valueIndex;
+ } else {
+ value = valueIndex;
+ }
+ const char * valueName = criterion.values[valueIndex];
+ if(not type->addValuePair(value, valueName)) {
+ return status.failure("Could not add value " + string(valueName) +
+ " to criterion " + criterion.name);
+ }
+ }
+ // Create criterion and add it to the pfw
+ criteria[criterion.name] = pfw->createSelectionCriterion(criterion.name, type);
+ }
+ return status.success();
+}
+
+
+bool pfwStart(PfwHandler *handle, const char *configPath,
+ const PfwCriterion criteria[], size_t criterionNb,
+ const PfwLogger *logger)
+{
+ // Check that the api is correctly used
+ if (handle == NULL) { return Status::failure(); }
+ Status &status = handle->lastStatus;
+
+ if (handle->pfw != NULL) {
+ return status.failure("Can not start an already started parameter framework");
+ }
+ if (configPath == NULL) {
+ return status.failure("char *configPath is NULL, "
+ "while starting the parameter framework");
+ }
+ if (criteria == NULL) {
+ return status.failure("char *criteria is NULL, "
+ "while starting the parameter framework "
+ "(config path is " + string(configPath) + ")");
+ }
+ // Create a pfw
+ handle->pfw = new CParameterMgrPlatformConnector(configPath);
+
+ handle->setLogger(logger);
+
+ if (not handle->createCriteria(criteria, criterionNb)) {
+ return status.failure();
+ }
+
+ return status.forward(handle->pfw->start(status.msg()));
+}
+
+const char *pfwGetLastError(const PfwHandler *handle)
+{
+ return handle == NULL ? NULL : handle->lastStatus.msg().c_str();
+}
+
+static pfw::Criterion *getCriterion(const pfw::Criteria &criteria,
+ const string &name)
+{
+ pfw::Criteria::const_iterator it = criteria.find(name);
+ return it == criteria.end() ? NULL : it->second;
+}
+
+bool pfwSetCriterion(PfwHandler *handle, const char name[], int value)
+{
+ if (handle == NULL) { return Status::failure(); }
+ Status &status = handle->lastStatus;
+ if (name == NULL) {
+ return status.failure("char *name of the criterion is NULL, "
+ "while setting a criterion.");
+ }
+ if (handle->pfw == NULL) {
+ return status.failure("Can not set criterion \"" + string(name) +
+ "\" as the parameter framework is not started.");
+ }
+ pfw::Criterion *criterion = getCriterion(handle->criteria, name);
+ if (criterion == NULL) {
+ return status.failure("Can not set criterion " + string(name) + " as does not exist");
+ }
+ criterion->setCriterionState(value);
+ return status.success();
+}
+bool pfwGetCriterion(const PfwHandler *handle, const char name[], int *value)
+{
+ if (handle == NULL) { return Status::failure(); }
+ Status &status = handle->lastStatus;
+ if (name == NULL) {
+ return status.failure("char *name of the criterion is NULL, "
+ "while getting a criterion.");
+ }
+ if (handle->pfw == NULL) {
+ return status.failure("Can not get criterion \"" + string(name) +
+ "\" as the parameter framework is not started.");
+ }
+ if (value == NULL) {
+ return status.failure("Can not get criterion \"" + string(name) +
+ "\" as the out value is NULL.");
+ }
+ pfw::Criterion *criterion = getCriterion(handle->criteria, name);
+ if (criterion == NULL) {
+ return status.failure("Can not get criterion " + string(name) + " as it does not exist");
+ }
+ *value = criterion->getCriterionState();
+ return status.success();
+}
+
+bool pfwApplyConfigurations(const PfwHandler *handle)
+{
+ if (handle == NULL) { return Status::failure(); }
+ Status &status = handle->lastStatus;
+ if (handle->pfw == NULL) {
+ return status.failure("Can not commit criteria "
+ "as the parameter framework is not started.");
+ }
+ handle->pfw->applyConfigurations();
+ return status.success();
+}
+
+///////////////////////////////
+/////// Parameter access //////
+///////////////////////////////
+
+struct PfwParameterHandler_
+{
+ PfwHandler &pfw;
+ CParameterHandle &parameter;
+};
+
+PfwParameterHandler *pfwBindParameter(PfwHandler *handle, const char path[])
+{
+ if (handle == NULL) { return NULL; }
+ Status &status = handle->lastStatus;
+ if (path == NULL) {
+ status.failure("Can not bind a parameter without its path");
+ return NULL;
+ }
+ if (handle->pfw == NULL) {
+ status.failure("The parameter framework is not started, "
+ "while trying to bind parameter \"" + string(path) + "\")");
+ return NULL;
+ }
+
+ CParameterHandle *paramHandle;
+ paramHandle = handle->pfw->createParameterHandle(path, status.msg());
+ if (paramHandle == NULL) {
+ return NULL;
+ }
+
+ status.success();
+ PfwParameterHandler publicHandle = {*handle, *paramHandle};
+ return new PfwParameterHandler(publicHandle);
+}
+
+void pfwUnbindParameter(PfwParameterHandler *handle)
+{
+ if (handle == NULL) { return; }
+ delete &handle->parameter;
+ delete handle;
+}
+
+
+bool pfwGetIntParameter(const PfwParameterHandler *handle, int32_t *value)
+{
+ if (handle == NULL) { return Status::failure(); }
+ Status &status = handle->pfw.lastStatus;
+ if (value == NULL) {
+ return status.failure("int32_t *value is NULL, "
+ "while trying to get parameter \"" +
+ handle->parameter.getPath() + "\" value as int)");
+ }
+ return status.forward(handle->parameter.getAsSignedInteger(*value, status.msg()));
+}
+bool pfwSetIntParameter(PfwParameterHandler *handle, int32_t value)
+{
+ if (handle == NULL) { return Status::failure(); }
+ Status &status = handle->pfw.lastStatus;
+ return status.forward(handle->parameter.setAsSignedInteger(value, status.msg()));
+}
+
+bool pfwGetStringParameter(const PfwParameterHandler *handle, const char *value[])
+{
+ if (handle == NULL) { return Status::failure(); }
+ Status &status = handle->pfw.lastStatus;
+ if (value == NULL) {
+ return status.failure("char **value is NULL, "
+ "while trying to get parameter \"" +
+ handle->parameter.getPath() + "\" value as string)");
+ }
+ *value = NULL;
+ string retValue;
+ bool success = handle->parameter.getAsString(retValue, status.msg());
+ if (not success) { return status.forward(); }
+
+ *value = strdup(retValue.c_str());
+ return status.success();
+}
+
+bool pfwSetStringParameter(PfwParameterHandler *handle, const char value[])
+{
+ if (handle == NULL) { return Status::failure(); }
+ Status &status = handle->pfw.lastStatus;
+ return status.forward(handle->parameter.setAsString(value, status.msg()));
+}
+
+void pfwFree(void *ptr) { std::free(ptr); }
+
diff --git a/bindings/c/ParameterFramework.h b/bindings/c/ParameterFramework.h
new file mode 100644
index 0000000..20cc820
--- /dev/null
+++ b/bindings/c/ParameterFramework.h
@@ -0,0 +1,265 @@
+/** @copyright
+ * Copyright (c) 2015, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file Simplified parameter framework C API.
+ * This API does not target a perfect one/one mapping with the c++ one,
+ * but rather aim ease of use and type safety (as far as possible in c).
+ * All function are reentrant and function call on a pfw (PfwHandle)
+ * does not impact any other pfw.
+ * Ie. There is no shared resources between pfw instances.
+ */
+
+#pragma once
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stddef.h>
+
+/** Lots of function in this API require non null pointer parameter.
+ * Such arguments are marked NONNULL.
+ */
+#define NONNULL __attribute__((nonnull))
+#define NONNULL_(...) __attribute__((nonnull (__VA_ARGS__)))
+#define USERESULT __attribute__((warn_unused_result))
+
+/** Private handle to a parameter framework.
+ * A PfwHandler* is valid if:
+ * - it was created by pfwCreate
+ * - it has not been destroyed by pfwDestroyParameter
+ * - is not NULL
+ * A valid handle MUST be provided to all pfw related method.
+ * A valid handler MUST be destroyed with pfwDestroy before programme
+ * termination.
+ * @note Forward declaration to break header dependency.
+ */
+struct PfwHandler_;
+/** Typedef for use ease. @see PfwHandler_. */
+typedef struct PfwHandler_ PfwHandler;
+
+///////////////////////////////
+///////////// Log /////////////
+///////////////////////////////
+/** Pfw log level for the callback. */
+typedef enum {
+ pfwLogInfo = 55, //< Random value to avoid unfortunate mismatch.
+ pfwLogWarning
+} PfwLogLevel;
+
+/** Type of the parameter framework log callback.
+ * @param userCtx[in] Arbitrary context provided during callback registration.
+ * @param level[in] Log level of the log line.
+ * @param logLine[in] Log line (without end line control character like '\n')
+ * to be logged. The pointer is invalidate after function
+ * return or if any pfw function is called.
+ */
+typedef void PfwLogCb(void *userCtx, PfwLogLevel level, const char *logLine);
+
+/** Logger containing a callback method and its context. */
+typedef struct {
+ /** User defined arbitrary value that will be provided to all logCb call. */
+ void *userCtx;
+ /** Callback that will be called.
+ * If NULL nothing will be logged.
+ */
+ PfwLogCb *logCb;
+} PfwLogger;
+
+///////////////////////////////
+///////////// Core ////////////
+///////////////////////////////
+
+/** Structure of a parameter framework criterion. */
+typedef struct {
+ /** Name of the criterion in the pfw configuration rules. */
+ const char *name; //< Must not be null.
+ bool inclusive; //< True if the criterion is inclusive, false if exclusive.
+ /** Null terminated list of criterion value names.
+ * @example { "Red", "Green", "Blue", NULL }
+ *
+ * For an exclusive criterion, the list must not contain more elements then
+ * INT_MAX.
+ * For an inclusive criterion, the list must not contain more elements then
+ * sizeof(int) * BIT_CHAR - 1.
+ * Ie: (int)1 << n must *not* overflow (UB),
+ * were n is the number of element in the
+ * list. @see pfwSetCriterion
+ */
+ const char **values; //< Must not be null.
+} PfwCriterion;
+
+
+/** Create a parameter framework instance.
+ * Can not fail except for memory allocation.
+ */
+PfwHandler *pfwCreate() USERESULT;
+
+/** Destroy a parameter framework. Can not fail. */
+void pfwDestroy(PfwHandler *handle) NONNULL;
+
+/** Start a parameter framework.
+ * @param handle[in] @see PfwHandler
+ * @param configPath[in] Path to the file containing the pfw configuration.
+ * @param criteria[in] An array of PfwCriterion.
+ * @param criterionNb[in] The number of PfwCriterion in criteria.
+ * @param logger[in] the logger to use for all operation.
+ * If NULL, log infos to standard output and
+ * errors to standard error.
+ * @return true on success, false on failure.
+ */
+bool pfwStart(PfwHandler *handle, const char *configPath,
+ const PfwCriterion criteria[], size_t criterionNb,
+ const PfwLogger *loggger) NONNULL_(1, 2, 3) USERESULT;
+
+/** @return a string describing the last call result.
+ * If the last pfw function call succeeded, return an empty string.
+ * If the last pfw function call failed, return a message explaining the error cause.
+ * The return pointer is invalidated if any pfw method is called on the SAME
+ * PfwHandle.
+ *
+ * Each PfwHandle own it's last error message. It is not static nor TLS.
+ * As a result, calling a pfw function with a NULL PfwHandler will result in a
+ * failure WITHOUT updating the last error.
+ */
+const char *pfwGetLastError(const PfwHandler *handle) NONNULL;
+
+/** Set a criterion value given its name and value.
+ * @param handle[in] @see PfwHandler
+ * @param name[in] The name of the criterion that need to be changed.
+ * @param value If the criterion is exclusive, the index of the new value.
+ * If the criterion is inclusive, a bit field where each bit
+ * correspond to the value index.
+ * For an inclusive criterion defined as such: { "Red", "Green", "Blue", NULL }
+ * to set the value Green and Blue, value has to be 1<<1 | 1<<2 = 0b110 = 6.
+ * For an exclusive criterion defined as such: { "Car", "Boat", "Plane", NULL }
+ * to set the value Plane, value has to be 2.
+ *
+ * Criterion change do not have impact on the parameters value
+ * (no configuration applied) until the changes are committed using pfwApplyConfigurations.
+ *
+ * @return true on success and false on failure.
+ */
+bool pfwSetCriterion(PfwHandler *handle, const char name[], int value) NONNULL USERESULT;
+/** Get a criterion value given its name.
+ * Same usage as pfwSetCriterion except that value is an out param.
+ * Get criterion will return the last value setted with pfwSetCriterion independantly of pfwCommitCritenio.
+ */
+bool pfwGetCriterion(const PfwHandler *handle, const char name[], int *value) NONNULL USERESULT;
+
+/** Commit criteria change and change parameters according to the configurations.
+ * Criterion do not have impact on the parameters value when changed,
+ * instead they are staged and only feed to the rule engine
+ * (who then impact parameter values according to the configuration) when
+ * committed with this function.
+ *
+ * @param handle[in] @see PfwHandler
+ * @return true on success and false on failure.
+ */
+bool pfwApplyConfigurations(const PfwHandler *handle) NONNULL USERESULT;
+
+///////////////////////////////
+/////// Parameter access //////
+///////////////////////////////
+
+/** Handler to a pfw parameter.
+ * A PfwParameterHandler* is valid if:
+ * - it was created by pfwBindParameter
+ * - it has not been destroyed by pfwDestroyParameter
+ * - is not NULL
+ * - the pfwHandle used to created is still valid (ie. it must not outlive
+ * its parent pfw)
+ * A valid handle MUST be provided to all pfw parameter related method.
+ * Any created handle MUST be destroyed (with pfwDestroyParameter) before
+ * the PfwHandler that was used for its creation.
+ * @note Forward declaration to break header dependency.
+ */
+struct PfwParameterHandler_;
+typedef struct PfwParameterHandler_ PfwParameterHandler;
+
+/** Construct the handle to a parameter given its path.
+ * The PfwHandle MUST stay valid until PfwParameterHandler destruction.
+ * @return a PfwParameterHandler on success, NULL on error.
+ * @see pfwGetLastError for error detail.
+ */
+PfwParameterHandler *pfwBindParameter(PfwHandler *handle, const char path[]) NONNULL;
+/** Destroy a parameter handle. Can not fail. */
+void pfwUnbindParameter(PfwParameterHandler *handle) NONNULL;
+
+/** Access the value of a previously bind int parameter.
+ * @param handle[in] Handler to a valid parameter.
+ * @param value[in] Non null pointer to an integer that will
+ * hold the parameter value on success, undefined otherwise.
+ * return true of success, false on failure.
+ */
+bool pfwGetIntParameter(const PfwParameterHandler *handle, int32_t *value ) NONNULL USERESULT;
+
+/** Set the value of a previously bind int parameter.
+ * @param handle[in] Handler to a valid parameter.
+ * @param value[in] The parameter value to set.
+ * return true of success, false on failure.
+ */
+bool pfwSetIntParameter(PfwParameterHandler *handle, int32_t value) NONNULL USERESULT;
+
+/** Access the value of a previously bind string parameter.
+ * @param handle[in] Handler to a valid parameter.
+ * @param value[out] Non null pointer on a string.
+ * Will point on the parameter value string on success,
+ * NULL on failure.
+ * The callee MUST free the returned string using pfwFree after use.
+ * @return true on success, false on failure.
+ */
+bool pfwGetStringParameter(const PfwParameterHandler *handle, const char *value[]) NONNULL;
+
+/** Set the value of a previously bind string parameter.
+ * @param handle[in] Handler to a valid parameter
+ * @param value[in] Non null pointer to a null terminated string to set.
+ */
+bool pfwSetStringParameter(PfwParameterHandler *handle, const char value[]) NONNULL USERESULT;
+
+/** Frees the memory space pointed to by ptr,
+ * which must have been returned by a previous call to the pfw.
+ *
+ * @param ptr[in] pointer to the memory to free.
+ * @see man 3 free for usage.
+ * @note Wrapper around the standard free to avoid problems
+ * in case of a different pfw and client allocator.
+ */
+void pfwFree(void *ptr);
+
+#undef NONNULL
+#undef NONNULL_
+#undef USERESULT
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bindings/c/Test.cpp b/bindings/c/Test.cpp
new file mode 100644
index 0000000..c450e60
--- /dev/null
+++ b/bindings/c/Test.cpp
@@ -0,0 +1,414 @@
+/*
+ * Copyright (c) 2015, Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ParameterFramework.h"
+
+#define CATCH_CONFIG_MAIN // This tells Catch to provide a main()
+#include <catch.hpp>
+
+#include <string>
+#include <memory>
+#include <vector>
+
+#include <cstring>
+#include <cerrno>
+#include <climits>
+extern "C"
+{
+#include <unistd.h>
+}
+
+struct Test
+{
+ /** @return true if str is empty. */
+ bool empty(const char *str)
+ {
+ REQUIRE(str != NULL);
+ return *str == '\0';
+ }
+
+ void REQUIRE_FAILURE(bool success)
+ {
+ THEN("It should be an error") {
+ INFO("Previous pfw log: \n" + logLines);
+ CAPTURE(pfwGetLastError(pfw));
+ CHECK(not success);
+ CHECK(not empty(pfwGetLastError(pfw)));
+ }
+ }
+
+ void REQUIRE_SUCCESS(bool success)
+ {
+ THEN("It should be a success") {
+ INFO("Previous pfw log: \n" + logLines);
+ CAPTURE(pfwGetLastError(pfw));
+ CHECK(success);
+ CHECK(empty(pfwGetLastError(pfw)));
+ }
+ }
+
+ /** Class to create a temporary file */
+ class TmpFile
+ {
+ public:
+ TmpFile(const std::string &content) {
+ char tmpName[] = "./tmpPfwUnitTestXXXXXX";
+ mFd = mkstemp(tmpName);
+ CAPTURE(errno);
+ REQUIRE(mFd != -1);
+ mPath = tmpName;
+ write(mFd, content.c_str(), content.length());
+ }
+ ~TmpFile() {
+ CHECK(close(mFd) != -1);
+ unlink(mPath.c_str());
+ }
+ operator const char *() const { return mPath.c_str(); }
+ const std::string &path() const { return mPath; }
+ private:
+ std::string mPath;
+ int mFd;
+ };
+
+ /** Log in logLines. */
+ static void logCb(void *voidLogLines, PfwLogLevel level, const char *logLine)
+ {
+ std::string &logLines = *reinterpret_cast<std::string *>(voidLogLines);
+ switch(level) {
+ case pfwLogWarning:
+ logLines += "Warning: ";
+ break;
+ case pfwLogInfo:
+ logLines += "Info: ";
+ }
+ logLines += logLine;
+ logLines += '\n';
+ }
+
+ /** Log buffer, will only be display in case of failure */
+ std::string logLines;
+
+ /** Pfw handler used in the tests. */
+ PfwHandler *pfw;
+
+};
+
+TEST_CASE_METHOD(Test, "Parameter-framework c api use") {
+ // Create criteria
+ const char *letterList[] = {"a", "b", "c", NULL};
+ const char *numberList[] = {"1", "2", "3", NULL};
+ const PfwCriterion criteria[] = {
+ {"inclusiveCrit", true, letterList},
+ {"exclusiveCrit", false, numberList},
+ };
+ size_t criterionNb = sizeof(criteria)/sizeof(criteria[0]);
+ PfwLogger logger = {&logLines, logCb};
+
+ // Create valid pfw config file
+ const char *intParameterPath = "/test/system/integer";
+ const char *stringParameterPath = "/test/system/string";
+ TmpFile system("<?xml version='1.0' encoding='UTF-8'?>\
+ <Subsystem Name='system' Type='Virtual' Endianness='Little'>\
+ <ComponentLibrary/>\
+ <InstanceDefinition>\
+ <IntegerParameter Name='integer' Size='32' Signed='true' Max='100'/>\
+ <StringParameter Name='string' MaxLength='9'/>\
+ </InstanceDefinition>\
+ </Subsystem>");
+ TmpFile libraries("<?xml version='1.0' encoding='UTF-8'?>\
+ <SystemClass Name='test'>\
+ <SubsystemInclude Path='" + system.path() + "'/>\
+ </SystemClass>");
+ TmpFile config("<?xml version='1.0' encoding='UTF-8'?>\
+ <ParameterFrameworkConfiguration\
+ SystemClassName='test' TuningAllowed='false'>\
+ <SubsystemPlugins/>\
+ <StructureDescriptionFileLocation Path='" + libraries.path() + "'/>\
+ </ParameterFrameworkConfiguration>");
+
+ GIVEN("A created parameter framework") {
+ pfw = pfwCreate();
+ REQUIRE(pfw != NULL);
+
+ THEN("Error message should be empty") {
+ CHECK(empty(pfwGetLastError(pfw)));
+ }
+
+ WHEN("The pfw is started without an handler") {
+ CHECK(not pfwStart(NULL, config, criteria, criterionNb, &logger));
+ }
+ WHEN("The pfw is started without a config path") {
+ REQUIRE_FAILURE(pfwStart(pfw, NULL, criteria, criterionNb, &logger));
+ }
+ WHEN("The pfw is started without an existent file") {
+ REQUIRE_FAILURE(pfwStart(pfw, "/doNotExist", criteria, criterionNb, &logger));
+ }
+
+ WHEN("The pfw is started without a criteria list") {
+ REQUIRE_FAILURE(pfwStart(pfw, config, NULL, criterionNb, &logger));
+ }
+ WHEN("The pfw is started with duplicated criterion value") {
+ const PfwCriterion duplicatedCriteria[] = {
+ {"duplicated name", true, letterList},
+ {"duplicated name", false, numberList},
+ };
+ REQUIRE_FAILURE(pfwStart(pfw, config, duplicatedCriteria, 2, &logger));
+ }
+ WHEN("The pfw is started with duplicated criterion value state") {
+ const char * values[] = {"a", "a", NULL};
+ const PfwCriterion duplicatedCriteria[] = {{"name", true, values}};
+
+ WHEN("Using test logger") {
+ REQUIRE_FAILURE(pfwStart(pfw, config, duplicatedCriteria, 1, &logger));
+ }
+ WHEN("Using default logger") {
+ // Test coverage of default logger warning
+ REQUIRE_FAILURE(pfwStart(pfw, config, duplicatedCriteria, 1, NULL));
+ }
+ }
+ WHEN("The pfw is started with NULL name criterion") {
+ const PfwCriterion duplicatedCriteria[] = {{NULL, true, letterList}};
+ REQUIRE_FAILURE(pfwStart(pfw, config, duplicatedCriteria, 1, &logger));
+ }
+ WHEN("The pfw is started with NULL criterion state list") {
+ const PfwCriterion duplicatedCriteria[] = {{"name", true, NULL}};
+ REQUIRE_FAILURE(pfwStart(pfw, config, duplicatedCriteria, 1, &logger));
+ }
+ GIVEN("A criteria with lots of values")
+ {
+ // Build a criterion with as many value as there is bits in int.
+ std::vector<char> names(sizeof(int) * CHAR_BIT + 1, 'a');
+ names.back() = '\0';
+ std::vector<const char *> values(names.size());
+ for(size_t i = 0; i < values.size(); ++i) {
+ values[i] = &names[i];
+ }
+ values.back() = NULL;
+ /* The pfw c api requires criterion values to be a NULL terminated
+ * array of string. Each string is a pointer to a NULL terminated
+ * array of char. The pfw requires each string to be different
+ * from all others, ie strcmp(values[i], values[j]) != 0 for any
+ * i j.
+ *
+ * In order to generate easily an array of different strings,
+ * instantiate one string (names) big enough
+ * (@see PfwCriterion::values).
+ * Then instantiate an array of pointer (values),
+ * each pointing to a different position in the previously
+ * created string.
+ *
+ * Representation of the names and values vectors.
+ *
+ * n = number of bit in an int
+ * <--- n+1 elements --->
+ * names = |a|a|a|a|...|a|a|a|\0|
+ * ^ ^ ^
+ * values[0] = ´ | |
+ * values[1] = --´ |
+ * ... |
+ * values[n - 1] = -----------´
+ * values[n] = NULL
+ *
+ */
+ const PfwCriterion duplicatedCriteria[] = {{"name", true, &values[0]}};
+
+ WHEN("The pfw is started with a too long criterion state list") {
+ REQUIRE_FAILURE(pfwStart(pfw, config, duplicatedCriteria, 1, &logger));
+ }
+ WHEN("The pfw is started with max length criterion state list") {
+ values[values.size() - 2] = NULL; // Hide last value
+ REQUIRE_SUCCESS(pfwStart(pfw, config, duplicatedCriteria, 1, &logger));
+ }
+ }
+
+ WHEN("The pfw is started with zero criteria") {
+ REQUIRE_SUCCESS(pfwStart(pfw, config, criteria, 0, &logger));
+ }
+
+ WHEN("The pfw is started twice a pfw") {
+ REQUIRE_SUCCESS(pfwStart(pfw, config, criteria, criterionNb, &logger));
+ REQUIRE_FAILURE(pfwStart(pfw, config, criteria, criterionNb, &logger));
+ }
+
+ WHEN("The pfw is started without a logger callback") {
+ PfwLogger noLog = { NULL, NULL };
+ REQUIRE_SUCCESS(pfwStart(pfw, config, criteria, criterionNb, &noLog));
+ }
+ WHEN("The pfw is started with default logger") {
+ REQUIRE_SUCCESS(pfwStart(pfw, config, criteria, criterionNb, NULL));
+ }
+
+ WHEN("Get criterion of a stopped pfw") {
+ int value;
+ REQUIRE_FAILURE(pfwGetCriterion(pfw, criteria[0].name, &value));
+ }
+ WHEN("Set criterion of a stopped pfw") {
+ REQUIRE_FAILURE(pfwSetCriterion(pfw, criteria[0].name, 1));
+ }
+ WHEN("Commit criteria of a stopped pfw") {
+ REQUIRE_FAILURE(pfwApplyConfigurations(pfw));
+ }
+
+ WHEN("Bind parameter with a stopped pfw") {
+ REQUIRE(pfwBindParameter(pfw, intParameterPath) == NULL);
+ }
+
+ WHEN("The pfw is started correctly")
+ {
+ REQUIRE_SUCCESS(pfwStart(pfw, config, criteria, criterionNb, &logger));
+ int value;
+
+ WHEN("Get criterion without an handle") {
+ REQUIRE(not pfwGetCriterion(NULL, criteria[0].name, &value));
+ }
+ WHEN("Get criterion without a name") {
+ REQUIRE_FAILURE(pfwGetCriterion(pfw, NULL, &value));
+ }
+ WHEN("Get criterion without an output value") {
+ REQUIRE_FAILURE(pfwGetCriterion(pfw, criteria[0].name, NULL));
+ }
+ WHEN("Get not existing criterion") {
+ REQUIRE_FAILURE(pfwGetCriterion(pfw, "Do not exist", &value));
+ }
+ THEN("All criterion should value 0") {
+ for(size_t i = 0; i < criterionNb; ++i) {
+ const char *criterionName = criteria[i].name;
+ CAPTURE(criterionName);
+ REQUIRE_SUCCESS(pfwGetCriterion(pfw, criterionName, &value));
+ REQUIRE(value == 0);
+ }
+ }
+
+ WHEN("Set criterion without an handle") {
+ REQUIRE(not pfwSetCriterion(NULL, criteria[0].name, 1));
+ }
+ WHEN("Set criterion without a name") {
+ REQUIRE_FAILURE(pfwSetCriterion(pfw, NULL, 2));
+ }
+ WHEN("Set not existing criterion") {
+ REQUIRE_FAILURE(pfwSetCriterion(pfw, "Do not exist", 3));
+ }
+ WHEN("Set criterion value") {
+ for(size_t i = 0; i < criterionNb; ++i) {
+ const char *criterionName = criteria[i].name;
+ CAPTURE(criterionName);
+ REQUIRE_SUCCESS(pfwSetCriterion(pfw, criterionName, 3));
+ }
+ THEN("Get criterion value should return what was set") {
+ for(size_t i = 0; i < criterionNb; ++i) {
+ const char *criterionName = criteria[i].name;
+ CAPTURE(criterionName);
+ REQUIRE_SUCCESS(pfwGetCriterion(pfw, criterionName, &value));
+ REQUIRE(value == 3);
+ }
+ }
+ }
+ WHEN("Commit criteria without a pfw") {
+ REQUIRE(not pfwApplyConfigurations(NULL));
+ }
+ WHEN("Commit criteria of a started pfw") {
+ REQUIRE_SUCCESS(pfwApplyConfigurations(pfw));
+ }
+
+ WHEN("Bind parameter without a pfw") {
+ REQUIRE(pfwBindParameter(NULL, intParameterPath) == NULL);
+ }
+ WHEN("Bind parameter without a path") {
+ REQUIRE_FAILURE(pfwBindParameter(pfw, NULL) != NULL);
+ }
+ WHEN("Bind a non existing parameter") {
+ REQUIRE_FAILURE(pfwBindParameter(pfw, "do/not/exist") != NULL);
+ }
+
+ WHEN("Set an int parameter without a parameter handle") {
+ REQUIRE(not pfwSetIntParameter(NULL, value));
+ }
+ WHEN("Get an int parameter without a parameter handle") {
+ REQUIRE(not pfwGetIntParameter(NULL, &value));
+ }
+
+ GIVEN("An integer parameter handle") {
+ PfwParameterHandler *param = pfwBindParameter(pfw, intParameterPath);
+ REQUIRE_SUCCESS(param != NULL);
+
+ WHEN("Get an int parameter without an output value") {
+ REQUIRE_FAILURE(pfwGetIntParameter(param, NULL));
+ }
+
+ WHEN("Set parameter out of range") {
+ REQUIRE_FAILURE(pfwSetIntParameter(param, 101));
+ }
+
+ WHEN("Set parameter") {
+ REQUIRE_SUCCESS(pfwSetIntParameter(param, 11));
+ THEN("Get parameter should return what was set") {
+ REQUIRE_SUCCESS(pfwGetIntParameter(param, &value));
+ REQUIRE(value == 11);
+ }
+ }
+
+ pfwUnbindParameter(param);
+ }
+
+ GIVEN("An string parameter handle") {
+ PfwParameterHandler *param = pfwBindParameter(pfw, stringParameterPath);
+ REQUIRE_SUCCESS(param != NULL);
+
+ WHEN("Get an int parameter without an output value") {
+ REQUIRE_FAILURE(pfwGetStringParameter(param, NULL));
+ }
+
+ WHEN("Set parameter out of range") {
+ REQUIRE_FAILURE(pfwSetStringParameter(param, "ko_1234567"));
+ }
+
+ WHEN("Set parameter") {
+ const char *value;
+ REQUIRE_SUCCESS(pfwSetStringParameter(param, "ok"));
+ THEN("Get parameter should return what was set") {
+ REQUIRE_SUCCESS(pfwGetStringParameter(param, &value));
+ REQUIRE(value == std::string("ok"));
+ pfwFree((void *)value);
+ }
+ }
+
+ pfwUnbindParameter(param);
+ }
+ }
+
+ pfwDestroy(pfw);
+ }
+}
+
+SCENARIO("Get last error without a pfw") {
+ THEN("Should return NULL") {
+ CHECK(pfwGetLastError(NULL) == NULL);
+ }
+}