Browse Source

Merge Python scripting support from Vasiliy Chernov

Suren A. Chilingaryan 8 years ago
parent
commit
a962c90543

+ 3 - 0
.bzrignore

@@ -33,3 +33,6 @@ Doxyfile
 html
 pcilib/build.h
 build.h
+build
+pcipywrap.py
+pcipywrapPYTHON_wrap.c

+ 23 - 4
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

+ 3 - 0
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})

+ 92 - 0
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;
+}

+ 2 - 2
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

+ 7 - 6
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
 ===========

+ 1 - 1
misc/xml/format.sh

@@ -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 $*

+ 1 - 0
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

+ 12 - 0
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;
+}

+ 14 - 0
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
 }

+ 11 - 4
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);

+ 13 - 1
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 {
@@ -1255,6 +1257,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

+ 4 - 1
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));

+ 346 - 24
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 */
 }

+ 108 - 1
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

+ 22 - 0
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;

+ 7 - 6
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;
     }

+ 1 - 1
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) */

+ 17 - 7
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;

+ 1 - 1
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);

+ 22 - 0
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)

+ 503 - 0
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;
+}

+ 68 - 0
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 */

+ 25 - 0
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;

+ 399 - 0
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)

+ 119 - 0
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()
+

+ 49 - 5
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 };

+ 1 - 0
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;

+ 2 - 0
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>

+ 6 - 0
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')
+

+ 5 - 0
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')

+ 2 - 0
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>