summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.bzrignore3
-rw-r--r--CMakeLists.txt27
-rw-r--r--apps/CMakeLists.txt3
-rw-r--r--apps/test_multithread.c92
-rw-r--r--docs/Doxyfile.in4
-rw-r--r--docs/ToDo13
-rw-r--r--[-rwxr-xr-x]misc/xml/format.sh0
-rwxr-xr-xpci2
-rw-r--r--pcilib/config.h.in1
-rw-r--r--pcilib/error.c12
-rw-r--r--pcilib/error.h14
-rw-r--r--pcilib/pci.c15
-rw-r--r--pcilib/pcilib.h14
-rw-r--r--pcilib/property.c5
-rw-r--r--pcilib/py.c370
-rw-r--r--pcilib/py.h109
-rw-r--r--pcilib/value.c22
-rw-r--r--pcilib/view.c13
-rw-r--r--pcilib/view.h2
-rw-r--r--pcilib/xml.c24
-rw-r--r--pcitool/cli.c2
-rw-r--r--pywrap/CMakeLists.txt22
-rw-r--r--pywrap/pcipywrap.c503
-rw-r--r--pywrap/pcipywrap.h68
-rw-r--r--pywrap/pcipywrap.i25
-rw-r--r--pywrap/server.py399
-rw-r--r--pywrap/test_pcipywrap.py119
-rw-r--r--views/transform.c54
-rw-r--r--views/transform.h1
-rw-r--r--xml/test/props.xml2
-rw-r--r--xml/test/test_prop2.py6
-rw-r--r--xml/test/test_prop3.py5
-rw-r--r--xml/types.xsd2
33 files changed, 1889 insertions, 64 deletions
diff --git a/.bzrignore b/.bzrignore
index 3c1afaa..e7ce7bc 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -33,3 +33,6 @@ Doxyfile
html
pcilib/build.h
build.h
+build
+pcipywrap.py
+pcipywrapPYTHON_wrap.c
diff --git a/CMakeLists.txt b/CMakeLists.txt
index fcd82b9..b77529e 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,13 +1,14 @@
project(pcitool)
-set(PCILIB_VERSION "0.2.5")
+set(PCILIB_VERSION "0.2.6")
set(PCILIB_ABI_VERSION "2")
-cmake_minimum_required(VERSION 2.6)
+cmake_minimum_required(VERSION 2.8)
#set(PKG_CONFIG_USE_CMAKE_PREFIX_PATH true)
#set(CMAKE_PREFIX_PATH ${CMAKE_SYSTEM_PREFIX_PATH})
-set(DISABLE_PCITOOL FALSE CACHE BOOL "Build only the library")
+set(DISABLE_PCITOOL FALSE CACHE BOOL "Build only the library")
+set(DISABLE_PYTHON FALSE CACHE BOOL "Disable python scripting support")
#list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
@@ -35,7 +36,12 @@ SET(ENV{PKG_CONFIG_PATH} "${LIB_INSTALL_DIR}/pkgconfig:$ENV{PKG_CONFIG_PATH}")
find_package(PkgConfig REQUIRED)
find_package(Threads REQUIRED)
-find_package(PythonLibs REQUIRED)
+
+if (NOT DISABLE_PYTHON)
+ find_package(PythonLibs 2.7 REQUIRED)
+ find_package(SWIG REQUIRED)
+ set(HAVE_PYTHON TRUE)
+endif (NOT DISABLE_PYTHON)
set(EXTRA_SYSTEM_LIBS -lrt)
@@ -91,16 +97,29 @@ add_subdirectory(pcitool)
add_subdirectory(apps)
add_subdirectory(xml)
+if (HAVE_PYTHON)
+ add_subdirectory(pywrap)
+endif (HAVE_PYTHON)
+
set_target_properties(pcilib PROPERTIES
VERSION ${PCILIB_VERSION}
SOVERSION ${PCILIB_ABI_VERSION}
)
+
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/misc/pcitool.pc.in ${CMAKE_CURRENT_BINARY_DIR}/misc/pcitool.pc)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/pcilib/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/pcilib/config.h)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/pcilib/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/pcilib/version.h)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/docs/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/docs/Doxyfile)
+if (NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
+ file(COPY ${CMAKE_SOURCE_DIR}/xml DESTINATION ${CMAKE_BINARY_DIR})
+ file(COPY ${CMAKE_SOURCE_DIR}/pci
+ DESTINATION ${CMAKE_BINARY_DIR}
+ FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
+ )
+endif(NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
+
install(FILES
${CMAKE_CURRENT_BINARY_DIR}/misc/pcitool.pc
DESTINATION ${LIB_INSTALL_DIR}/pkgconfig
diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt
index 4524db4..45d627b 100644
--- a/apps/CMakeLists.txt
+++ b/apps/CMakeLists.txt
@@ -17,3 +17,6 @@ add_executable(compare_to_value compare_to_value.c)
add_executable(heb_strip_bad_values heb_strip_bad_values.c)
add_executable(check_counter check_counter.c)
+
+add_executable(test_multithread test_multithread.c)
+target_link_libraries (test_multithread pcilib ${CMAKE_THREAD_LIBS_INIT})
diff --git a/apps/test_multithread.c b/apps/test_multithread.c
new file mode 100644
index 0000000..4d0e8f2
--- /dev/null
+++ b/apps/test_multithread.c
@@ -0,0 +1,92 @@
+#include <stdio.h>
+#include <pthread.h>
+#include "pcilib.h"
+#include <stdlib.h>
+
+const char* prop = "/registers/fpga/reg1";
+char* reg;
+int stop = 0;
+
+void *get_prop(void *arg)
+{
+ pcilib_t *ctx = (pcilib_t*)arg;
+
+ while(!stop)
+ {
+ int err;
+ pcilib_value_t val = {0};
+ err = pcilib_get_property(ctx, prop, &val);
+ if(err)
+ {
+ printf("err pcilib_read_register\n");
+ return NULL;
+ }
+ long value = pcilib_get_value_as_int(ctx, &val, &err);
+ pcilib_clean_value(ctx, &val);
+ if(err)
+ {
+ printf("err pcilib_get_value_as_int\n");
+ return NULL;
+ }
+ printf("reg = %li\n", value);
+ }
+ return NULL;
+}
+
+void *read_reg(void *arg)
+{
+ pcilib_t *ctx = (pcilib_t*)arg;
+
+ while(!stop)
+ {
+ int err;
+ pcilib_register_value_t reg_val = {0};
+ pcilib_value_t val = {0};
+
+ err = pcilib_read_register(ctx, NULL, reg, &reg_val);
+
+ if(err)
+ {
+ printf("err pcilib_read_register\n");
+ return NULL;
+ }
+ err = pcilib_set_value_from_register_value(ctx, &val, reg_val);
+ if(err)
+ {
+ printf("err pcilib_set_value_from_register_value\n");
+ return NULL;
+ }
+ long value = pcilib_get_value_as_int(ctx, &val, &err);
+ pcilib_clean_value(ctx, &val);
+ if(err)
+ {
+ printf("err pcilib_get_value_as_int\n");
+ return NULL;
+ }
+ printf("reg = %li\n", value);
+ }
+ return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+ if (argc < 5) {
+ printf("Usage:\n\t\t%s <device> <model> <register> <num_threads>\n", argv[0]);
+ exit(0);
+ }
+
+ reg = argv[3];
+ int threads = atoi( argv[4] );
+
+ pcilib_t *ctx = pcilib_open(argv[1], argv[2]);
+
+ for(int i = 0; i < threads; i++)
+ {
+ pthread_t pth;
+ pthread_create(&pth, NULL, read_reg, ctx);
+ }
+
+ getchar();
+ stop = 1;
+ return 0;
+}
diff --git a/docs/Doxyfile.in b/docs/Doxyfile.in
index ef98587..9303846 100644
--- a/docs/Doxyfile.in
+++ b/docs/Doxyfile.in
@@ -243,7 +243,7 @@ TCL_SUBST =
# members will be omitted, etc.
# The default value is: NO.
-OPTIMIZE_OUTPUT_FOR_C = NO
+OPTIMIZE_OUTPUT_FOR_C = YES
# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
# Python sources only. Doxygen will then generate output that is more tailored
@@ -1486,7 +1486,7 @@ MATHJAX_CODEFILE =
# The default value is: YES.
# This tag requires that the tag GENERATE_HTML is set to YES.
-SEARCHENGINE = NO
+SEARCHENGINE = YES
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
# implemented using a web server instead of a web client using Javascript. There
diff --git a/docs/ToDo b/docs/ToDo
index 0c54eea..70daf55 100644
--- a/docs/ToDo
+++ b/docs/ToDo
@@ -11,12 +11,11 @@ High Priority (we would need it for IPE Camera)
Normal Priority (it would make just few things a bit easier)
===============
- 1. Support Python-scripts in the views (we need to provide python API to read registers/properties)
- 2. Integrate base streaming model into the pcitool
- 3. Implement pcilib_configure_autotrigger
- 4. Really check the specified min, max values while setting registers
- 5. Provide OR and AND operations on registers in cli
- 6. Support writting a data from a binary file in cli
+ 1. Integrate base streaming model into the pcitool
+ 2. Implement pcilib_configure_autotrigger
+ 3. Really check the specified min, max values while setting registers
+ 4. Provide OR and AND operations on registers in cli
+ 5. Support writting a data from a binary file in cli
Low Priority (only as generalization for other projects)
============
@@ -25,6 +24,8 @@ Low Priority (only as generalization for other projects)
3. Define a syntax for register dependencies / delays (?)
4. Use pthread_condition_t instead of polling
5. Support FIFO reads/writes from/to registers
+ 6. OPC UA interface to the registers
+ 7. Generate XML models from SystemRDL descriptions
Performance
===========
diff --git a/misc/xml/format.sh b/misc/xml/format.sh
index c522f44..c522f44 100755..100644
--- a/misc/xml/format.sh
+++ b/misc/xml/format.sh
diff --git a/pci b/pci
index a07d93d..5639dc0 100755
--- a/pci
+++ b/pci
@@ -2,4 +2,4 @@
APP_PATH=`dirname $0`
-PCILIB_MODEL_DIR="$APP_PATH/xml" LD_LIBRARY_PATH="$APP_PATH/pcilib" $APP_PATH/pcitool/pci $*
+PYTHONPATH="$APP_PATH/pywrap:$PYTHONPATH" PCILIB_MODEL_DIR="$APP_PATH/xml" LD_LIBRARY_PATH="$APP_PATH/pcilib" $APP_PATH/pcitool/pci $*
diff --git a/pcilib/config.h.in b/pcilib/config.h.in
index bdd9ec3..cd8033c 100644
--- a/pcilib/config.h.in
+++ b/pcilib/config.h.in
@@ -3,3 +3,4 @@
#cmakedefine PCILIB_MODEL_DIR "${PCILIB_MODEL_DIR}"
#cmakedefine PCILIB_DEBUG_DIR "${PCILIB_DEBUG_DIR}"
#cmakedefine HAVE_STDATOMIC_H @HAVE_STDATOMIC_H@
+#cmakedefine HAVE_PYTHON
diff --git a/pcilib/error.c b/pcilib/error.c
index 06af292..ae8bacb 100644
--- a/pcilib/error.c
+++ b/pcilib/error.c
@@ -76,3 +76,15 @@ int pcilib_set_logger(pcilib_log_priority_t min_prio, pcilib_logger_t logger, vo
return 0;
}
+
+pcilib_logger_t pcilib_get_logger() {
+ return pcilib_logger;
+}
+
+pcilib_log_priority_t pcilib_get_log_level() {
+ return pcilib_logger_min_prio;
+}
+
+void* pcilib_get_logger_context() {
+ return pcilib_logger_argument;
+}
diff --git a/pcilib/error.h b/pcilib/error.h
index a9f4c0b..051ecd8 100644
--- a/pcilib/error.h
+++ b/pcilib/error.h
@@ -40,6 +40,20 @@ extern "C" {
void pcilib_log_message(const char *file, int line, pcilib_log_flags_t flags, pcilib_log_priority_t prio, const char *msg, ...);
void pcilib_log_vmessage(const char *file, int line, pcilib_log_flags_t flags, pcilib_log_priority_t prio, const char *msg, va_list va);
+/**
+ * Gets current logger function.
+ */
+pcilib_logger_t pcilib_get_logger();
+
+/**
+ * Gets current logger min priority.
+ */
+pcilib_log_priority_t pcilib_get_log_level();
+
+/**
+ * Gets current logger argument.
+ */
+void* pcilib_get_logger_context();
#ifdef __cplusplus
}
diff --git a/pcilib/pci.c b/pcilib/pci.c
index eaf41ac..19165ba 100644
--- a/pcilib/pci.c
+++ b/pcilib/pci.c
@@ -191,6 +191,14 @@ pcilib_t *pcilib_open(const char *device, const char *model) {
if (!ctx->model)
ctx->model = strdup(model?model:"pci");
+
+ err = pcilib_py_add_script_dir(ctx, NULL);
+ if (err) {
+ pcilib_error("Error (%i) add script path to python path", err);
+ pcilib_close(ctx);
+ return NULL;
+ }
+
xmlerr = pcilib_init_xml(ctx, ctx->model);
if ((xmlerr)&&(xmlerr != PCILIB_ERROR_NOTFOUND)) {
@@ -198,6 +206,7 @@ pcilib_t *pcilib_open(const char *device, const char *model) {
pcilib_close(ctx);
return NULL;
}
+
// We have found neither standard model nor XML
if ((err)&&(xmlerr)) {
@@ -219,7 +228,6 @@ pcilib_t *pcilib_open(const char *device, const char *model) {
pcilib_close(ctx);
return NULL;
}
-
err = pcilib_init_event_engine(ctx);
if (err) {
pcilib_error("Error (%i) initializing event engine\n", err);
@@ -305,8 +313,6 @@ void pcilib_close(pcilib_t *ctx) {
if (ctx->event_plugin)
pcilib_plugin_close(ctx->event_plugin);
-
- pcilib_free_py(ctx);
if (ctx->locks.kmem)
pcilib_free_locking(ctx);
@@ -348,11 +354,12 @@ void pcilib_close(pcilib_t *ctx) {
if (ctx->registers)
free(ctx->registers);
-
+
if (ctx->model)
free(ctx->model);
pcilib_free_xml(ctx);
+ pcilib_free_py(ctx);
if (ctx->handle >= 0)
close(ctx->handle);
diff --git a/pcilib/pcilib.h b/pcilib/pcilib.h
index 3e7cf2b..8ab8e9e 100644
--- a/pcilib/pcilib.h
+++ b/pcilib/pcilib.h
@@ -43,7 +43,8 @@ typedef enum {
typedef enum {
PCILIB_ACCESS_R = 1, /**< getting property is allowed */
PCILIB_ACCESS_W = 2, /**< setting property is allowed */
- PCILIB_ACCESS_RW = 3
+ PCILIB_ACCESS_RW = 3,
+ PCILIB_ACCESS_INCONSISTENT = 0x10000 /**< inconsistent access, one will not read that one has written */
} pcilib_access_mode_t;
typedef enum {
@@ -54,6 +55,7 @@ typedef enum {
PCILIB_REGISTER_RW1C = 5,
PCILIB_REGISTER_W1I = 8, /**< writting 1 inversts the bit, writting 0 keeps the value */
PCILIB_REGISTER_RW1I = 9,
+ PCILIB_REGISTER_INCONSISTENT = 0x10000 /**< inconsistent register, writting and reading does not match */
} pcilib_register_mode_t;
typedef enum {
@@ -1256,6 +1258,16 @@ int pcilib_set_value_from_register_value(pcilib_t *ctx, pcilib_value_t *val, pci
int pcilib_set_value_from_static_string(pcilib_t *ctx, pcilib_value_t *val, const char *str);
/**
+ * Initializes the polymorphic value from the string. The string is copied.
+ * If `val` already contains the value, cleans it first. Therefore, before first usage the value should be always initialized to 0.
+ * @param[in] ctx - pcilib context
+ * @param[in,out] val - initialized polymorphic value
+ * @param[in] str - initializer
+ * @return - 0 on success or memory error
+ */
+int pcilib_set_value_from_string(pcilib_t *ctx, pcilib_value_t *value, const char *str);
+
+/**
* Get the floating point value from the polymorphic type. May inmply impliced type conversion,
* for isntance parsing the number from the string. Will return 0. and report an error if
* conversion failed.
diff --git a/pcilib/property.c b/pcilib/property.c
index a7d1a61..dfab9a6 100644
--- a/pcilib/property.c
+++ b/pcilib/property.c
@@ -165,7 +165,6 @@ pcilib_property_info_t *pcilib_get_property_list(pcilib_t *ctx, const char *bran
continue;
}
-
dir = (struct dir_hash_s*)malloc(sizeof(struct dir_hash_s));
if (!dir) {
err = PCILIB_ERROR_MEMORY;
@@ -226,6 +225,10 @@ pcilib_property_info_t *pcilib_get_property_list(pcilib_t *ctx, const char *bran
};
}
+ HASH_ITER(hh, dir_hash, dir, dir_tmp) {
+ HASH_DEL(dir_hash, dir);
+ free(dir);
+ }
HASH_CLEAR(hh, dir_hash);
memset(&info[pos], 0, sizeof(pcilib_property_info_t));
diff --git a/pcilib/py.c b/pcilib/py.c
index 4256afc..9254df7 100644
--- a/pcilib/py.c
+++ b/pcilib/py.c
@@ -1,66 +1,333 @@
-#include <Python.h>
-
+#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
-
+#include <alloca.h>
#include "pci.h"
#include "debug.h"
#include "pcilib.h"
#include "py.h"
#include "error.h"
+#include "config.h"
+
+#ifdef HAVE_PYTHON
+# include <Python.h>
+#endif /* HAVE_PYTHON */
+
+#ifdef HAVE_PYTHON
+typedef struct pcilib_script_s pcilib_script_t;
+
+struct pcilib_script_s {
+ const char *name; /**< Script name */
+ PyObject *module; /**< PyModule object, contains script enviroment */
+ UT_hash_handle hh; /**< hash */
+};
struct pcilib_py_s {
- PyObject *main_module;
- PyObject *global_dict;
+ int finalyze; /**< Indicates, that we are initialized from wrapper and should not destroy Python resources in destructor */
+ PyObject *main_module; /**< Main interpreter */
+ PyObject *global_dict; /**< Dictionary of main interpreter */
+ PyObject *pcilib_pywrap; /**< pcilib wrapper module */
+ pcilib_script_t *script_hash; /**< Hash with loaded scripts */
};
+#endif /* HAVE_PYTHON */
+
+void pcilib_log_python_error(const char *file, int line, pcilib_log_flags_t flags, pcilib_log_priority_t prio, const char *msg, ...) {
+ va_list va;
+ const char *type = NULL;
+ const char *val = NULL;
+
+#ifdef HAVE_PYTHON
+ PyObject *pytype = NULL;
+ PyObject *pyval = NULL;
+ PyObject *pytraceback = NULL;
+
+ PyErr_Fetch(&pytype, &pyval, &pytraceback);
+ type = PyString_AsString(pytype);
+ val = PyString_AsString(pyval);
+#endif /* HAVE_PYTHON */
+
+ va_start(va, msg);
+ if (type) {
+ char *str;
+ size_t len = 32;
+
+ if (msg) len += strlen(msg);
+ if (type) len += strlen(type);
+ if (val) len += strlen(val);
+
+ str = alloca(len * sizeof(char));
+ if (str) {
+ if (msg&&val)
+ sprintf(str, "%s <%s: %s>", msg, type, val);
+ else if (msg)
+ sprintf(str, "%s <%s>", msg, type);
+ else if (val)
+ sprintf(str, "Python error %s: %s", type, val);
+ else
+ sprintf(str, "Python error %s", type);
+
+ pcilib_log_vmessage(file, line, flags, prio, str, va);
+ }
+ } else {
+ pcilib_log_vmessage(file, line, flags, prio, msg, va);
+ }
+ va_end(va);
+
+#ifdef HAVE_PYTHON
+ Py_XDECREF(pytype);
+ Py_XDECREF(pyval);
+ Py_XDECREF(pytraceback);
+#endif /* HAVE_PYTHON */
+}
+
+
int pcilib_init_py(pcilib_t *ctx) {
+#ifdef HAVE_PYTHON
ctx->py = (pcilib_py_t*)malloc(sizeof(pcilib_py_t));
if (!ctx->py) return PCILIB_ERROR_MEMORY;
- Py_Initialize();
+ memset(ctx->py, 0, sizeof(pcilib_py_t));
+ if(Py_IsInitialized())
+ ctx->py->finalyze = 1;
+ else {
+ Py_Initialize();
+
+ // Since python is being initializing from c programm, it needs to initialize threads to work properly with c threads
+ PyEval_InitThreads();
+ PyEval_ReleaseLock();
+ }
+
ctx->py->main_module = PyImport_AddModule("__parser__");
- if (!ctx->py->main_module)
+ if (!ctx->py->main_module) {
+ pcilib_python_error("Error importing python parser");
return PCILIB_ERROR_FAILED;
+ }
ctx->py->global_dict = PyModule_GetDict(ctx->py->main_module);
- if (!ctx->py->global_dict)
+ if (!ctx->py->global_dict) {
+ pcilib_python_error("Error locating global python dictionary");
+ return PCILIB_ERROR_FAILED;
+ }
+
+ PyObject *pywrap = PyImport_ImportModule("pcipywrap");
+ if (!pywrap) {
+ pcilib_python_error("Error importing pcilib python wrapper");
+ return PCILIB_ERROR_FAILED;
+ }
+
+ PyObject *mod_name = PyString_FromString("Pcipywrap");
+ ctx->py->pcilib_pywrap = PyObject_CallMethodObjArgs(pywrap, mod_name, PyCObject_FromVoidPtr(ctx, NULL), NULL);
+ Py_XDECREF(mod_name);
+
+ if (!ctx->py->pcilib_pywrap) {
+ pcilib_python_error("Error initializing python wrapper");
return PCILIB_ERROR_FAILED;
+ }
+#endif /* HAVE_PYTHON */
+
+ return 0;
+}
+
+int pcilib_py_add_script_dir(pcilib_t *ctx, const char *dir) {
+#ifdef HAVE_PYTHON
+ PyObject* pypath;
+ char *script_dir;
+
+ const char *model_dir = getenv("PCILIB_MODEL_DIR");
+ if (!model_dir) model_dir = PCILIB_MODEL_DIR;
+
+ if (!dir) dir = ctx->model;
+
+ if (*dir == '/') {
+ script_dir = (char*)dir;
+ } else {
+ script_dir = alloca(strlen(model_dir) + strlen(dir) + 2);
+ if (!script_dir) return PCILIB_ERROR_MEMORY;
+ sprintf(script_dir, "%s/%s", model_dir, dir);
+ }
+
+ pypath = PySys_GetObject("path");
+ if (!pypath) {
+ pcilib_python_error("Can't get python path");
+ return PCILIB_ERROR_FAILED;
+ }
+
+ // Shall we check if the directory already in the path?
+ if(PyList_Append(pypath, PyString_FromString(script_dir)) == -1) {
+ pcilib_python_error("Can't add directory (%s) to python path", script_dir);
+ return PCILIB_ERROR_FAILED;
+ }
+#endif /* HAVE_PYTHON */
return 0;
}
void pcilib_free_py(pcilib_t *ctx) {
- if (ctx->py) {
- // Dict and module references are borrowed
+#ifdef HAVE_PYTHON
+ int finalyze = 0;
+
+ if (ctx->py) {
+ if(ctx->py->finalyze) finalyze = 1;
+
+ if (ctx->py->script_hash) {
+ pcilib_script_t *script, *script_tmp;
+
+ HASH_ITER(hh, ctx->py->script_hash, script, script_tmp) {
+ HASH_DEL(ctx->py->script_hash, script);
+ free(script);
+ }
+ ctx->py->script_hash = NULL;
+ }
+
free(ctx->py);
ctx->py = NULL;
}
+
+ if (finalyze)
+ Py_Finalize();
+#endif /* HAVE_PYTHON */
+}
+
+int pcilib_py_load_script(pcilib_t *ctx, const char *script_name) {
+#ifdef HAVE_PYTHON
+ PyObject* pymodule;
+ pcilib_script_t *module = NULL;
+
+
+ char *module_name = strdupa(script_name);
+ if (!module_name) return PCILIB_ERROR_MEMORY;
+
+ char *py = strrchr(module_name, '.');
+ if ((!py)||(strcasecmp(py, ".py"))) {
+ pcilib_error("Invalid script name (%s) is specified", script_name);
+ return PCILIB_ERROR_INVALID_ARGUMENT;
+ }
+ *py = 0;
+
+ HASH_FIND_STR(ctx->py->script_hash, script_name, module);
+ if (module) return 0;
+
+ pymodule = PyImport_ImportModule(module_name);
+ if (!pymodule) {
+ pcilib_python_error("Error importing script (%s)", script_name);
+ return PCILIB_ERROR_FAILED;
+ }
+
+ module = (pcilib_script_t*)malloc(sizeof(pcilib_script_t));
+ if (!module) return PCILIB_ERROR_MEMORY;
- Py_Finalize();
+ module->module = pymodule;
+ module->name = script_name;
+ HASH_ADD_KEYPTR(hh, ctx->py->script_hash, module->name, strlen(module->name), module);
+#endif /* HAVE_PYTHON */
+ return 0;
}
-/*
-static int pcilib_py_realloc_string(pcilib_t *ctx, size_t required, size_t *size, char **str) {
- char *ptr;
- size_t cur = *size;
+int pcilib_py_get_transform_script_properties(pcilib_t *ctx, const char *script_name, pcilib_access_mode_t *mode_ret) {
+ pcilib_access_mode_t mode = 0;
+
+#ifdef HAVE_PYTHON
+ PyObject *dict;
+ PyObject *pystr;
+ pcilib_script_t *module;
+
+ HASH_FIND_STR(ctx->py->script_hash, script_name, module);
+
+ if(!module) {
+ pcilib_error("Script (%s) is not loaded yet", script_name);
+ return PCILIB_ERROR_NOTFOUND;
+ }
+
+ dict = PyModule_GetDict(module->module);
+ if (!dict) {
+ pcilib_python_error("Error getting dictionary for script (%s)", script_name);
+ return PCILIB_ERROR_FAILED;
+ }
- if ((required + 1) > cur) {
- while (cur < required) cur *= 2;
- ptr = (char*)realloc(*str, cur);
- if (!ptr) return PCILIB_ERROR_MEMORY;
- *size = cur;
- *str = ptr;
- }
- ]
+ pystr = PyString_FromString("read_from_register");
+ if (pystr) {
+ if (PyDict_Contains(dict, pystr)) mode |= PCILIB_ACCESS_R;
+ Py_XDECREF(pystr);
+ }
+
+ pystr = PyString_FromString("write_to_register");
+ if (pystr) {
+ if (PyDict_Contains(dict, pystr)) mode |= PCILIB_ACCESS_W;
+ Py_XDECREF(pystr);
+ }
+#endif /* HAVE_PYTHON */
+
+ if (mode_ret) *mode_ret = mode;
return 0;
}
-*/
+pcilib_py_object *pcilib_get_value_as_pyobject(pcilib_t* ctx, pcilib_value_t *val, int *ret) {
+#ifdef HAVE_PYTHON
+ int err = 0;
+ PyObject *res = NULL;
+
+ long ival;
+ double fval;
+
+ switch(val->type) {
+ case PCILIB_TYPE_LONG:
+ ival = pcilib_get_value_as_int(ctx, val, &err);
+ if (!err) res = (PyObject*)PyInt_FromLong(ival);
+ break;
+ case PCILIB_TYPE_DOUBLE:
+ fval = pcilib_get_value_as_float(ctx, val, &err);
+ if (!err) res = (PyObject*)PyFloat_FromDouble(fval);
+ break;
+ default:
+ err = PCILIB_ERROR_NOTSUPPORTED;
+ pcilib_error("Can't convert pcilib value of type (%lu) to PyObject", val->type);
+ }
+
+ if (err) {
+ if (ret) *ret = err;
+ return NULL;
+ } else if (!res) {
+ if (ret) *ret = PCILIB_ERROR_MEMORY;
+ return res;
+ }
+
+ if (ret) *ret = 0;
+ return res;
+#else /* HAVE_PYTHON */
+ pcilib_error("Python is not supported");
+ return NULL;
+#endif /* HAVE_PYTHON */
+}
+
+int pcilib_set_value_from_pyobject(pcilib_t* ctx, pcilib_value_t *val, pcilib_py_object *pval) {
+#ifdef HAVE_PYTHON
+ int err = 0;
+ PyObject *pyval = (PyObject*)pval;
+
+ if (PyInt_Check(pyval)) {
+ err = pcilib_set_value_from_int(ctx, val, PyInt_AsLong(pyval));
+ } else if (PyFloat_Check(pyval)) {
+ err = pcilib_set_value_from_float(ctx, val, PyFloat_AsDouble(pyval));
+ } else if (PyString_Check(pyval)) {
+ err = pcilib_set_value_from_string(ctx, val, PyString_AsString(pyval));
+ } else {
+ pcilib_error("Can't convert PyObject to polymorphic pcilib value");
+ err = PCILIB_ERROR_NOTSUPPORTED;
+ }
+
+ return err;
+#else /* HAVE_PYTHON */
+ pcilib_error("Python is not supported");
+ return PCILIB_ERROR_NOTSUPPORTED;
+#endif /* HAVE_PYTHON */
+}
+
+#ifdef HAVE_PYTHON
static char *pcilib_py_parse_string(pcilib_t *ctx, const char *codestr, pcilib_value_t *value) {
int i;
int err = 0;
@@ -166,8 +433,10 @@ static char *pcilib_py_parse_string(pcilib_t *ctx, const char *codestr, pcilib_v
return dst;
}
+#endif /* HAVE_PYTHON */
int pcilib_py_eval_string(pcilib_t *ctx, const char *codestr, pcilib_value_t *value) {
+#ifdef HAVE_PYTHON
PyGILState_STATE gstate;
char *code;
PyObject* obj;
@@ -189,4 +458,57 @@ int pcilib_py_eval_string(pcilib_t *ctx, const char *codestr, pcilib_value_t *va
pcilib_debug(VIEWS, "Evaluating a Python string \'%s\' to %lf=\'%s\'", codestr, PyFloat_AsDouble(obj), code);
return pcilib_set_value_from_float(ctx, value, PyFloat_AsDouble(obj));
+#else /* HAVE_PYTHON */
+ pcilib_error("Current build not support python.");
+ return PCILIB_ERROR_NOTAVAILABLE;
+#endif /* HAVE_PYTHON */
+}
+
+int pcilib_py_eval_func(pcilib_t *ctx, const char *script_name, const char *func_name, pcilib_value_t *val) {
+#ifdef HAVE_PYTHON
+ int err = 0;
+ PyObject *pyfunc;
+ PyObject *pyval = NULL, *pyret;
+ pcilib_script_t *module = NULL;
+
+ HASH_FIND_STR(ctx->py->script_hash, script_name, module);
+
+ if (!module) {
+ pcilib_error("Script (%s) is not loaded", script_name);
+ return PCILIB_ERROR_NOTFOUND;
+ }
+
+ if (val) {
+ pyval = pcilib_get_value_as_pyobject(ctx, val, &err);
+ if (err) return err;
+ }
+
+ pyfunc = PyUnicode_FromString(func_name);
+ if (!pyfunc) {
+ if (pyval) Py_XDECREF(pyval);
+ return PCILIB_ERROR_MEMORY;
+ }
+
+ PyGILState_STATE gstate = PyGILState_Ensure();
+ pyret = PyObject_CallMethodObjArgs(module->module, pyfunc, ctx->py->pcilib_pywrap, pyval, NULL);
+ PyGILState_Release(gstate);
+
+ Py_XDECREF(pyfunc);
+ Py_XDECREF(pyval);
+
+ if (!pyret) {
+ pcilib_python_error("Error executing function (%s) of python script (%s)", func_name, script_name);
+ return PCILIB_ERROR_FAILED;
+ }
+
+ if ((val)&&(pyret != Py_None))
+ err = pcilib_set_value_from_pyobject(ctx, val, pyret);
+
+ Py_XDECREF(pyret);
+
+ return err;
+#else /* HAVE_PYTHON */
+ pcilib_error("Python is not supported");
+ return PCILIB_ERROR_NOTSUPPORTED;
+#endif /* HAVE_PYTHON */
}
diff --git a/pcilib/py.h b/pcilib/py.h
index 21c31e9..c372a09 100644
--- a/pcilib/py.h
+++ b/pcilib/py.h
@@ -1,16 +1,123 @@
#ifndef _PCILIB_PY_H
#define _PCILIB_PY_H
+#include <pcilib.h>
+#include <pcilib/error.h>
+
+#define pcilib_python_error(...) pcilib_log_python_error(__FILE__, __LINE__, PCILIB_LOG_DEFAULT, PCILIB_LOG_ERROR, __VA_ARGS__)
+
typedef struct pcilib_py_s pcilib_py_t;
+typedef void pcilib_py_object;
#ifdef __cplusplus
extern "C" {
#endif
+void pcilib_log_python_error(const char *file, int line, pcilib_log_flags_t flags, pcilib_log_priority_t prio, const char *msg, ...);
+
+/** Initializes Python engine
+ *
+ * This function will return success if Python support is disabled. Only functions
+ * executing python call, like pcilib_py_eval_string(), return errors. Either way,
+ * no script directories are configured. The pcilib_add_script_dir() call is used
+ * for this purpose.
+ *
+ * @param[in,out] ctx - pcilib context
+ * @return - error or 0 on success
+ */
int pcilib_init_py(pcilib_t *ctx);
-int pcilib_py_eval_string(pcilib_t *ctx, const char *codestr, pcilib_value_t *value);
+
+/** Cleans up memory used by various python structures
+ * and finalyzes python environment if pcilib is not started from python script
+ *
+ * @param[in] ctx - the pcilib_t context
+ */
void pcilib_free_py(pcilib_t *ctx);
+/** Add an additional path to look for python scripts
+ *
+ * The default location for python files is /usr/local/share/pcilib/models/@b{model}.
+ * This can be altered using CMake PCILIB_MODEL_DIR variable while building or using
+ * PCILIB_MODEL_DIR environmental variable dynamicly. The default location is added
+ * with @b{location} = NULL. Additional directories can be added as well either
+ * by specifying relative path from the default directory or absolute path in the
+ * system.
+ *
+ * @param[in,out] ctx - pcilib context
+ * @param[in] location - NULL or path to additional scripts
+ * @return - error or 0 on success
+ */
+int pcilib_py_add_script_dir(pcilib_t *ctx, const char *location);
+
+/** Loads the specified python script
+ *
+ * Once loaded the script is available until pcilib context is destryoed.
+ *
+ * @param[in,out] ctx - pcilib context
+ * @param[in] name - script name, the passed variable is referenced and, hence, should have static duration
+ * @return - error or 0 on success
+ */
+int pcilib_py_load_script(pcilib_t *ctx, const char *name);
+
+/** Check if the specified script can be used as transform view and detects transform configuration
+ *
+ * @param[in,out] ctx - pcilib context
+ * @param[in] name - script name
+ * @param[out] mode - supported access mode (read/write/read-write)
+ * @return - error or 0 on success
+ */
+int pcilib_py_get_transform_script_properties(pcilib_t *ctx, const char *name, pcilib_access_mode_t *mode);
+
+/**
+ * Get the PyObject from the polymorphic type. The returned value should be cleaned with Py_XDECREF()
+ * @param[in] ctx - pcilib context
+ * @param[in] val - initialized polymorphic value of arbitrary type
+ * @param[out] err - error code or 0 on sccuess
+ * @return - valid PyObject or NULL in the case of error
+ */
+pcilib_py_object *pcilib_get_value_as_pyobject(pcilib_t* ctx, pcilib_value_t *val, int *err);
+
+/**
+ * Initializes the polymorphic value from PyObject. If `val` already contains the value, cleans it first.
+ * Therefore, before first usage the value should be always initialized to 0.
+ * @param[in] ctx - pcilib context
+ * @param[in,out] val - initialized polymorphic value
+ * @param[in] pyval - valid PyObject* containing PyInt, PyFloat, or PyString
+ * @return - 0 on success or memory error
+ */
+int pcilib_set_value_from_pyobject(pcilib_t* ctx, pcilib_value_t *val, pcilib_py_object *pyval);
+
+/** Evaluates the specified python code and returns result in @b{val}
+ *
+ * The python code may include special variables which will be substituted by pcitool before executing Python interpreter
+ * @b{$value} - will be replaced by the current value of the @b{val} parameter
+ * @b{$reg} - will be replaced by the current value of the specified register @b{reg}
+ * @b{${/prop/temp}} - will be replaced by the current value of the specified property @b{/prop/temp}
+ * @b{${/prop/temp:C}} - will be replaced by the current value of the specified property @b{/prop/temp} in the given units
+
+ * @param[in,out] ctx - pcilib context
+ * @param[in] codestr - python code to evaluate
+ * @param[in,out] val - Should contain the value which will be substituted in place of @b{$value} and on
+ * successful execution will contain the computed value
+ * @return - error or 0 on success
+ */
+int pcilib_py_eval_string(pcilib_t *ctx, const char *codestr, pcilib_value_t *val);
+
+/** Execute the specified function in the Python script which was loaded with pcilib_py_load_script() call
+ *
+ * The function is expected to accept two paramters. The first parameter is pcipywrap context and the @b{val}
+ * is passed as the second parameter. The return value of the script will be returned in the @b{val} as well.
+ * If function returns Py_None, the value of @b{val} will be unchanged.
+ *
+ * @param[in,out] ctx - pcilib context
+ * @param[in] script - script name
+ * @param[in] func - function name
+ * @param[in,out] val - Should contain the value of second parameter of the function before call and on
+ * successful return will contain the returned value
+ * @return - error or 0 on success
+ */
+int pcilib_py_eval_func(pcilib_t *ctx, const char *script, const char *func, pcilib_value_t *val);
+
#ifdef __cplusplus
}
#endif
diff --git a/pcilib/value.c b/pcilib/value.c
index 6e65307..e8268e9 100644
--- a/pcilib/value.c
+++ b/pcilib/value.c
@@ -1,3 +1,4 @@
+#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -71,6 +72,27 @@ int pcilib_set_value_from_static_string(pcilib_t *ctx, pcilib_value_t *value, co
return 0;
}
+int pcilib_set_value_from_string(pcilib_t *ctx, pcilib_value_t *value, const char *str) {
+ size_t len;
+
+ pcilib_clean_value(ctx, value);
+
+ len = strlen(str) + 1;
+ if (len < sizeof(value->str)) {
+ memcpy(value->str, str, len);
+ value->sval = value->str;
+ } else {
+ value->data = (void*)strdup(str);
+ if (!value->data) return PCILIB_ERROR_MEMORY;
+
+ value->size = strlen(str) + 1;
+ value->sval = value->data;
+ }
+ value->type = PCILIB_TYPE_STRING;
+
+ return 0;
+}
+
double pcilib_get_value_as_float(pcilib_t *ctx, const pcilib_value_t *val, int *ret) {
int err;
double res;
diff --git a/pcilib/view.c b/pcilib/view.c
index e31fdba..985c1b2 100644
--- a/pcilib/view.c
+++ b/pcilib/view.c
@@ -69,8 +69,11 @@ int pcilib_add_views_custom(pcilib_t *ctx, size_t n, const pcilib_view_descripti
return PCILIB_ERROR_MEMORY;
}
+ memcpy(cur, v, v->api->description_size);
+ ctx->views[ctx->num_views + i] = cur;
+
if (v->api->init)
- view_ctx = v->api->init(ctx);
+ view_ctx = v->api->init(ctx, ctx->num_views + i);
else {
view_ctx = (pcilib_view_context_t*)malloc(sizeof(pcilib_view_context_t));
if (view_ctx) memset(view_ctx, 0, sizeof(pcilib_view_context_t));
@@ -83,14 +86,12 @@ int pcilib_add_views_custom(pcilib_t *ctx, size_t n, const pcilib_view_descripti
return PCILIB_ERROR_FAILED;
}
- memcpy(cur, v, v->api->description_size);
- view_ctx->view = ctx->num_views + i;
+ view_ctx->view = ctx->num_views + i;
view_ctx->name = v->name;
- if (refs) refs[i] = view_ctx;
-
HASH_ADD_KEYPTR(hh, ctx->view_hash, view_ctx->name, strlen(view_ctx->name), view_ctx);
- ctx->views[ctx->num_views + i] = cur;
+
+ if (refs) refs[i] = view_ctx;
ptr += v->api->description_size;
}
diff --git a/pcilib/view.h b/pcilib/view.h
index 33d4d96..8b1c07c 100644
--- a/pcilib/view.h
+++ b/pcilib/view.h
@@ -19,7 +19,7 @@ typedef enum {
typedef struct {
pcilib_version_t version; /**< Version */
size_t description_size; /**< The actual size of the description */
- pcilib_view_context_t *(*init)(pcilib_t *ctx); /**< Optional function which should allocated context used by read/write functions */
+ pcilib_view_context_t *(*init)(pcilib_t *ctx, pcilib_view_t view); /**< Optional function which should allocated context used by read/write functions */
void (*free)(pcilib_t *ctx, pcilib_view_context_t *view); /**< Optional function which should clean context */
void (*free_description)(pcilib_t *ctx, pcilib_view_description_t *view); /**< Optional function which shoud clean required parts of the extended description if non-static memory was used to initialize it */
int (*read_from_reg)(pcilib_t *ctx, pcilib_view_context_t *view, pcilib_register_value_t regval, pcilib_value_t *val); /**< Function which computes view value based on the passed the register value (view-based properties should not use register value) */
diff --git a/pcilib/xml.c b/pcilib/xml.c
index 50aaa35..fd12636 100644
--- a/pcilib/xml.c
+++ b/pcilib/xml.c
@@ -40,6 +40,7 @@
#include "xml.h"
#include "error.h"
#include "view.h"
+#include "py.h"
#include "views/enum.h"
#include "views/transform.h"
@@ -48,11 +49,11 @@
#define REGISTERS_PATH ((xmlChar*)"./register") /**< all standard registers nodes */
#define BIT_REGISTERS_PATH ((xmlChar*)"./field") /**< all bits registers nodes */
#define REGISTER_VIEWS_PATH ((xmlChar*)"./view") /**< supported register & field views */
-#define TRANSFORM_VIEWS_PATH ((xmlChar*)"/model/transform") /**< path to complete nodes of views */
+#define TRANSFORM_VIEWS_PATH ((xmlChar*)"/model/transform") /**< path to complete nodes of views */
#define ENUM_VIEWS_PATH ((xmlChar*)"/model/enum") /**< path to complete nodes of views */
#define ENUM_ELEMENTS_PATH ((xmlChar*)"./name") /**< all elements in the enum */
#define UNITS_PATH ((xmlChar*)"/model/unit") /**< path to complete nodes of units */
-#define UNIT_TRANSFORMS_PATH ((xmlChar*)"./transform") /**< all transforms of the unit */
+#define UNIT_TRANSFORMS_PATH ((xmlChar*)"./transform") /**< all transforms of the unit */
@@ -492,6 +493,8 @@ static int pcilib_xml_parse_view(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDoc
xmlAttrPtr cur;
const char *value, *name;
+ int inconsistent = (desc->mode & PCILIB_ACCESS_INCONSISTENT);
+
for (cur = node->properties; cur != NULL; cur = cur->next) {
if (!cur->children) continue;
if (!xmlNodeIsText(cur->children)) continue;
@@ -537,8 +540,14 @@ static int pcilib_xml_parse_view(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDoc
pcilib_error("Invalid access mode (%s) is specified in the XML register description", value);
return PCILIB_ERROR_INVALID_DATA;
}
- }
+ } else if (!strcasecmp(name, "write_verification")) {
+ if (strcmp(value, "0")) inconsistent = 0;
+ else inconsistent = 1;
+ }
}
+
+ if (inconsistent) desc->mode |= PCILIB_ACCESS_INCONSISTENT;
+ else desc->mode &= ~PCILIB_ACCESS_INCONSISTENT;
return 0;
}
@@ -585,10 +594,12 @@ static int pcilib_xml_create_transform_view(pcilib_t *ctx, xmlXPathContextPtr xp
}
desc.write_to_reg = value;
if ((value)&&(*value)) mode |= PCILIB_ACCESS_W;
- }
+ } else if (!strcasecmp(name, "script")) {
+ desc.script = value;
+ break;
+ }
}
-
- desc.base.mode &= mode;
+ desc.base.mode &= (~PCILIB_ACCESS_RW)|mode;
err = pcilib_add_views_custom(ctx, 1, (pcilib_view_description_t*)&desc, &view_ctx);
if (err) return err;
@@ -597,7 +608,6 @@ static int pcilib_xml_create_transform_view(pcilib_t *ctx, xmlXPathContextPtr xp
return 0;
}
-
static int pcilib_xml_parse_value_name(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node, pcilib_register_value_name_t *desc) {
xmlAttr *cur;
char *value, *name;
diff --git a/pcitool/cli.c b/pcitool/cli.c
index bb3d9b8..3f1af74 100644
--- a/pcitool/cli.c
+++ b/pcitool/cli.c
@@ -1702,7 +1702,7 @@ int WriteRegister(pcilib_t *handle, const pcilib_model_description_t *model_info
err = pcilib_write_register(handle, bank, reg, value);
if (err) Error("Error writting register %s\n", reg);
- if ((model_info->registers[regid].mode&PCILIB_REGISTER_RW) == PCILIB_REGISTER_RW) {
+ if ((model_info->registers[regid].mode&(PCILIB_REGISTER_RW|PCILIB_REGISTER_INCONSISTENT)) == PCILIB_REGISTER_RW) {
const char *format = (val.format?val.format:"%u");
err = pcilib_read_register(handle, bank, reg, &verify);
diff --git a/pywrap/CMakeLists.txt b/pywrap/CMakeLists.txt
new file mode 100644
index 0000000..1693232
--- /dev/null
+++ b/pywrap/CMakeLists.txt
@@ -0,0 +1,22 @@
+include_directories(
+ ${CMAKE_SOURCE_DIR}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_SOURCE_DIR}/pcilib
+ ${CMAKE_BINARY_DIR}/pcilib
+ ${LIBXML2_INCLUDE_DIRS}
+ ${PYTHON_INCLUDE_DIR}
+ ${UTHASH_INCLUDE_DIRS}
+)
+
+set(HEADERS pcipywrap.h)
+
+#Creating python wrapping
+include(${SWIG_USE_FILE})
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+set(CMAKE_SWIG_FLAGS "")
+
+swig_add_module(pcipywrap python pcipywrap.i pcipywrap.c)
+swig_link_libraries(pcipywrap ${PYTHON_LIBRARIES} pcilib)
+
+#configure_file(server.py server.py)
+#configure_file(test_pcipywrap.py test_pcipywrap.py)
diff --git a/pywrap/pcipywrap.c b/pywrap/pcipywrap.c
new file mode 100644
index 0000000..bcf4561
--- /dev/null
+++ b/pywrap/pcipywrap.c
@@ -0,0 +1,503 @@
+#include "pcipywrap.h"
+
+char* full_log = NULL;
+
+/*!
+ * \brief Wraping for vsnprintf function, that saves string to char*
+ * \return saved from vsnprintf string
+ */
+char* vmake_str(const char* msg, va_list vl)
+{
+ char *buf;
+ size_t sz;
+
+ va_list vl_copy;
+ va_copy(vl_copy, vl);
+
+ sz = vsnprintf(NULL, 0, msg, vl);
+ buf = (char *)malloc(sz + 1);
+
+ if(!buf)
+ {
+ return NULL;
+ }
+
+ vsnprintf(buf, sz+1, msg, vl_copy);
+ va_end(vl_copy);
+
+ return buf;
+}
+
+
+/*!
+ * \brief Wraping for vsnprintf function, that saves string to char*
+ * \return saved from vsnprintf string
+ */
+char* make_str(const char* msg, ...)
+{
+ va_list vl;
+ va_start(vl, msg);
+ char *buf = vmake_str(msg, vl);
+ va_end(vl);
+ return buf;
+}
+
+/*!
+ * \brief Version of pcilib_logger_t, that saves error text to Python exeption
+ */
+void pcilib_print_error_to_py(void *arg, const char *file, int line,
+ pcilib_log_priority_t prio, const char *msg,
+ va_list va) {
+ //wrap error message with file and line number
+ char* buf_raw_msg = vmake_str(msg, va);
+ char* buf_wrapped_message = make_str("%s [%s:%d]\n", buf_raw_msg, file, line);
+
+ if(prio == PCILIB_LOG_ERROR)
+ {
+ if(!full_log)
+ full_log = make_str("");
+
+ //copy received message to log
+ char* buf = full_log;
+ full_log = make_str("%s%s", buf, buf_wrapped_message);
+ free(buf);
+ }
+ else
+ printf("%s", buf_wrapped_message);
+
+ free(buf_wrapped_message);
+ free(buf_raw_msg);
+}
+
+void set_python_exception(const char* msg, ...)
+{
+ va_list vl;
+ va_start(vl, msg);
+ char *buf = vmake_str(msg, vl);
+
+ char* wrapped_exeption;
+ if(full_log)
+ wrapped_exeption = make_str("%s\nprogramm error log:\n%s", buf, full_log);
+ else
+ wrapped_exeption = buf;
+
+ free(full_log);
+ full_log = NULL;
+
+ PyErr_SetString(PyExc_Exception, wrapped_exeption);
+
+ free(buf);
+ if(full_log)
+ free(wrapped_exeption);
+ va_end(vl);
+}
+
+
+void __redirect_logs_to_exeption()
+{
+ pcilib_set_logger(pcilib_get_log_level(),
+ pcilib_print_error_to_py,
+ pcilib_get_logger_context());
+}
+
+/*!
+ * \brief Wrap for PyDict_SetItem, with decrease reference counting after set.
+ */
+void pcilib_pydict_set_item(PyObject* dict, PyObject* name, PyObject* value)
+{
+ PyDict_SetItem(dict,
+ name,
+ value);
+ Py_XDECREF(name);
+ Py_XDECREF(value);
+}
+
+/*!
+ * \brief Wrap for PyList_Append, with decrease reference counting after append.
+ */
+void pcilib_pylist_append(PyObject* list, PyObject* value)
+{
+ PyList_Append(list, value);
+ Py_XDECREF(value);
+}
+
+void add_pcilib_value_to_dict(pcilib_t* ctx, PyObject* dict, pcilib_value_t* val, const char *name)
+{
+ PyObject *py_val = (PyObject*)pcilib_get_value_as_pyobject(ctx, val, NULL);
+
+ if(py_val)
+ pcilib_pydict_set_item(dict,
+ PyString_FromString(name),
+ py_val);
+ else
+ pcilib_pydict_set_item(dict,
+ PyString_FromString("defvalue"),
+ PyString_FromString("invalid"));
+}
+
+PyObject * pcilib_convert_property_info_to_pyobject(pcilib_t* ctx, pcilib_property_info_t listItem)
+{
+ PyObject* pylistItem = PyDict_New();
+
+ if(listItem.name)
+ pcilib_pydict_set_item(pylistItem,
+ PyString_FromString("name"),
+ PyString_FromString(listItem.name));
+
+ if(listItem.description)
+ pcilib_pydict_set_item(pylistItem,
+ PyString_FromString("description"),
+ PyString_FromString(listItem.description));
+
+ if(listItem.path)
+ pcilib_pydict_set_item(pylistItem,
+ PyString_FromString("path"),
+ PyString_FromString(listItem.path));
+
+ //serialize types
+ const char* type = "invalid";
+ switch(listItem.type)
+ {
+ case PCILIB_TYPE_INVALID:
+ type = "invalid";
+ break;
+ case PCILIB_TYPE_STRING:
+ type = "string";
+ break;
+ case PCILIB_TYPE_DOUBLE:
+ type = "double";
+ break;
+ case PCILIB_TYPE_LONG :
+ type = "long";
+ break;
+ default:
+ break;
+ }
+ pcilib_pydict_set_item(pylistItem,
+ PyString_FromString("type"),
+ PyString_FromString(type));
+
+
+ //serialize modes
+ PyObject* modes = PyList_New(0);
+
+ if((listItem.mode & PCILIB_ACCESS_R ) == PCILIB_REGISTER_R)
+ pcilib_pylist_append(modes, PyString_FromString("R"));
+ if((listItem.mode & PCILIB_ACCESS_W ) == PCILIB_REGISTER_W)
+ pcilib_pylist_append(modes, PyString_FromString("W"));
+ if((listItem.mode & PCILIB_ACCESS_RW ) == PCILIB_REGISTER_RW)
+ pcilib_pylist_append(modes, PyString_FromString("RW"));
+ if((listItem.mode & PCILIB_REGISTER_INCONSISTENT) == PCILIB_REGISTER_INCONSISTENT)
+ pcilib_pylist_append(modes, PyString_FromString("NO_CHK"));
+
+ pcilib_pydict_set_item(pylistItem,
+ PyString_FromString("mode"),
+ modes);
+
+ //serialize flags
+ PyObject* flags = PyList_New(0);
+
+ if((listItem.flags & PCILIB_LIST_FLAG_CHILDS ) == PCILIB_LIST_FLAG_CHILDS)
+ pcilib_pylist_append(flags, PyString_FromString("childs"));
+
+ pcilib_pydict_set_item(pylistItem,
+ PyString_FromString("flags"),
+ flags);
+
+ if(listItem.unit)
+ pcilib_pydict_set_item(pylistItem,
+ PyString_FromString("unit"),
+ PyString_FromString(listItem.unit));
+
+ return pylistItem;
+}
+
+PyObject * pcilib_convert_register_info_to_pyobject(pcilib_t* ctx, pcilib_register_info_t listItem)
+{
+ PyObject* pylistItem = PyDict_New();
+
+ if(listItem.name)
+ pcilib_pydict_set_item(pylistItem,
+ PyString_FromString("name"),
+ PyString_FromString(listItem.name));
+
+ if(listItem.description)
+ pcilib_pydict_set_item(pylistItem,
+ PyString_FromString("description"),
+ PyString_FromString(listItem.description));
+
+ if(listItem.bank)
+ pcilib_pydict_set_item(pylistItem,
+ PyString_FromString("bank"),
+ PyString_FromString(listItem.bank));
+
+ //serialize modes
+ PyObject* modes = PyList_New(0);
+
+ if((listItem.mode & PCILIB_REGISTER_R) == PCILIB_REGISTER_R)
+ pcilib_pylist_append(modes, PyString_FromString("R"));
+ if((listItem.mode & PCILIB_REGISTER_W) == PCILIB_REGISTER_W)
+ pcilib_pylist_append(modes, PyString_FromString("W"));
+ if((listItem.mode & PCILIB_REGISTER_RW) == PCILIB_REGISTER_RW)
+ pcilib_pylist_append(modes, PyString_FromString("RW"));
+ if((listItem.mode & PCILIB_REGISTER_W1C) == PCILIB_REGISTER_W1C)
+ pcilib_pylist_append(modes, PyString_FromString("W1C"));
+ if((listItem.mode & PCILIB_REGISTER_RW1C) == PCILIB_REGISTER_RW1C)
+ pcilib_pylist_append(modes, PyString_FromString("RW1C"));
+ if((listItem.mode & PCILIB_REGISTER_W1I) == PCILIB_REGISTER_W1I)
+ pcilib_pylist_append(modes, PyString_FromString("W1I"));
+ if((listItem.mode & PCILIB_REGISTER_RW1I) == PCILIB_REGISTER_RW1I)
+ pcilib_pylist_append(modes, PyString_FromString("RW1I"));
+ if((listItem.mode & PCILIB_REGISTER_INCONSISTENT) == PCILIB_REGISTER_INCONSISTENT)
+ pcilib_pylist_append(modes, PyString_FromString("NO_CHK"));
+
+ pcilib_pydict_set_item(pylistItem,
+ PyString_FromString("mode"),
+ modes);
+
+ pcilib_value_t defval = {0};
+ pcilib_set_value_from_register_value(ctx, &defval, listItem.defvalue);
+ add_pcilib_value_to_dict(ctx, pylistItem, &defval, "defvalue");
+
+ if(listItem.range)
+ {
+ pcilib_value_t minval = {0};
+ pcilib_set_value_from_register_value(ctx, &minval, listItem.range->min);
+
+ pcilib_value_t maxval = {0};
+ pcilib_set_value_from_register_value(ctx, &maxval, listItem.range->max);
+
+ PyObject* range = PyDict_New();
+ add_pcilib_value_to_dict(ctx, range, &minval, "min");
+ add_pcilib_value_to_dict(ctx, range, &maxval, "max");
+ pcilib_pydict_set_item(pylistItem,
+ PyString_FromString("range"),
+ range);
+ }
+
+ if(listItem.values)
+ {
+ PyObject* values = PyList_New(0);
+
+ for (int j = 0; listItem.values[j].name; j++)
+ {
+ PyObject* valuesItem = PyDict_New();
+
+ pcilib_value_t val = {0};
+ pcilib_set_value_from_register_value(ctx, &val, listItem.values[j].value);
+
+ pcilib_value_t min = {0};
+ pcilib_set_value_from_register_value(ctx, &min, listItem.values[j].min);
+
+ pcilib_value_t max = {0};
+ pcilib_set_value_from_register_value(ctx, &max, listItem.values[j].max);
+
+ add_pcilib_value_to_dict(ctx, valuesItem, &val, "value");
+ add_pcilib_value_to_dict(ctx, valuesItem, &min, "min");
+ add_pcilib_value_to_dict(ctx, valuesItem, &max, "max");
+
+ if(listItem.values[j].name)
+ pcilib_pydict_set_item(valuesItem,
+ PyString_FromString("name"),
+ PyString_FromString(listItem.values[j].name));
+
+ if(listItem.values[j].description)
+ pcilib_pydict_set_item(valuesItem,
+ PyString_FromString("name"),
+ PyString_FromString(listItem.values[j].description));
+
+ pcilib_pylist_append(values, valuesItem);
+ }
+
+ pcilib_pydict_set_item(pylistItem,
+ PyString_FromString("values"),
+ values);
+ }
+
+ return pylistItem;
+}
+
+Pcipywrap *new_Pcipywrap(const char* fpga_device, const char* model)
+{
+ //opening device
+ pcilib_t* ctx = pcilib_open(fpga_device, model);
+ if(!ctx)
+ {
+ set_python_exception("Failed pcilib_open(%s, %s)", fpga_device, model);
+ return NULL;
+ }
+ Pcipywrap *self;
+ self = (Pcipywrap *) malloc(sizeof(Pcipywrap));
+ self->shared = 0;
+ self->ctx = ctx;
+ return self;
+}
+
+Pcipywrap *create_Pcipywrap(PyObject* ctx)
+{
+ if(!PyCObject_Check(ctx))
+ {
+ set_python_exception("Incorrect ctx type. Only PyCObject is allowed");
+ return NULL;
+ }
+
+ Pcipywrap *self;
+ self = (Pcipywrap *) malloc(sizeof(Pcipywrap));
+ self->shared = 1;
+ self->ctx = PyCObject_AsVoidPtr(ctx);
+ return self;
+}
+
+void delete_Pcipywrap(Pcipywrap *self) {
+ if(!self->shared)
+ pcilib_close(self->ctx);
+
+ free(self);
+}
+
+PyObject* Pcipywrap_read_register(Pcipywrap *self, const char *regname, const char *bank)
+{
+ pcilib_value_t val = {0};
+ pcilib_register_value_t reg_value;
+
+ int err;
+
+ err = pcilib_read_register(self->ctx, bank, regname, &reg_value);
+ if(err)
+ {
+ set_python_exception("Failed pcilib_read_register");
+ return NULL;
+ }
+
+ err = pcilib_set_value_from_register_value(self->ctx, &val, reg_value);
+ if(err)
+ {
+ set_python_exception("Failed pcilib_set_value_from_register_value");
+ return NULL;
+ }
+
+ return pcilib_get_value_as_pyobject(self->ctx, &val, NULL);
+}
+
+PyObject* Pcipywrap_write_register(Pcipywrap *self, PyObject* val, const char *regname, const char *bank)
+{
+ pcilib_value_t val_internal = {0};
+ pcilib_register_value_t reg_value;
+
+ int err;
+
+ err = pcilib_set_value_from_pyobject(self->ctx, &val_internal, val);
+
+ if(err)
+ {
+ set_python_exception("Failed pcilib_set_value_from_pyobject");
+ return NULL;
+ }
+
+
+ reg_value = pcilib_get_value_as_register_value(self->ctx, &val_internal, &err);
+ if(err)
+ {
+ set_python_exception("Failed pcilib_set_value_from_pyobject, (error %i)", err);
+ return NULL;
+ }
+
+ err = pcilib_write_register(self->ctx, bank, regname, reg_value);
+
+ if(err)
+ {
+ set_python_exception("Failed pcilib_set_value_from_pyobject, (error %i)", err);
+ return NULL;
+ }
+
+ return PyInt_FromLong((long)1);
+}
+
+PyObject* Pcipywrap_get_property(Pcipywrap *self, const char *prop)
+{
+ int err;
+ pcilib_value_t val = {0};
+
+ err = pcilib_get_property(self->ctx, prop, &val);
+
+ if(err)
+ {
+ set_python_exception("Failed pcilib_get_property, (error %i)", err);
+ return NULL;
+ }
+
+ return pcilib_get_value_as_pyobject(self->ctx, &val, NULL);
+}
+
+PyObject* Pcipywrap_set_property(Pcipywrap *self, PyObject* val, const char *prop)
+{
+ int err;
+
+ pcilib_value_t val_internal = {0};
+ err = pcilib_set_value_from_pyobject(self->ctx, &val_internal, val);
+ if(err)
+ {
+ set_python_exception("pcilib_set_value_from_pyobject, (error %i)", err);
+ return NULL;
+ }
+
+ err = pcilib_set_property(self->ctx, prop, &val_internal);
+ if(err)
+ {
+ set_python_exception("pcilib_set_property, (error %i)", err);
+ return NULL;
+ }
+
+ return PyInt_FromLong((long)1);
+}
+
+PyObject* Pcipywrap_get_registers_list(Pcipywrap *self, const char *bank)
+{
+ pcilib_register_info_t *list = pcilib_get_register_list(self->ctx, bank, PCILIB_LIST_FLAGS_DEFAULT);
+
+ PyObject* pyList = PyList_New(0);
+ for(int i = 0; i < ((pcilib_t*)self->ctx)->num_reg; i++)
+ {
+ //serialize item attributes
+ PyObject* pylistItem = pcilib_convert_register_info_to_pyobject(self->ctx, list[i]);
+ pcilib_pylist_append(pyList, pylistItem);
+ }
+
+ pcilib_free_register_info(self->ctx, list);
+
+ return pyList;
+}
+
+PyObject* Pcipywrap_get_register_info(Pcipywrap *self, const char* reg,const char *bank)
+{
+ pcilib_register_info_t *info = pcilib_get_register_info(self->ctx, bank, reg, PCILIB_LIST_FLAGS_DEFAULT);
+
+ if(!info)
+ {
+ return NULL;
+ }
+
+ PyObject* py_info = pcilib_convert_register_info_to_pyobject(self->ctx, info[0]);
+
+ pcilib_free_register_info(self->ctx, info);
+
+ return py_info;
+}
+
+PyObject* Pcipywrap_get_property_list(Pcipywrap *self, const char* branch)
+{
+ pcilib_property_info_t *list = pcilib_get_property_list(self->ctx, branch, PCILIB_LIST_FLAGS_DEFAULT);
+
+ PyObject* pyList = PyList_New(0);
+
+ for(int i = 0; list[i].path; i++)
+ {
+ //serialize item attributes
+ PyObject* pylistItem = pcilib_convert_property_info_to_pyobject(self->ctx, list[i]);
+ pcilib_pylist_append(pyList, pylistItem);
+ }
+
+ pcilib_free_property_info(self->ctx, list);
+
+ return pyList;
+}
diff --git a/pywrap/pcipywrap.h b/pywrap/pcipywrap.h
new file mode 100644
index 0000000..99cebd7
--- /dev/null
+++ b/pywrap/pcipywrap.h
@@ -0,0 +1,68 @@
+#ifndef PCIPYWRAP_H
+#define PCIPYWRAP_H
+
+#include "pci.h"
+#include "error.h"
+#include <Python.h>
+
+typedef struct {
+ void* ctx;
+ int shared;
+} Pcipywrap;
+
+/*!
+ * \brief Redirect pcilib standart log stream to exeption text.
+ * Logger will accumulate errors untill get message, starts with "#E".
+ * After that, logger will write last error, and all accumulated errors
+ * to Python exeption text
+ */
+void __redirect_logs_to_exeption();
+
+/*!
+ * \brief Wraps for pcilib_open function.
+ * \param[in] fpga_device path to the device file [/dev/fpga0]
+ * \param[in] model specifies the model of hardware, autodetected if NULL is passed
+ * \return Pointer to pcilib_t, created by pcilib_open; NULL with exeption text, if failed.
+ */
+PyObject* create_pcilib_instance(const char *fpga_device, const char *model);
+
+Pcipywrap *new_Pcipywrap(const char* fpga_device, const char* model);
+Pcipywrap *create_Pcipywrap(PyObject* ctx);
+void delete_Pcipywrap(Pcipywrap *self);
+
+/*!
+ * \brief Reads register value. Wrap for pcilib_read_register function.
+ * \param[in] regname the name of the register
+ * \param[in] bank should specify the bank name if register with the same name may occur in multiple banks, NULL otherwise
+ * \return register value, can be integer or float type; NULL with exeption text, if failed.
+ */
+PyObject* Pcipywrap_read_register(Pcipywrap *self, const char *regname, const char *bank);
+
+/*!
+ * \brief Writes value to register. Wrap for pcilib_write_register function.
+ * \param[in] val Register value, that needs to be set. Can be int, float or string.
+ * \param[in] regname the name of the register
+ * \param[in] bank should specify the bank name if register with the same name may occur in multiple banks, NULL otherwise
+ * \return 1, serialized to PyObject or NULL with exeption text, if failed.
+ */
+PyObject* Pcipywrap_write_register(Pcipywrap *self, PyObject* val, const char *regname, const char *bank);
+
+/*!
+ * \brief Reads propety value. Wrap for pcilib_get_property function.
+ * \param[in] prop property name (full name including path)
+ * \return property value, can be integer or float type; NULL with exeption text, if failed.
+ */
+PyObject* Pcipywrap_get_property(Pcipywrap *self, const char *prop);
+
+/*!
+ * \brief Writes value to property. Wrap for pcilib_set_property function.
+ * \param[in] prop property name (full name including path)
+ * \param[in] val Property value, that needs to be set. Can be int, float or string.
+ * \return 1, serialized to PyObject or NULL with exeption text, if failed.
+ */
+PyObject* Pcipywrap_set_property(Pcipywrap *self, PyObject* val, const char *prop);
+PyObject* Pcipywrap_get_registers_list(Pcipywrap *self, const char *bank);
+PyObject* Pcipywrap_get_register_info(Pcipywrap *self, const char* reg,const char *bank);
+PyObject* Pcipywrap_get_property_list(Pcipywrap *self, const char* branch);
+
+#endif /* PCIPYWRAP_H */
diff --git a/pywrap/pcipywrap.i b/pywrap/pcipywrap.i
new file mode 100644
index 0000000..88a746f
--- /dev/null
+++ b/pywrap/pcipywrap.i
@@ -0,0 +1,25 @@
+%module pcipywrap
+
+%{
+#include "pcipywrap.h"
+%}
+
+extern void __redirect_logs_to_exeption();
+
+typedef struct {
+ %extend {
+ Pcipywrap(const char* fpga_device = NULL, const char* model = NULL);
+ Pcipywrap(PyObject* ctx){return create_Pcipywrap(ctx);}
+ ~Pcipywrap();
+
+ PyObject* read_register(const char *regname = NULL, const char *bank = NULL);
+ PyObject* write_register(PyObject* val, const char *regname, const char *bank = NULL);
+
+ PyObject* get_property(const char *prop);
+ PyObject* set_property(PyObject* val, const char *prop);
+
+ PyObject* get_registers_list(const char *bank = NULL);
+ PyObject* get_register_info(const char* reg,const char *bank = NULL);
+ PyObject* get_property_list(const char* branch = NULL);
+ }
+} Pcipywrap;
diff --git a/pywrap/server.py b/pywrap/server.py
new file mode 100644
index 0000000..03302a2
--- /dev/null
+++ b/pywrap/server.py
@@ -0,0 +1,399 @@
+import time
+import os
+import pcipywrap
+import json
+import BaseHTTPServer
+import sys
+from optparse import OptionParser
+
+class PcilibServerHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+ def __init__(s, pcilib, *args):
+ s.pcilib = pcilib
+ BaseHTTPServer.BaseHTTPRequestHandler.__init__(s, *args)
+
+ def do_HEAD(s):
+ s.send_response(200)
+ s.send_header('content-type', 'application/json')
+ s.end_headers()
+
+ def do_GET(s):
+ length = int(s.headers['Content-Length'])
+
+ #deserialize input data
+ data = json.loads(s.rfile.read(length).decode('utf-8'))
+
+ if 'command' in data:
+ command = data['command']
+ if(command == 'help'):
+ s.help(data)
+
+ #elif(command == 'open'):
+ # #check required arguments
+ # if not 'device' in data:
+ # s.error('message doesnt contains "device" field, '
+ # 'which is required for "open" command', data)
+ # return
+ # #parse command arguments and convert them to string
+ # device = str(data.get('device', None))
+ # model = data.get('model', None)
+ # if not model is None:
+ # model = str(model)
+ #
+ # try:
+ # s.openPcilibInstance(device, model)
+ # except Exception as e:
+ # s.error(str(e), data)
+ # return
+ #
+ # #Success! Create and send reply
+ # s.send_response(200)
+ # s.send_header('content-type', 'application/json')
+ # s.end_headers()
+ # out = dict()
+ # out['status'] = 'ok'
+ # s.wrapMessageAndSend(out, data)
+
+ elif(command == 'get_registers_list'):
+ #parse command arguments and convert them to string
+ bank = data.get('bank', None)
+ if not bank is None:
+ bank = str(bank)
+
+ registers = dict()
+ try:
+ registers = s.pcilib.get_registers_list(bank)
+ except Exception as e:
+ s.error(str(e), data)
+ return
+
+ #Success! Create and send reply
+ s.send_response(200)
+ s.send_header('content-type', 'application/json')
+ s.end_headers()
+ out = dict()
+ out['status'] = 'ok'
+ out['registers'] = registers
+ s.wrapMessageAndSend(out, data)
+
+ elif(command == 'get_register_info'):
+ #check required arguments
+ if not 'reg' in data:
+ s.error('message doesnt contains "reg" field, '
+ 'which is required for "get_register_info" command', data)
+ return
+
+ #parse command arguments and convert them to string
+ reg = str(data.get('reg', None))
+ bank = data.get('bank', None)
+ if not bank is None:
+ bank = str(bank)
+
+ register = dict()
+ try:
+ register = s.pcilib.get_register_info(reg, bank)
+ except Exception as e:
+ s.error(str(e), data)
+ return
+
+ #Success! Create and send reply
+ s.send_response(200)
+ s.send_header('content-type', 'application/json')
+ s.end_headers()
+ out = dict()
+ out['status'] = 'ok'
+ out['register'] = register
+ s.wrapMessageAndSend(out, data)
+
+ elif(command == 'get_property_list'):
+ #parse command arguments and convert them to string
+ branch = data.get('branch', None)
+ if not branch is None:
+ branch = str(branch)
+
+ properties = dict()
+ try:
+ properties = s.pcilib.get_property_list(branch)
+ except Exception as e:
+ s.error(str(e), data)
+ return
+
+ #Success! Create and send reply
+ s.send_response(200)
+ s.send_header('content-type', 'application/json')
+ s.end_headers()
+ out = dict()
+ out['status'] = 'ok'
+ out['properties'] = properties
+ s.wrapMessageAndSend(out, data)
+
+ elif(command == 'read_register'):
+ #check required arguments
+ if not 'reg' in data:
+ s.error('message doesnt contains "reg" field, '
+ 'which is required for "read_register" command', data)
+ return
+
+ #parse command arguments and convert them to string
+ reg = str(data.get('reg', None))
+ bank = data.get('bank', None)
+ if not bank is None:
+ bank = str(bank)
+
+ value = 0
+ try:
+ value = s.pcilib.read_register(reg, bank)
+ except Exception as e:
+ s.error(str(e), data)
+ return
+
+ #Success! Create and send reply
+ s.send_response(200)
+ s.send_header('content-type', 'application/json')
+ s.end_headers()
+ out = dict()
+ out['status'] = 'ok'
+ out['value'] = value
+ s.wrapMessageAndSend(out, data)
+
+ elif(command == 'write_register'):
+ #check required arguments
+ if not 'reg' in data:
+ s.error('message doesnt contains "reg" field, '
+ 'which is required for "write_register" command', data)
+ return
+
+ if not 'value' in data:
+ s.error('message doesnt contains "value" field, '
+ 'which is required for "write_register" command', data)
+ return
+
+ #parse command arguments and convert them to string
+ reg = str(data.get('reg', None))
+ value = str(data.get('value', None))
+ bank = data.get('bank', None)
+ if not bank is None:
+ bank = str(bank)
+
+ try:
+ s.pcilib.write_register(value, reg, bank)
+ except Exception as e:
+ s.error(str(e), data)
+ return
+
+ #Success! Create and send reply
+ s.send_response(200)
+ s.send_header('content-type', 'application/json')
+ s.end_headers()
+ out = dict()
+ out['status'] = 'ok'
+ s.wrapMessageAndSend(out, data)
+
+ elif(command == 'get_property'):
+ #check required arguments
+ if not 'prop' in data:
+ s.error('message doesnt contains "prop" field, '
+ 'which is required for "get_property" command', data)
+ return
+
+ #parse command arguments and convert them to string
+ prop = str(data.get('prop', None))
+
+ value = 0
+ try:
+ value = s.pcilib.get_property(prop)
+ except Exception as e:
+ s.error(str(e), data)
+ return
+
+ #Success! Create and send reply
+ s.send_response(200)
+ s.send_header('content-type', 'application/json')
+ s.end_headers()
+ out = dict()
+ out['status'] = 'ok'
+ out['value'] = value
+ s.wrapMessageAndSend(out, data)
+
+ elif(command == 'set_property'):
+ #check required arguments
+ if not 'prop' in data:
+ s.error('message doesnt contains "prop" field, '
+ 'which is required for "set_property" command', data)
+ return
+
+ if not 'value' in data:
+ s.error('message doesnt contains "value" field, '
+ 'which is required for "set_property" command', data)
+ return
+
+ #parse command arguments and convert them to string
+ prop = str(data.get('prop', None))
+ value = str(data.get('value', None))
+
+ try:
+ s.pcilib.set_property(value, prop)
+ except Exception as e:
+ s.error(str(e), data)
+ return
+
+ #Success! Create and send reply
+ s.send_response(200)
+ s.send_header('content-type', 'application/json')
+ s.end_headers()
+ out = dict()
+ out['status'] = 'ok'
+ s.wrapMessageAndSend(out, data)
+
+
+ else:
+ s.error('command "' + command + '" undefined', data)
+ return
+ else:
+ s.error('message doesnt contains "command" field, which is required', data)
+ return
+
+
+ #print str(s.headers['content-type'])
+ #print post_data['some']
+
+ """open device context """
+ def openPcilibInstance(s, device, model):
+ s.pcilib = pcipywrap.create_pcilib_instance(device, model)
+
+ """Send help message"""
+ def help(s, received_message = None):
+ s.send_response(200)
+ s.send_header('content-type', 'application/json')
+ s.end_headers()
+ usage = str('Usage:\n'
+ ' Server receive commands via http GET with json packet.\n'
+ ' content-type should have value "application/json"\n'
+ ' Server could handle only commands. to set command, you\n'
+ ' should specify field "command" in packet with command name\n'
+ ' List of commands:\n'
+ '\n'
+ ' command: help - Get help. This will return usage\n'
+ '\n'
+
+ ' command: open - Opens context of device. It will be reopened if already open.\n'
+ ' required fields\n'
+ ' device: - path to the device file [/dev/fpga0]\n'
+ ' optional fields\n'
+ ' model: - specifies the model of hardware, autodetected if doesnt exists\n'
+ '\n'
+
+ ' command: get_registers_list - Returns the list of registers provided by the hardware model.\n'
+ ' optional fields\n'
+ ' bank: - if set, only register within the specified bank will be returned\n'
+ '\n'
+
+ ' command: get_register_info - Returns the information about the specified register.\n'
+ ' required fields\n'
+ ' reg: - the name of the register\n'
+ ' optional fields\n'
+ ' bank: - if set, only register within the specified bank will be returned\n'
+ '\n'
+
+ ' command: get_property_list - Returns the list of properties available under the specified path.\n'
+ ' optional fields\n'
+ ' branch: - Path. If not set, will return the top-level properties\n'
+ '\n'
+
+ ' command: read_register - Reads the specified register.\n'
+ ' required fields\n'
+ ' reg: - the name of the register\n'
+ ' optional fields\n'
+ ' bank: - if set, only register within the specified bank will be processed\n'
+ '\n'
+
+ ' command: write_register - Writes to specified register.\n'
+ ' required fields\n'
+ ' reg: - the name of the register\n'
+ ' value: - the register value to write. Should be int, float or string (with number)\n'
+ ' optional fields\n'
+ ' bank: - if set, only register within the specified bank will be processed\n'
+ '\n'
+
+ ' command: get_property - Reads / computes the property value.\n'
+ ' required fields\n'
+ ' prop: - full name including path\n'
+ '\n'
+
+ ' command: set_property - Writes the property value or executes the code associated with property.\n'
+ ' required fields\n'
+ ' prop: - full name including path\n'
+ ' value: - the property value to write. Should be int, float or string (with number)\n'
+ '\n')
+ out = {'status': 'ok', 'usage' : usage}
+ s.wrapMessageAndSend(out, received_message)
+
+ """Send error message with text description"""
+ def error(s, info, received_message = None):
+ s.send_response(400)
+ s.send_header('content-type', 'application/json')
+ s.end_headers()
+ out = dict()
+
+ out['status'] = 'error'
+ out['description'] = info
+ out['note'] = 'send {"command" : "help"} to get help'
+ s.wrapMessageAndSend(out, received_message)
+
+ def wrapMessageAndSend(s, message, received_message = None):
+ if not received_message is None:
+ message['received_message'] = received_message
+ s.wfile.write(json.dumps(message))
+
+if __name__ == '__main__':
+
+ #parce command line options
+ parser = OptionParser()
+ parser.add_option("-p", "--port", action="store",
+ type="int", dest="port", default=9000,
+ help="Set server port (9000)")
+ parser.add_option("-d", "--device", action="store",
+ type="string", dest="device", default=str('/dev/fpga0'),
+ help="FPGA device (/dev/fpga0)")
+ parser.add_option("-m", "--model", action="store",
+ type="string", dest="model", default=None,
+ help="Memory model (autodetected)")
+ opts = parser.parse_args()[0]
+
+ HOST_NAME = ''
+ PORT_NUMBER = opts.port
+ MODEL = opts.model
+ DEVICE = opts.device
+
+ #Set enviroment variables, if it not setted already
+ if not 'APP_PATH' in os.environ:
+ APP_PATH = ''
+ file_dir = os.path.dirname(os.path.abspath(__file__))
+ APP_PATH = str(os.path.abspath(file_dir + '/../..'))
+ os.environ["APP_PATH"] = APP_PATH
+
+ if not 'PCILIB_MODEL_DIR' in os.environ:
+ os.environ['PCILIB_MODEL_DIR'] = os.environ["APP_PATH"] + "/xml"
+
+ if not 'LD_LIBRARY_PATH' in os.environ:
+ os.environ['LD_LIBRARY_PATH'] = os.environ["APP_PATH"] + "/pcilib"
+
+ #redirect logs to exeption
+ pcipywrap.__redirect_logs_to_exeption()
+
+ #start server
+ pcilib_server = BaseHTTPServer.HTTPServer
+
+ #pass Pcipywrap to to server handler
+ lib = pcipywrap.Pcipywrap(DEVICE, MODEL)
+ def handler(*args):
+ PcilibServerHandler(lib, *args)
+
+ httpd = pcilib_server((HOST_NAME, PORT_NUMBER), handler)
+
+ print time.asctime(), "Server Starts - %s:%s" % (HOST_NAME, PORT_NUMBER)
+ try:
+ httpd.serve_forever()
+ except KeyboardInterrupt:
+ pass
+ httpd.server_close()
+ print time.asctime(), "Server Stops - %s:%s" % (HOST_NAME, PORT_NUMBER)
diff --git a/pywrap/test_pcipywrap.py b/pywrap/test_pcipywrap.py
new file mode 100644
index 0000000..257b4a5
--- /dev/null
+++ b/pywrap/test_pcipywrap.py
@@ -0,0 +1,119 @@
+import threading
+import pcipywrap
+import random
+import os
+import json
+import requests
+import time
+
+class test_pcipywrap():
+ def __init__(self, device, model, num_threads = 150,
+ write_percentage = 0.1, register = 'test_prop2',
+ server_host = 'http://localhost', server_port = 12412,
+ server_message_delay = 0):
+ #initialize enviroment variables
+ if not 'APP_PATH' in os.environ:
+ APP_PATH = ''
+ file_dir = os.path.dirname(os.path.abspath(__file__))
+ APP_PATH = str(os.path.abspath(file_dir + '/../..'))
+ os.environ["APP_PATH"] = APP_PATH
+
+ if not 'PCILIB_MODEL_DIR' in os.environ:
+ os.environ['PCILIB_MODEL_DIR'] = os.environ["APP_PATH"] + "/xml"
+ if not 'LD_LIBRARY_PATH' in os.environ:
+ os.environ['LD_LIBRARY_PATH'] = os.environ["APP_PATH"] + "/pcilib"
+
+ random.seed()
+ #create pcilib_instance
+ self.pcilib = pcipywrap.Pcipywrap(device, model)
+ self.num_threads = num_threads
+ self.write_percentage = write_percentage
+ self.register = register
+ self.server_message_delay = server_message_delay
+ self.server_port = server_port
+ self.server_host = server_host
+
+ def testThreadSafeReadWrite(self):
+ def threadFunc():
+ if random.randint(0, 100) >= (self.write_percentage * 100):
+ ret = self.pcilib.get_property('/test/prop2')
+ print self.register, ':', ret
+ del ret
+ else:
+ val = random.randint(0, 65536)
+ print 'set value:', val
+ self.pcilib.write_register(val, self.register)
+ try:
+ while(1):
+ thread_list = [threading.Thread(target=threadFunc) for i in range(0, self.num_threads)]
+ for i in range(0, self.num_threads):
+ thread_list[i].start()
+ for i in range(0, self.num_threads):
+ thread_list[i].join()
+ print 'cycle done'
+ except KeyboardInterrupt:
+ print 'testing done'
+ pass
+
+ def testMemoryLeak(self):
+ try:
+ while(1):
+ #print self.pcilib.create_pcilib_instance('/dev/fpga0','test_pywrap')
+
+ print self.pcilib.get_property_list('/test')
+ print self.pcilib.get_register_info('test_prop1')
+ #print self.pcilib.get_registers_list();
+
+ #print self.pcilib.read_register('reg1')
+ #print self.pcilib.write_register(12, 'reg1')
+
+ #print self.pcilib.get_property('/test/prop2')
+ #print self.pcilib.set_property(12, '/test/prop2')
+ except KeyboardInterrupt:
+ print 'testing done'
+ pass
+
+ def testServer(self):
+ url = str(self.server_host + ':' + str(self.server_port))
+ headers = {'content-type': 'application/json'}
+ payload =[{'com': 'open', 'data2' : '12341'},
+ #{'command': 'open', 'device' : '/dev/fpga0', 'model': 'test_pywrap'},
+ {'command': 'help'},
+ {'command': 'get_registers_list'},
+ {'command': 'get_register_info', 'reg': 'reg1'},
+ {'command': 'get_property_list'},
+ {'command': 'read_register', 'reg': 'reg1'},
+ {'command': 'write_register', 'reg': 'reg1'},
+ {'command': 'get_property', 'prop': '/test/prop2'},
+ {'command': 'set_property', 'prop': '/test/prop2'}]
+
+ def sendRandomMessage():
+ message_number = random.randint(1, len(payload) - 1)
+ print 'message number: ', message_number
+ payload[message_number]['value'] = random.randint(0, 65535)
+ r = requests.get(url, data=json.dumps(payload[message_number]), headers=headers)
+ print json.dumps(r.json(), sort_keys=True, indent=4, separators=(',', ': '))
+
+ try:
+ r = requests.get(url, data=json.dumps(payload[1]), headers=headers)
+ print json.dumps(r.json(), sort_keys=True, indent=3, separators=(',', ': '))
+
+ while(1):
+ time.sleep(self.server_message_delay)
+ thread_list = [threading.Thread(target=sendRandomMessage) for i in range(0, self.num_threads)]
+ for i in range(0, self.num_threads):
+ thread_list[i].start()
+ for i in range(0, self.num_threads):
+ thread_list[i].join()
+ print 'cycle done'
+
+ except KeyboardInterrupt:
+ print 'testing done'
+ pass
+
+if __name__ == '__main__':
+ lib = test_pcipywrap('/dev/fpga0','test_pywrap', num_threads = 150,
+ write_percentage = 0.1, register = 'test_prop2',server_host = 'http://localhost', server_port = 12412,
+ server_message_delay = 0)
+ lib.testThreadSafeReadWrite()
+
diff --git a/views/transform.c b/views/transform.c
index de7ee0e..f2d4b4a 100644
--- a/views/transform.c
+++ b/views/transform.c
@@ -9,7 +9,43 @@
#include "model.h"
#include "transform.h"
#include "py.h"
+#include "error.h"
+static pcilib_view_context_t * pcilib_transform_view_init(pcilib_t *ctx, pcilib_view_t view) {
+ int err;
+
+ pcilib_view_context_t *view_ctx;
+ const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx);
+ pcilib_transform_view_description_t *v = (pcilib_transform_view_description_t*)(model_info->views[view]);
+
+ if(v->script) {
+ pcilib_access_mode_t mode = 0;
+
+ err = pcilib_py_load_script(ctx, v->script);
+ if(err) {
+ pcilib_error("Error (%i), loading script %s", err, v->script);
+ return NULL;
+ }
+
+ err = pcilib_py_get_transform_script_properties(ctx, v->script, &mode);
+ if(err) {
+ pcilib_error("Error (%i) obtaining properties of transform script %s", err, v->script);
+ return NULL;
+ }
+
+ if ((v->base.mode&PCILIB_REGISTER_RW) == 0)
+ v->base.mode |= PCILIB_REGISTER_RW;
+ v->base.mode &= (~PCILIB_REGISTER_RW)|mode;
+
+ if (!v->read_from_reg) v->read_from_reg = "read_from_register";
+ if (!v->write_to_reg) v->write_to_reg = "write_to_register";
+ }
+
+ view_ctx = (pcilib_view_context_t*)malloc(sizeof(pcilib_view_context_t));
+ if (view_ctx) memset(view_ctx, 0, sizeof(pcilib_view_context_t));
+
+ return view_ctx;
+}
static int pcilib_transform_view_read(pcilib_t *ctx, pcilib_view_context_t *view_ctx, pcilib_register_value_t regval, pcilib_value_t *val) {
int err;
@@ -20,7 +56,12 @@ static int pcilib_transform_view_read(pcilib_t *ctx, pcilib_view_context_t *view
err = pcilib_set_value_from_register_value(ctx, val, regval);
if (err) return err;
- return pcilib_py_eval_string(ctx, v->read_from_reg, val);
+ if (v->script)
+ err = pcilib_py_eval_func(ctx, v->script, v->read_from_reg, val);
+ else
+ err = pcilib_py_eval_string(ctx, v->read_from_reg, val);
+
+ return err;
}
static int pcilib_transform_view_write(pcilib_t *ctx, pcilib_view_context_t *view_ctx, pcilib_register_value_t *regval, const pcilib_value_t *val) {
@@ -33,13 +74,16 @@ static int pcilib_transform_view_write(pcilib_t *ctx, pcilib_view_context_t *vie
err = pcilib_copy_value(ctx, &val_copy, val);
if (err) return err;
- err = pcilib_py_eval_string(ctx, v->write_to_reg, &val_copy);
+ if (v->script)
+ err = pcilib_py_eval_func(ctx, v->script, v->write_to_reg, &val_copy);
+ else
+ err = pcilib_py_eval_string(ctx, v->write_to_reg, &val_copy);
+
if (err) return err;
-
+
*regval = pcilib_get_value_as_register_value(ctx, &val_copy, &err);
return err;
}
-
const pcilib_view_api_description_t pcilib_transform_view_api =
- { PCILIB_VERSION, sizeof(pcilib_transform_view_description_t), NULL, NULL, NULL, pcilib_transform_view_read, pcilib_transform_view_write };
+ { PCILIB_VERSION, sizeof(pcilib_transform_view_description_t), pcilib_transform_view_init, NULL, NULL, pcilib_transform_view_read, pcilib_transform_view_write };
diff --git a/views/transform.h b/views/transform.h
index f474552..774a019 100644
--- a/views/transform.h
+++ b/views/transform.h
@@ -6,6 +6,7 @@
typedef struct {
pcilib_view_description_t base;
+ const char *script; /**< Python script module name */
const char *read_from_reg; /**< Formula explaining how to convert the register value to the view value */
const char *write_to_reg; /**< Formula explaining how to convert from the view value to the register value */
} pcilib_transform_view_description_t;
diff --git a/xml/test/props.xml b/xml/test/props.xml
index cf163eb..57702e2 100644
--- a/xml/test/props.xml
+++ b/xml/test/props.xml
@@ -1,4 +1,6 @@
<?xml version="1.0"?>
<model xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<transform path="/test/prop1" register="test_prop1" unit="C" read_from_register="(503975./1024000)*${/registers/fpga/sensor_temperature:C} - 27315./100" description="formula to get real fpga temperature from the fpga_temperature register in decimal"/>
+ <transform path="/test/prop2" register="test_prop2" unit="C" script="test_prop2.py" description="test python script #1" write_verification="0" />
+ <transform path="/test/prop3" register="test_prop3" unit="C" script="test_prop3.py" description="test python script #2" />
</model>
diff --git a/xml/test/test_prop2.py b/xml/test/test_prop2.py
new file mode 100644
index 0000000..d78dbea
--- /dev/null
+++ b/xml/test/test_prop2.py
@@ -0,0 +1,6 @@
+def read_from_register(ctx, value):
+ return ctx.get_property('/test/prop3') / 2
+
+def write_to_register(ctx, value):
+ ctx.set_property(value*2, '/test/prop3')
+
diff --git a/xml/test/test_prop3.py b/xml/test/test_prop3.py
new file mode 100644
index 0000000..a082096
--- /dev/null
+++ b/xml/test/test_prop3.py
@@ -0,0 +1,5 @@
+def read_from_register(ctx, value):
+ return ctx.get_property('/registers/fpga/reg1')
+
+def write_to_register(ctx, value):
+ ctx.set_property(value, '/registers/fpga/reg1')
diff --git a/xml/types.xsd b/xml/types.xsd
index 78be773..5fc8902 100644
--- a/xml/types.xsd
+++ b/xml/types.xsd
@@ -59,6 +59,7 @@
<xsd:attribute name="unit" type="xsd:string" />
<xsd:attribute name="type" type="pcilib_data_type_t" />
<xsd:attribute name="mode" type="pcilib_access_mode_t" />
+ <xsd:attribute name="write_verification" type="bool_t" default="1"/>
<xsd:attribute name="visible" type="bool_t" default="0" />
<xsd:attribute name="description" type="xsd:string" />
</xsd:complexType>
@@ -70,6 +71,7 @@
<xsd:attribute name="register" type="xsd:string" />
<xsd:attribute name="read_from_register" type="xsd:string" />
<xsd:attribute name="write_to_register" type="xsd:string" />
+ <xsd:attribute name="script" type="xsd:string" />
<!-- xsd 1.1 <xsd:assert test="(@path and not(@name)) or (not(@path) and @name)"/> -->
</xsd:extension>
</xsd:complexContent>