summaryrefslogtreecommitdiffstats
path: root/pcilib
diff options
context:
space:
mode:
Diffstat (limited to 'pcilib')
-rw-r--r--pcilib/CMakeLists.txt8
-rw-r--r--pcilib/build.h.in7
-rw-r--r--pcilib/config.h.in1
-rw-r--r--pcilib/error.c7
-rw-r--r--pcilib/pci.c5
-rw-r--r--pcilib/pcilib.h15
-rw-r--r--pcilib/property.c6
-rw-r--r--pcilib/py.c653
-rw-r--r--pcilib/py.h122
-rw-r--r--pcilib/value.c22
-rw-r--r--pcilib/view.c13
-rw-r--r--pcilib/view.h2
-rw-r--r--pcilib/xml.c32
13 files changed, 496 insertions, 397 deletions
diff --git a/pcilib/CMakeLists.txt b/pcilib/CMakeLists.txt
index cdc9c3f..a7557b7 100644
--- a/pcilib/CMakeLists.txt
+++ b/pcilib/CMakeLists.txt
@@ -8,10 +8,10 @@ include_directories(
${UTHASH_INCLUDE_DIRS}
)
-set(HEADERS pcilib.h pci.h datacpy.h memcpy.h pagecpy.h cpu.h timing.h export.h value.h bar.h fifo.h model.h bank.h register.h view.h property.h unit.h xml.h py.h kmem.h irq.h locking.h lock.h dma.h event.h plugin.h tools.h error.h debug.h env.h version.h config.h)
-add_library(pcilib SHARED pci.c datacpy.c memcpy.c pagecpy.c cpu.c timing.c export.c value.c bar.c fifo.c model.c bank.c register.c view.c unit.c property.c xml.c py.c kmem.c irq.c locking.c lock.c dma.c event.c plugin.c tools.c error.c debug.c env.c )
+set(HEADERS pcilib.h pci.h datacpy.h memcpy.h pagecpy.h cpu.h timing.h export.h value.h bar.h fifo.h model.h bank.h register.h view.h property.h unit.h xml.h py.h kmem.h irq.h locking.h lock.h dma.h event.h plugin.h tools.h error.h debug.h env.h version.h config.h build.h)
+add_library(pcilib SHARED pci.c datacpy.c memcpy.c pagecpy.c cpu.c timing.c export.c value.c bar.c fifo.c model.c bank.c register.c view.c unit.c property.c xml.c py.c kmem.c irq.c locking.c lock.c dma.c event.c plugin.c tools.c error.c debug.c env.c)
target_link_libraries(pcilib dma protocols views ${CMAKE_THREAD_LIBS_INIT} ${UFODECODE_LIBRARIES} ${CMAKE_DL_LIBS} ${EXTRA_SYSTEM_LIBS} ${LIBXML2_LIBRARIES} ${PYTHON_LIBRARIES})
-add_dependencies(pcilib dma protocols views)
+add_dependencies(pcilib build dma protocols views)
install(TARGETS pcilib
LIBRARY DESTINATION lib${LIB_SUFFIX}
@@ -23,4 +23,4 @@ install(FILES pcilib.h
install(FILES bar.h kmem.h locking.h lock.h bank.h register.h xml.h dma.h event.h model.h error.h debug.h env.h tools.h timing.h cpu.h datacpy.h pagecpy.h memcpy.h export.h version.h view.h unit.h
DESTINATION include/pcilib
-)
+) \ No newline at end of file
diff --git a/pcilib/build.h.in b/pcilib/build.h.in
new file mode 100644
index 0000000..1713378
--- /dev/null
+++ b/pcilib/build.h.in
@@ -0,0 +1,7 @@
+#define PCILIB_REVISION "${PCILIB_REVISION}"
+#define PCILIB_REVISION_BRANCH "${PCILIB_REVISION_BRANCH}"
+#define PCILIB_REVISION_AUTHOR "${PCILIB_REVISION_AUTHOR}"
+#define PCILIB_REVISION_MODIFICATIONS "${PCILIB_REVISION_MODIFICATIONS}"
+#define PCILIB_BUILD_DATE "${PCILIB_BUILD_DATE}"
+#define PCILIB_BUILD_DIR "${CMAKE_SOURCE_DIR}"
+#define PCILIB_LAST_MODIFICATION "${PCILIB_LAST_MODIFICATION}"
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 a2e5a04..ae8bacb 100644
--- a/pcilib/error.c
+++ b/pcilib/error.c
@@ -80,10 +80,11 @@ int pcilib_set_logger(pcilib_log_priority_t min_prio, pcilib_logger_t logger, vo
pcilib_logger_t pcilib_get_logger() {
return pcilib_logger;
}
+
pcilib_log_priority_t pcilib_get_log_level() {
- return pcilib_logger_min_prio;
+ return pcilib_logger_min_prio;
}
+
void* pcilib_get_logger_context() {
- return pcilib_logger_argument;
+ return pcilib_logger_argument;
}
-
diff --git a/pcilib/pci.c b/pcilib/pci.c
index 2b7b97b..19165ba 100644
--- a/pcilib/pci.c
+++ b/pcilib/pci.c
@@ -192,7 +192,7 @@ 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);
+ err = pcilib_py_add_script_dir(ctx, NULL);
if (err) {
pcilib_error("Error (%i) add script path to python path", err);
pcilib_close(ctx);
@@ -355,12 +355,11 @@ void pcilib_close(pcilib_t *ctx) {
if (ctx->registers)
free(ctx->registers);
- pcilib_free_py(ctx);
-
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 c32d1fb..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,7 +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 = 0x1000 /**< dont check register value after set*/
+ PCILIB_REGISTER_INCONSISTENT = 0x10000 /**< inconsistent register, writting and reading does not match */
} pcilib_register_mode_t;
typedef enum {
@@ -1257,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 3a7ebb3..dfab9a6 100644
--- a/pcilib/property.c
+++ b/pcilib/property.c
@@ -225,11 +225,9 @@ 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_DEL(dir_hash, dir);
+ free(dir);
}
HASH_CLEAR(hh, dir_hash);
diff --git a/pcilib/py.c b/pcilib/py.c
index a288043..9254df7 100644
--- a/pcilib/py.c
+++ b/pcilib/py.c
@@ -1,151 +1,333 @@
-#ifdef BUILD_PYTHON_MODULES
-#include <Python.h>
-#endif
-
+#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 BUILD_PYTHON_MODULES
-typedef struct pcilib_script_s {
- const char* name;
- PyObject *module; /**< PyModule object, contains script enviroment */
- UT_hash_handle hh;
-} pcilib_script_s;
+#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;
- PyObject *pcilib_pywrap;
- int py_initialized_inside; ///< Flag, shows that Py_Initialize has been called inside class
- struct pcilib_script_s *scripts;
+ 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
+#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 BUILD_PYTHON_MODULES
+#ifdef HAVE_PYTHON
ctx->py = (pcilib_py_t*)malloc(sizeof(pcilib_py_t));
if (!ctx->py) return PCILIB_ERROR_MEMORY;
- if(!Py_IsInitialized())
- {
+ 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 works properly with c threads
+ // 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->py_initialized_inside = 1;
- }
- else
- ctx->py->py_initialized_inside = 0;
+ }
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* py_script_module = PyImport_ImportModule("pcipywrap");
- if(!py_script_module)
- {
- printf("Error in import python module: ");
- PyErr_Print();
- 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(py_script_module,
- mod_name,
- PyCObject_FromVoidPtr(ctx, NULL),
- NULL);
- Py_XDECREF(mod_name);
+ 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)
- {
- printf("Error in import python module: ");
- PyErr_Print();
+ if (!ctx->py->pcilib_pywrap) {
+ pcilib_python_error("Error initializing python wrapper");
return PCILIB_ERROR_FAILED;
- }
-
- ctx->py->scripts = NULL;
-#endif
+ }
+#endif /* HAVE_PYTHON */
+
return 0;
}
-int pcilib_py_add_script_dir(pcilib_t *ctx)
-{
-#ifdef BUILD_PYTHON_MODULES
- //create path string, where the model scripts should be
- static int model_dir_added = 0;
- if(!model_dir_added)
- {
- char* model_dir = getenv("PCILIB_MODEL_DIR");
- char* model_path = malloc(strlen(model_dir) + strlen(ctx->model) + 2);
- if (!model_path) return PCILIB_ERROR_MEMORY;
- sprintf(model_path, "%s/%s", model_dir, ctx->model);
- //add path to python
- PyObject* path = PySys_GetObject("path");
- if(PyList_Append(path, PyString_FromString(model_path)) == -1)
- {
- pcilib_error("Cant set PCILIB_MODEL_DIR library path to python.");
- free(model_path);
- return PCILIB_ERROR_FAILED;
- }
- free(model_path);
- model_dir_added = 1;
- }
-#endif
- 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) {
-#ifdef BUILD_PYTHON_MODULES
- int py_initialized_inside = 0;
+#ifdef HAVE_PYTHON
+ int finalyze = 0;
if (ctx->py) {
- if(ctx->py->py_initialized_inside)
- py_initialized_inside = 1;
-
- // Dict and module references are borrowed
+ 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(py_initialized_inside)
- Py_Finalize();
-#endif
+ if (finalyze)
+ Py_Finalize();
+#endif /* HAVE_PYTHON */
}
-/*
-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_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;
+
+ 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;
+}
+
+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;
}
-*/
-#ifdef BUILD_PYTHON_MODULES
+
+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;
@@ -251,10 +433,10 @@ static char *pcilib_py_parse_string(pcilib_t *ctx, const char *codestr, pcilib_v
return dst;
}
-#endif
+#endif /* HAVE_PYTHON */
int pcilib_py_eval_string(pcilib_t *ctx, const char *codestr, pcilib_value_t *value) {
-#ifdef BUILD_PYTHON_MODULES
+#ifdef HAVE_PYTHON
PyGILState_STATE gstate;
char *code;
PyObject* obj;
@@ -276,248 +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
+#else /* HAVE_PYTHON */
pcilib_error("Current build not support python.");
return PCILIB_ERROR_NOTAVAILABLE;
-#endif
+#endif /* HAVE_PYTHON */
}
-pcilib_py_object* pcilib_get_value_as_pyobject(pcilib_t* ctx, pcilib_value_t *val, int *ret)
-{
-#ifdef BUILD_PYTHON_MODULES
- int err;
-
- switch(val->type)
- {
- case PCILIB_TYPE_INVALID:
- pcilib_error("Invalid register output type (PCILIB_TYPE_INVALID)");
- if (ret) *ret = PCILIB_ERROR_NOTSUPPORTED;
- return NULL;
-
- case PCILIB_TYPE_STRING:
- pcilib_error("Invalid register output type (PCILIB_TYPE_STRING)");
- if (ret) *ret = PCILIB_ERROR_NOTSUPPORTED;
- return NULL;
-
- case PCILIB_TYPE_LONG:
- {
- long ret_val;
- ret_val = pcilib_get_value_as_int(ctx, val, &err);
-
- if(err)
- {
- if (ret) *ret = err;
- return NULL;
- }
-
- if (ret) *ret = 0;
- return (PyObject*)PyInt_FromLong((long) ret_val);
- }
-
- case PCILIB_TYPE_DOUBLE:
- {
- double ret_val;
- ret_val = pcilib_get_value_as_float(ctx, val, &err);
-
- if(err)
- {
- if (ret) *ret = err;
- return NULL;
- }
-
- if (ret) *ret = 0;
- return (PyObject*)PyFloat_FromDouble((double) ret_val);
- }
-
- default:
- if (ret) *ret = PCILIB_ERROR_NOTSUPPORTED;
- pcilib_error("Invalid register output type (unknown)");
- return NULL;
- }
-#else
- pcilib_error("Current build not support python.");
- if (ret) *ret = PCILIB_ERROR_NOTAVAILABLE;
- return NULL;
-#endif
-}
+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;
-int pcilib_set_value_from_pyobject(pcilib_t* ctx, pcilib_value_t *val, pcilib_py_object* pyObjVal)
-{
-#ifdef BUILD_PYTHON_MODULES
- PyObject* pyVal = pyObjVal;
- int err;
-
- PyGILState_STATE gstate = PyGILState_Ensure();
- if(PyInt_Check(pyVal))
- {
- err = pcilib_set_value_from_int(ctx, val, PyInt_AsLong(pyVal));
+ 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;
}
- 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_static_string(ctx, val, PyString_AsString(pyVal));
- else
- {
- PyGILState_Release(gstate);
- pcilib_error("Invalid input. Input type should be int, float or string.");
- return PCILIB_ERROR_NOTSUPPORTED;
- }
+
+ 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);
- if(err)
- return err;
-
- return 0;
-#else
- pcilib_error("Current build not support python.");
- return PCILIB_ERROR_NOTAVAILABLE;
-#endif
-}
-int pcilib_py_init_script(pcilib_t *ctx, const char* module_name)
-{
-#ifdef BUILD_PYTHON_MODULES
- //extract module name from script name
- char* py_module_name = strdup(module_name);
- py_module_name = strtok(py_module_name, ".");
- if(!py_module_name)
- {
- pcilib_error("Invalid script name specified in XML property (%s)."
- " Seems like name doesnt contains extension", module_name);
- return PCILIB_ERROR_INVALID_DATA;
- }
-
- pcilib_script_s* module = NULL;
- HASH_FIND_STR( ctx->py->scripts, module_name, module);
- if(module)
- {
- pcilib_warning("Python module %s is already in hash. Skip init step", module_name);
- return 0;
- }
-
- //import python script
- PyObject* py_script_module = PyImport_ImportModule(py_module_name);
- if(!py_script_module)
- {
- printf("Error in import python module: ");
- PyErr_Print();
- free(py_module_name);
- return PCILIB_ERROR_INVALID_DATA;
- }
- free(py_module_name);
+ Py_XDECREF(pyfunc);
+ Py_XDECREF(pyval);
- //Success. Create struct and initialize values
- module = malloc(sizeof(pcilib_script_s));
- if (!module)
- return PCILIB_ERROR_MEMORY;
- module->module = py_script_module;
- module->name = module_name;
- HASH_ADD_STR( ctx->py->scripts, name, module);
-#endif
- return 0;
-}
+ if (!pyret) {
+ pcilib_python_error("Error executing function (%s) of python script (%s)", func_name, script_name);
+ return PCILIB_ERROR_FAILED;
+ }
-int pcilib_py_get_transform_script_properties(pcilib_t *ctx, const char* module_name,
-pcilib_access_mode_t *mode)
-{
-#ifdef BUILD_PYTHON_MODULES
- pcilib_script_s *module;
-
- HASH_FIND_STR(ctx->py->scripts, module_name, module);
- if(!module)
- {
- pcilib_error("Failed to find script module (%s) in hash", module_name);
- return PCILIB_ERROR_NOTFOUND;
- }
-
- PyObject* dict = PyModule_GetDict(module->module);
- //Setting correct mode
- mode[0] = 0;
- if(PyDict_Contains(dict, PyString_FromString("read_from_register")))
- mode[0] |= PCILIB_ACCESS_R;
- if(PyDict_Contains(dict, PyString_FromString("write_to_register")))
- mode[0] |= PCILIB_ACCESS_W;
- return 0;
-#else
- mode[0] = PCILIB_ACCESS_RW;
- return 0;
-#endif
-}
+ if ((val)&&(pyret != Py_None))
+ err = pcilib_set_value_from_pyobject(ctx, val, pyret);
-int pcilib_py_free_script(pcilib_t *ctx, const char* module_name)
-{
-#ifdef BUILD_PYTHON_MODULES
- pcilib_script_s *module;
- HASH_FIND_STR(ctx->py->scripts, module_name, module);
-
- if(!module)
- {
- pcilib_warning("Cant find Python module %s in hash. Seems it has already deleted.", module_name);
- return 0;
- }
-
- if(module->module)
- {
- module->module = NULL;
- }
-
- HASH_DEL(ctx->py->scripts, module);
- free(module);
-#endif
- return 0;
-}
+ Py_XDECREF(pyret);
-int pcilib_script_run_func(pcilib_t *ctx, const char* module_name,
- const char* func_name, pcilib_value_t *val)
-{
-#ifdef BUILD_PYTHON_MODULES
- int err;
- pcilib_script_s *module;
- HASH_FIND_STR(ctx->py->scripts, module_name, module);
- if(!module)
- {
- pcilib_error("Failed to find script module (%s) in hash", module_name);
- return PCILIB_ERROR_NOTFOUND;
- }
-
- PyGILState_STATE gstate = PyGILState_Ensure();
- PyObject *input = pcilib_get_value_as_pyobject(ctx, val, &err);
- if(err)
- return err;
-
- PyObject *py_func_name = PyUnicode_FromString(func_name);
- PyObject *ret = PyObject_CallMethodObjArgs(module->module,
- py_func_name,
- ctx->py->pcilib_pywrap,
- input,
- NULL);
-
- Py_XDECREF(py_func_name);
- Py_XDECREF(input);
- PyGILState_Release(gstate);
-
- if (!ret)
- {
- printf("Python script error: ");
- PyErr_Print();
- return PCILIB_ERROR_FAILED;
- }
-
- if(ret != Py_None)
- {
- err = pcilib_set_value_from_pyobject(ctx, val, ret);
- Py_XDECREF(ret);
-
- if(err)
- {
- pcilib_error("Failed to convert python script return value to internal type: %i", err);
- return err;
- }
- }
- return 0;
-#else
- pcilib_error("Current build not support python.");
- return PCILIB_ERROR_NOTAVAILABLE;
-#endif
+ 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 04b4e8b..c372a09 100644
--- a/pcilib/py.h
+++ b/pcilib/py.h
@@ -1,7 +1,10 @@
#ifndef _PCILIB_PY_H
#define _PCILIB_PY_H
-#include "pcilib.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;
@@ -10,39 +13,110 @@ typedef void pcilib_py_object;
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_add_script_dir(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);
-int pcilib_py_init_script(pcilib_t *ctx, const char* module_name);
-int pcilib_py_free_script(pcilib_t *ctx, const char* module_name);
-int pcilib_script_run_func(pcilib_t *ctx, const char* module_name,
- const char* func_name, pcilib_value_t *val);
-
-int pcilib_py_get_transform_script_properties(pcilib_t *ctx,
- const char* module_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);
-/*!
- * \brief Converts pcilib_value_t to PyObject.
- * \param ctx pointer to pcilib_t context
- * \param val pointer to pcilib_value_t to convert
- * \return PyObject, containing value. NULL with error message, sended to errstream.
+/**
+ * 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
*/
-pcilib_py_object* pcilib_get_value_as_pyobject(pcilib_t* ctx, pcilib_value_t *val, int *err);
+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
-/*!
- * \brief Converts PyObject to pcilib_value_t.
- * \param ctx pcilib context
- * \param pyVal python object, containing value
- * \param val initialized polymorphic value
- * \return 0 on success or memory error
+ * @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_set_value_from_pyobject(pcilib_t* ctx, pcilib_value_t *val, pcilib_py_object* pyObjVal);
+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
}
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 797f4ae..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, v);
+ 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 1a1d277..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, const pcilib_view_description_t *desc); /**< 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 35721aa..fd12636 100644
--- a/pcilib/xml.c
+++ b/pcilib/xml.c
@@ -40,9 +40,9 @@
#include "xml.h"
#include "error.h"
#include "view.h"
+#include "py.h"
#include "views/enum.h"
#include "views/transform.h"
-#include "py.h"
#define BANKS_PATH ((xmlChar*)"/model/bank") /**< path to complete nodes of banks */
@@ -492,8 +492,8 @@ static int pcilib_xml_create_bank(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDo
static int pcilib_xml_parse_view(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node, pcilib_view_description_t *desc) {
xmlAttrPtr cur;
const char *value, *name;
-
- int register_incosistent = 0;
+
+ int inconsistent = (desc->mode & PCILIB_ACCESS_INCONSISTENT);
for (cur = node->properties; cur != NULL; cur = cur->next) {
if (!cur->children) continue;
@@ -540,19 +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 (!strcasecmp(value, "0"))
- {
- register_incosistent = 1;
- }
- }
+ } else if (!strcasecmp(name, "write_verification")) {
+ if (strcmp(value, "0")) inconsistent = 0;
+ else inconsistent = 1;
}
+ }
- if(register_incosistent)
- {
- desc->mode |= PCILIB_REGISTER_INCONSISTENT;
- }
+ if (inconsistent) desc->mode |= PCILIB_ACCESS_INCONSISTENT;
+ else desc->mode &= ~PCILIB_ACCESS_INCONSISTENT;
return 0;
}
@@ -563,7 +558,7 @@ static int pcilib_xml_create_transform_view(pcilib_t *ctx, xmlXPathContextPtr xp
const char *value, *name;
pcilib_view_context_t *view_ctx;
- pcilib_access_mode_t mode = PCILIB_REGISTER_INCONSISTENT;
+ pcilib_access_mode_t mode = 0;
pcilib_transform_view_description_t desc = {{0}};
desc.base.api = &pcilib_transform_view_api;
@@ -600,11 +595,11 @@ 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.module = value;
- break;
+ 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;
@@ -845,7 +840,6 @@ static int pcilib_xml_process_document(pcilib_t *ctx, xmlDocPtr doc, xmlXPathCon
if (bank_nodes) transform_nodes = xmlXPathEvalExpression(TRANSFORM_VIEWS_PATH, xpath);
if (transform_nodes) enum_nodes = xmlXPathEvalExpression(ENUM_VIEWS_PATH, xpath);
if (enum_nodes) unit_nodes = xmlXPathEvalExpression(UNITS_PATH, xpath);
-
if (!unit_nodes) {
const unsigned char *expr = (enum_nodes?UNITS_PATH:(transform_nodes?ENUM_VIEWS_PATH:(bank_nodes?TRANSFORM_VIEWS_PATH:BANKS_PATH)));