summaryrefslogtreecommitdiffstats
path: root/pcilib
diff options
context:
space:
mode:
authorSuren A. Chilingaryan <csa@suren.me>2016-02-23 07:20:33 +0100
committerSuren A. Chilingaryan <csa@suren.me>2016-02-23 07:20:33 +0100
commita962c90543955bac98308c1b0d909048070d900a (patch)
tree70b06851187e6bf8cfd8ee28931bdea25ea92ac7 /pcilib
parent055279e09c3db9429e02874ec9620b9af357c80a (diff)
parent52eb7f4fb76ddf99dedf44332aae7af4df76ab36 (diff)
downloadpcitool-a962c90543955bac98308c1b0d909048070d900a.tar.gz
pcitool-a962c90543955bac98308c1b0d909048070d900a.tar.bz2
pcitool-a962c90543955bac98308c1b0d909048070d900a.tar.xz
pcitool-a962c90543955bac98308c1b0d909048070d900a.zip
Merge Python scripting support from Vasiliy Chernov
Diffstat (limited to 'pcilib')
-rw-r--r--pcilib/config.h.in1
-rw-r--r--pcilib/error.c12
-rw-r--r--pcilib/error.h14
-rw-r--r--pcilib/pci.c15
-rw-r--r--pcilib/pcilib.h14
-rw-r--r--pcilib/property.c5
-rw-r--r--pcilib/py.c370
-rw-r--r--pcilib/py.h109
-rw-r--r--pcilib/value.c22
-rw-r--r--pcilib/view.c13
-rw-r--r--pcilib/view.h2
-rw-r--r--pcilib/xml.c24
12 files changed, 556 insertions, 45 deletions
diff --git a/pcilib/config.h.in b/pcilib/config.h.in
index bdd9ec3..cd8033c 100644
--- a/pcilib/config.h.in
+++ b/pcilib/config.h.in
@@ -3,3 +3,4 @@
#cmakedefine PCILIB_MODEL_DIR "${PCILIB_MODEL_DIR}"
#cmakedefine PCILIB_DEBUG_DIR "${PCILIB_DEBUG_DIR}"
#cmakedefine HAVE_STDATOMIC_H @HAVE_STDATOMIC_H@
+#cmakedefine HAVE_PYTHON
diff --git a/pcilib/error.c b/pcilib/error.c
index 06af292..ae8bacb 100644
--- a/pcilib/error.c
+++ b/pcilib/error.c
@@ -76,3 +76,15 @@ int pcilib_set_logger(pcilib_log_priority_t min_prio, pcilib_logger_t logger, vo
return 0;
}
+
+pcilib_logger_t pcilib_get_logger() {
+ return pcilib_logger;
+}
+
+pcilib_log_priority_t pcilib_get_log_level() {
+ return pcilib_logger_min_prio;
+}
+
+void* pcilib_get_logger_context() {
+ return pcilib_logger_argument;
+}
diff --git a/pcilib/error.h b/pcilib/error.h
index a9f4c0b..051ecd8 100644
--- a/pcilib/error.h
+++ b/pcilib/error.h
@@ -40,6 +40,20 @@ extern "C" {
void pcilib_log_message(const char *file, int line, pcilib_log_flags_t flags, pcilib_log_priority_t prio, const char *msg, ...);
void pcilib_log_vmessage(const char *file, int line, pcilib_log_flags_t flags, pcilib_log_priority_t prio, const char *msg, va_list va);
+/**
+ * Gets current logger function.
+ */
+pcilib_logger_t pcilib_get_logger();
+
+/**
+ * Gets current logger min priority.
+ */
+pcilib_log_priority_t pcilib_get_log_level();
+
+/**
+ * Gets current logger argument.
+ */
+void* pcilib_get_logger_context();
#ifdef __cplusplus
}
diff --git a/pcilib/pci.c b/pcilib/pci.c
index eaf41ac..19165ba 100644
--- a/pcilib/pci.c
+++ b/pcilib/pci.c
@@ -191,6 +191,14 @@ pcilib_t *pcilib_open(const char *device, const char *model) {
if (!ctx->model)
ctx->model = strdup(model?model:"pci");
+
+ err = pcilib_py_add_script_dir(ctx, NULL);
+ if (err) {
+ pcilib_error("Error (%i) add script path to python path", err);
+ pcilib_close(ctx);
+ return NULL;
+ }
+
xmlerr = pcilib_init_xml(ctx, ctx->model);
if ((xmlerr)&&(xmlerr != PCILIB_ERROR_NOTFOUND)) {
@@ -198,6 +206,7 @@ pcilib_t *pcilib_open(const char *device, const char *model) {
pcilib_close(ctx);
return NULL;
}
+
// We have found neither standard model nor XML
if ((err)&&(xmlerr)) {
@@ -219,7 +228,6 @@ pcilib_t *pcilib_open(const char *device, const char *model) {
pcilib_close(ctx);
return NULL;
}
-
err = pcilib_init_event_engine(ctx);
if (err) {
pcilib_error("Error (%i) initializing event engine\n", err);
@@ -305,8 +313,6 @@ void pcilib_close(pcilib_t *ctx) {
if (ctx->event_plugin)
pcilib_plugin_close(ctx->event_plugin);
-
- pcilib_free_py(ctx);
if (ctx->locks.kmem)
pcilib_free_locking(ctx);
@@ -348,11 +354,12 @@ void pcilib_close(pcilib_t *ctx) {
if (ctx->registers)
free(ctx->registers);
-
+
if (ctx->model)
free(ctx->model);
pcilib_free_xml(ctx);
+ pcilib_free_py(ctx);
if (ctx->handle >= 0)
close(ctx->handle);
diff --git a/pcilib/pcilib.h b/pcilib/pcilib.h
index 3e7cf2b..8ab8e9e 100644
--- a/pcilib/pcilib.h
+++ b/pcilib/pcilib.h
@@ -43,7 +43,8 @@ typedef enum {
typedef enum {
PCILIB_ACCESS_R = 1, /**< getting property is allowed */
PCILIB_ACCESS_W = 2, /**< setting property is allowed */
- PCILIB_ACCESS_RW = 3
+ PCILIB_ACCESS_RW = 3,
+ PCILIB_ACCESS_INCONSISTENT = 0x10000 /**< inconsistent access, one will not read that one has written */
} pcilib_access_mode_t;
typedef enum {
@@ -54,6 +55,7 @@ typedef enum {
PCILIB_REGISTER_RW1C = 5,
PCILIB_REGISTER_W1I = 8, /**< writting 1 inversts the bit, writting 0 keeps the value */
PCILIB_REGISTER_RW1I = 9,
+ PCILIB_REGISTER_INCONSISTENT = 0x10000 /**< inconsistent register, writting and reading does not match */
} pcilib_register_mode_t;
typedef enum {
@@ -1256,6 +1258,16 @@ int pcilib_set_value_from_register_value(pcilib_t *ctx, pcilib_value_t *val, pci
int pcilib_set_value_from_static_string(pcilib_t *ctx, pcilib_value_t *val, const char *str);
/**
+ * Initializes the polymorphic value from the string. The string is copied.
+ * If `val` already contains the value, cleans it first. Therefore, before first usage the value should be always initialized to 0.
+ * @param[in] ctx - pcilib context
+ * @param[in,out] val - initialized polymorphic value
+ * @param[in] str - initializer
+ * @return - 0 on success or memory error
+ */
+int pcilib_set_value_from_string(pcilib_t *ctx, pcilib_value_t *value, const char *str);
+
+/**
* Get the floating point value from the polymorphic type. May inmply impliced type conversion,
* for isntance parsing the number from the string. Will return 0. and report an error if
* conversion failed.
diff --git a/pcilib/property.c b/pcilib/property.c
index a7d1a61..dfab9a6 100644
--- a/pcilib/property.c
+++ b/pcilib/property.c
@@ -165,7 +165,6 @@ pcilib_property_info_t *pcilib_get_property_list(pcilib_t *ctx, const char *bran
continue;
}
-
dir = (struct dir_hash_s*)malloc(sizeof(struct dir_hash_s));
if (!dir) {
err = PCILIB_ERROR_MEMORY;
@@ -226,6 +225,10 @@ pcilib_property_info_t *pcilib_get_property_list(pcilib_t *ctx, const char *bran
};
}
+ HASH_ITER(hh, dir_hash, dir, dir_tmp) {
+ HASH_DEL(dir_hash, dir);
+ free(dir);
+ }
HASH_CLEAR(hh, dir_hash);
memset(&info[pos], 0, sizeof(pcilib_property_info_t));
diff --git a/pcilib/py.c b/pcilib/py.c
index 4256afc..9254df7 100644
--- a/pcilib/py.c
+++ b/pcilib/py.c
@@ -1,66 +1,333 @@
-#include <Python.h>
-
+#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
-
+#include <alloca.h>
#include "pci.h"
#include "debug.h"
#include "pcilib.h"
#include "py.h"
#include "error.h"
+#include "config.h"
+
+#ifdef HAVE_PYTHON
+# include <Python.h>
+#endif /* HAVE_PYTHON */
+
+#ifdef HAVE_PYTHON
+typedef struct pcilib_script_s pcilib_script_t;
+
+struct pcilib_script_s {
+ const char *name; /**< Script name */
+ PyObject *module; /**< PyModule object, contains script enviroment */
+ UT_hash_handle hh; /**< hash */
+};
struct pcilib_py_s {
- PyObject *main_module;
- PyObject *global_dict;
+ int finalyze; /**< Indicates, that we are initialized from wrapper and should not destroy Python resources in destructor */
+ PyObject *main_module; /**< Main interpreter */
+ PyObject *global_dict; /**< Dictionary of main interpreter */
+ PyObject *pcilib_pywrap; /**< pcilib wrapper module */
+ pcilib_script_t *script_hash; /**< Hash with loaded scripts */
};
+#endif /* HAVE_PYTHON */
+
+void pcilib_log_python_error(const char *file, int line, pcilib_log_flags_t flags, pcilib_log_priority_t prio, const char *msg, ...) {
+ va_list va;
+ const char *type = NULL;
+ const char *val = NULL;
+
+#ifdef HAVE_PYTHON
+ PyObject *pytype = NULL;
+ PyObject *pyval = NULL;
+ PyObject *pytraceback = NULL;
+
+ PyErr_Fetch(&pytype, &pyval, &pytraceback);
+ type = PyString_AsString(pytype);
+ val = PyString_AsString(pyval);
+#endif /* HAVE_PYTHON */
+
+ va_start(va, msg);
+ if (type) {
+ char *str;
+ size_t len = 32;
+
+ if (msg) len += strlen(msg);
+ if (type) len += strlen(type);
+ if (val) len += strlen(val);
+
+ str = alloca(len * sizeof(char));
+ if (str) {
+ if (msg&&val)
+ sprintf(str, "%s <%s: %s>", msg, type, val);
+ else if (msg)
+ sprintf(str, "%s <%s>", msg, type);
+ else if (val)
+ sprintf(str, "Python error %s: %s", type, val);
+ else
+ sprintf(str, "Python error %s", type);
+
+ pcilib_log_vmessage(file, line, flags, prio, str, va);
+ }
+ } else {
+ pcilib_log_vmessage(file, line, flags, prio, msg, va);
+ }
+ va_end(va);
+
+#ifdef HAVE_PYTHON
+ Py_XDECREF(pytype);
+ Py_XDECREF(pyval);
+ Py_XDECREF(pytraceback);
+#endif /* HAVE_PYTHON */
+}
+
+
int pcilib_init_py(pcilib_t *ctx) {
+#ifdef HAVE_PYTHON
ctx->py = (pcilib_py_t*)malloc(sizeof(pcilib_py_t));
if (!ctx->py) return PCILIB_ERROR_MEMORY;
- Py_Initialize();
+ memset(ctx->py, 0, sizeof(pcilib_py_t));
+ if(Py_IsInitialized())
+ ctx->py->finalyze = 1;
+ else {
+ Py_Initialize();
+
+ // Since python is being initializing from c programm, it needs to initialize threads to work properly with c threads
+ PyEval_InitThreads();
+ PyEval_ReleaseLock();
+ }
+
ctx->py->main_module = PyImport_AddModule("__parser__");
- if (!ctx->py->main_module)
+ if (!ctx->py->main_module) {
+ pcilib_python_error("Error importing python parser");
return PCILIB_ERROR_FAILED;
+ }
ctx->py->global_dict = PyModule_GetDict(ctx->py->main_module);
- if (!ctx->py->global_dict)
+ if (!ctx->py->global_dict) {
+ pcilib_python_error("Error locating global python dictionary");
+ return PCILIB_ERROR_FAILED;
+ }
+
+ PyObject *pywrap = PyImport_ImportModule("pcipywrap");
+ if (!pywrap) {
+ pcilib_python_error("Error importing pcilib python wrapper");
+ return PCILIB_ERROR_FAILED;
+ }
+
+ PyObject *mod_name = PyString_FromString("Pcipywrap");
+ ctx->py->pcilib_pywrap = PyObject_CallMethodObjArgs(pywrap, mod_name, PyCObject_FromVoidPtr(ctx, NULL), NULL);
+ Py_XDECREF(mod_name);
+
+ if (!ctx->py->pcilib_pywrap) {
+ pcilib_python_error("Error initializing python wrapper");
return PCILIB_ERROR_FAILED;
+ }
+#endif /* HAVE_PYTHON */
+
+ return 0;
+}
+
+int pcilib_py_add_script_dir(pcilib_t *ctx, const char *dir) {
+#ifdef HAVE_PYTHON
+ PyObject* pypath;
+ char *script_dir;
+
+ const char *model_dir = getenv("PCILIB_MODEL_DIR");
+ if (!model_dir) model_dir = PCILIB_MODEL_DIR;
+
+ if (!dir) dir = ctx->model;
+
+ if (*dir == '/') {
+ script_dir = (char*)dir;
+ } else {
+ script_dir = alloca(strlen(model_dir) + strlen(dir) + 2);
+ if (!script_dir) return PCILIB_ERROR_MEMORY;
+ sprintf(script_dir, "%s/%s", model_dir, dir);
+ }
+
+ pypath = PySys_GetObject("path");
+ if (!pypath) {
+ pcilib_python_error("Can't get python path");
+ return PCILIB_ERROR_FAILED;
+ }
+
+ // Shall we check if the directory already in the path?
+ if(PyList_Append(pypath, PyString_FromString(script_dir)) == -1) {
+ pcilib_python_error("Can't add directory (%s) to python path", script_dir);
+ return PCILIB_ERROR_FAILED;
+ }
+#endif /* HAVE_PYTHON */
return 0;
}
void pcilib_free_py(pcilib_t *ctx) {
- if (ctx->py) {
- // Dict and module references are borrowed
+#ifdef HAVE_PYTHON
+ int finalyze = 0;
+
+ if (ctx->py) {
+ if(ctx->py->finalyze) finalyze = 1;
+
+ if (ctx->py->script_hash) {
+ pcilib_script_t *script, *script_tmp;
+
+ HASH_ITER(hh, ctx->py->script_hash, script, script_tmp) {
+ HASH_DEL(ctx->py->script_hash, script);
+ free(script);
+ }
+ ctx->py->script_hash = NULL;
+ }
+
free(ctx->py);
ctx->py = NULL;
}
+
+ if (finalyze)
+ Py_Finalize();
+#endif /* HAVE_PYTHON */
+}
+
+int pcilib_py_load_script(pcilib_t *ctx, const char *script_name) {
+#ifdef HAVE_PYTHON
+ PyObject* pymodule;
+ pcilib_script_t *module = NULL;
+
+
+ char *module_name = strdupa(script_name);
+ if (!module_name) return PCILIB_ERROR_MEMORY;
+
+ char *py = strrchr(module_name, '.');
+ if ((!py)||(strcasecmp(py, ".py"))) {
+ pcilib_error("Invalid script name (%s) is specified", script_name);
+ return PCILIB_ERROR_INVALID_ARGUMENT;
+ }
+ *py = 0;
+
+ HASH_FIND_STR(ctx->py->script_hash, script_name, module);
+ if (module) return 0;
+
+ pymodule = PyImport_ImportModule(module_name);
+ if (!pymodule) {
+ pcilib_python_error("Error importing script (%s)", script_name);
+ return PCILIB_ERROR_FAILED;
+ }
+
+ module = (pcilib_script_t*)malloc(sizeof(pcilib_script_t));
+ if (!module) return PCILIB_ERROR_MEMORY;
- Py_Finalize();
+ module->module = pymodule;
+ module->name = script_name;
+ HASH_ADD_KEYPTR(hh, ctx->py->script_hash, module->name, strlen(module->name), module);
+#endif /* HAVE_PYTHON */
+ return 0;
}
-/*
-static int pcilib_py_realloc_string(pcilib_t *ctx, size_t required, size_t *size, char **str) {
- char *ptr;
- size_t cur = *size;
+int pcilib_py_get_transform_script_properties(pcilib_t *ctx, const char *script_name, pcilib_access_mode_t *mode_ret) {
+ pcilib_access_mode_t mode = 0;
+
+#ifdef HAVE_PYTHON
+ PyObject *dict;
+ PyObject *pystr;
+ pcilib_script_t *module;
+
+ HASH_FIND_STR(ctx->py->script_hash, script_name, module);
+
+ if(!module) {
+ pcilib_error("Script (%s) is not loaded yet", script_name);
+ return PCILIB_ERROR_NOTFOUND;
+ }
+
+ dict = PyModule_GetDict(module->module);
+ if (!dict) {
+ pcilib_python_error("Error getting dictionary for script (%s)", script_name);
+ return PCILIB_ERROR_FAILED;
+ }
- if ((required + 1) > cur) {
- while (cur < required) cur *= 2;
- ptr = (char*)realloc(*str, cur);
- if (!ptr) return PCILIB_ERROR_MEMORY;
- *size = cur;
- *str = ptr;
- }
- ]
+ pystr = PyString_FromString("read_from_register");
+ if (pystr) {
+ if (PyDict_Contains(dict, pystr)) mode |= PCILIB_ACCESS_R;
+ Py_XDECREF(pystr);
+ }
+
+ pystr = PyString_FromString("write_to_register");
+ if (pystr) {
+ if (PyDict_Contains(dict, pystr)) mode |= PCILIB_ACCESS_W;
+ Py_XDECREF(pystr);
+ }
+#endif /* HAVE_PYTHON */
+
+ if (mode_ret) *mode_ret = mode;
return 0;
}
-*/
+pcilib_py_object *pcilib_get_value_as_pyobject(pcilib_t* ctx, pcilib_value_t *val, int *ret) {
+#ifdef HAVE_PYTHON
+ int err = 0;
+ PyObject *res = NULL;
+
+ long ival;
+ double fval;
+
+ switch(val->type) {
+ case PCILIB_TYPE_LONG:
+ ival = pcilib_get_value_as_int(ctx, val, &err);
+ if (!err) res = (PyObject*)PyInt_FromLong(ival);
+ break;
+ case PCILIB_TYPE_DOUBLE:
+ fval = pcilib_get_value_as_float(ctx, val, &err);
+ if (!err) res = (PyObject*)PyFloat_FromDouble(fval);
+ break;
+ default:
+ err = PCILIB_ERROR_NOTSUPPORTED;
+ pcilib_error("Can't convert pcilib value of type (%lu) to PyObject", val->type);
+ }
+
+ if (err) {
+ if (ret) *ret = err;
+ return NULL;
+ } else if (!res) {
+ if (ret) *ret = PCILIB_ERROR_MEMORY;
+ return res;
+ }
+
+ if (ret) *ret = 0;
+ return res;
+#else /* HAVE_PYTHON */
+ pcilib_error("Python is not supported");
+ return NULL;
+#endif /* HAVE_PYTHON */
+}
+
+int pcilib_set_value_from_pyobject(pcilib_t* ctx, pcilib_value_t *val, pcilib_py_object *pval) {
+#ifdef HAVE_PYTHON
+ int err = 0;
+ PyObject *pyval = (PyObject*)pval;
+
+ if (PyInt_Check(pyval)) {
+ err = pcilib_set_value_from_int(ctx, val, PyInt_AsLong(pyval));
+ } else if (PyFloat_Check(pyval)) {
+ err = pcilib_set_value_from_float(ctx, val, PyFloat_AsDouble(pyval));
+ } else if (PyString_Check(pyval)) {
+ err = pcilib_set_value_from_string(ctx, val, PyString_AsString(pyval));
+ } else {
+ pcilib_error("Can't convert PyObject to polymorphic pcilib value");
+ err = PCILIB_ERROR_NOTSUPPORTED;
+ }
+
+ return err;
+#else /* HAVE_PYTHON */
+ pcilib_error("Python is not supported");
+ return PCILIB_ERROR_NOTSUPPORTED;
+#endif /* HAVE_PYTHON */
+}
+
+#ifdef HAVE_PYTHON
static char *pcilib_py_parse_string(pcilib_t *ctx, const char *codestr, pcilib_value_t *value) {
int i;
int err = 0;
@@ -166,8 +433,10 @@ static char *pcilib_py_parse_string(pcilib_t *ctx, const char *codestr, pcilib_v
return dst;
}
+#endif /* HAVE_PYTHON */
int pcilib_py_eval_string(pcilib_t *ctx, const char *codestr, pcilib_value_t *value) {
+#ifdef HAVE_PYTHON
PyGILState_STATE gstate;
char *code;
PyObject* obj;
@@ -189,4 +458,57 @@ int pcilib_py_eval_string(pcilib_t *ctx, const char *codestr, pcilib_value_t *va
pcilib_debug(VIEWS, "Evaluating a Python string \'%s\' to %lf=\'%s\'", codestr, PyFloat_AsDouble(obj), code);
return pcilib_set_value_from_float(ctx, value, PyFloat_AsDouble(obj));
+#else /* HAVE_PYTHON */
+ pcilib_error("Current build not support python.");
+ return PCILIB_ERROR_NOTAVAILABLE;
+#endif /* HAVE_PYTHON */
+}
+
+int pcilib_py_eval_func(pcilib_t *ctx, const char *script_name, const char *func_name, pcilib_value_t *val) {
+#ifdef HAVE_PYTHON
+ int err = 0;
+ PyObject *pyfunc;
+ PyObject *pyval = NULL, *pyret;
+ pcilib_script_t *module = NULL;
+
+ HASH_FIND_STR(ctx->py->script_hash, script_name, module);
+
+ if (!module) {
+ pcilib_error("Script (%s) is not loaded", script_name);
+ return PCILIB_ERROR_NOTFOUND;
+ }
+
+ if (val) {
+ pyval = pcilib_get_value_as_pyobject(ctx, val, &err);
+ if (err) return err;
+ }
+
+ pyfunc = PyUnicode_FromString(func_name);
+ if (!pyfunc) {
+ if (pyval) Py_XDECREF(pyval);
+ return PCILIB_ERROR_MEMORY;
+ }
+
+ PyGILState_STATE gstate = PyGILState_Ensure();
+ pyret = PyObject_CallMethodObjArgs(module->module, pyfunc, ctx->py->pcilib_pywrap, pyval, NULL);
+ PyGILState_Release(gstate);
+
+ Py_XDECREF(pyfunc);
+ Py_XDECREF(pyval);
+
+ if (!pyret) {
+ pcilib_python_error("Error executing function (%s) of python script (%s)", func_name, script_name);
+ return PCILIB_ERROR_FAILED;
+ }
+
+ if ((val)&&(pyret != Py_None))
+ err = pcilib_set_value_from_pyobject(ctx, val, pyret);
+
+ Py_XDECREF(pyret);
+
+ return err;
+#else /* HAVE_PYTHON */
+ pcilib_error("Python is not supported");
+ return PCILIB_ERROR_NOTSUPPORTED;
+#endif /* HAVE_PYTHON */
}
diff --git a/pcilib/py.h b/pcilib/py.h
index 21c31e9..c372a09 100644
--- a/pcilib/py.h
+++ b/pcilib/py.h
@@ -1,16 +1,123 @@
#ifndef _PCILIB_PY_H
#define _PCILIB_PY_H
+#include <pcilib.h>
+#include <pcilib/error.h>
+
+#define pcilib_python_error(...) pcilib_log_python_error(__FILE__, __LINE__, PCILIB_LOG_DEFAULT, PCILIB_LOG_ERROR, __VA_ARGS__)
+
typedef struct pcilib_py_s pcilib_py_t;
+typedef void pcilib_py_object;
#ifdef __cplusplus
extern "C" {
#endif
+void pcilib_log_python_error(const char *file, int line, pcilib_log_flags_t flags, pcilib_log_priority_t prio, const char *msg, ...);
+
+/** Initializes Python engine
+ *
+ * This function will return success if Python support is disabled. Only functions
+ * executing python call, like pcilib_py_eval_string(), return errors. Either way,
+ * no script directories are configured. The pcilib_add_script_dir() call is used
+ * for this purpose.
+ *
+ * @param[in,out] ctx - pcilib context
+ * @return - error or 0 on success
+ */
int pcilib_init_py(pcilib_t *ctx);
-int pcilib_py_eval_string(pcilib_t *ctx, const char *codestr, pcilib_value_t *value);
+
+/** Cleans up memory used by various python structures
+ * and finalyzes python environment if pcilib is not started from python script
+ *
+ * @param[in] ctx - the pcilib_t context
+ */
void pcilib_free_py(pcilib_t *ctx);
+/** Add an additional path to look for python scripts
+ *
+ * The default location for python files is /usr/local/share/pcilib/models/@b{model}.
+ * This can be altered using CMake PCILIB_MODEL_DIR variable while building or using
+ * PCILIB_MODEL_DIR environmental variable dynamicly. The default location is added
+ * with @b{location} = NULL. Additional directories can be added as well either
+ * by specifying relative path from the default directory or absolute path in the
+ * system.
+ *
+ * @param[in,out] ctx - pcilib context
+ * @param[in] location - NULL or path to additional scripts
+ * @return - error or 0 on success
+ */
+int pcilib_py_add_script_dir(pcilib_t *ctx, const char *location);
+
+/** Loads the specified python script
+ *
+ * Once loaded the script is available until pcilib context is destryoed.
+ *
+ * @param[in,out] ctx - pcilib context
+ * @param[in] name - script name, the passed variable is referenced and, hence, should have static duration
+ * @return - error or 0 on success
+ */
+int pcilib_py_load_script(pcilib_t *ctx, const char *name);
+
+/** Check if the specified script can be used as transform view and detects transform configuration
+ *
+ * @param[in,out] ctx - pcilib context
+ * @param[in] name - script name
+ * @param[out] mode - supported access mode (read/write/read-write)
+ * @return - error or 0 on success
+ */
+int pcilib_py_get_transform_script_properties(pcilib_t *ctx, const char *name, pcilib_access_mode_t *mode);
+
+/**
+ * Get the PyObject from the polymorphic type. The returned value should be cleaned with Py_XDECREF()
+ * @param[in] ctx - pcilib context
+ * @param[in] val - initialized polymorphic value of arbitrary type
+ * @param[out] err - error code or 0 on sccuess
+ * @return - valid PyObject or NULL in the case of error
+ */
+pcilib_py_object *pcilib_get_value_as_pyobject(pcilib_t* ctx, pcilib_value_t *val, int *err);
+
+/**
+ * Initializes the polymorphic value from PyObject. If `val` already contains the value, cleans it first.
+ * Therefore, before first usage the value should be always initialized to 0.
+ * @param[in] ctx - pcilib context
+ * @param[in,out] val - initialized polymorphic value
+ * @param[in] pyval - valid PyObject* containing PyInt, PyFloat, or PyString
+ * @return - 0 on success or memory error
+ */
+int pcilib_set_value_from_pyobject(pcilib_t* ctx, pcilib_value_t *val, pcilib_py_object *pyval);
+
+/** Evaluates the specified python code and returns result in @b{val}
+ *
+ * The python code may include special variables which will be substituted by pcitool before executing Python interpreter
+ * @b{$value} - will be replaced by the current value of the @b{val} parameter
+ * @b{$reg} - will be replaced by the current value of the specified register @b{reg}
+ * @b{${/prop/temp}} - will be replaced by the current value of the specified property @b{/prop/temp}
+ * @b{${/prop/temp:C}} - will be replaced by the current value of the specified property @b{/prop/temp} in the given units
+
+ * @param[in,out] ctx - pcilib context
+ * @param[in] codestr - python code to evaluate
+ * @param[in,out] val - Should contain the value which will be substituted in place of @b{$value} and on
+ * successful execution will contain the computed value
+ * @return - error or 0 on success
+ */
+int pcilib_py_eval_string(pcilib_t *ctx, const char *codestr, pcilib_value_t *val);
+
+/** Execute the specified function in the Python script which was loaded with pcilib_py_load_script() call
+ *
+ * The function is expected to accept two paramters. The first parameter is pcipywrap context and the @b{val}
+ * is passed as the second parameter. The return value of the script will be returned in the @b{val} as well.
+ * If function returns Py_None, the value of @b{val} will be unchanged.
+ *
+ * @param[in,out] ctx - pcilib context
+ * @param[in] script - script name
+ * @param[in] func - function name
+ * @param[in,out] val - Should contain the value of second parameter of the function before call and on
+ * successful return will contain the returned value
+ * @return - error or 0 on success
+ */
+int pcilib_py_eval_func(pcilib_t *ctx, const char *script, const char *func, pcilib_value_t *val);
+
#ifdef __cplusplus
}
#endif
diff --git a/pcilib/value.c b/pcilib/value.c
index 6e65307..e8268e9 100644
--- a/pcilib/value.c
+++ b/pcilib/value.c
@@ -1,3 +1,4 @@
+#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -71,6 +72,27 @@ int pcilib_set_value_from_static_string(pcilib_t *ctx, pcilib_value_t *value, co
return 0;
}
+int pcilib_set_value_from_string(pcilib_t *ctx, pcilib_value_t *value, const char *str) {
+ size_t len;
+
+ pcilib_clean_value(ctx, value);
+
+ len = strlen(str) + 1;
+ if (len < sizeof(value->str)) {
+ memcpy(value->str, str, len);
+ value->sval = value->str;
+ } else {
+ value->data = (void*)strdup(str);
+ if (!value->data) return PCILIB_ERROR_MEMORY;
+
+ value->size = strlen(str) + 1;
+ value->sval = value->data;
+ }
+ value->type = PCILIB_TYPE_STRING;
+
+ return 0;
+}
+
double pcilib_get_value_as_float(pcilib_t *ctx, const pcilib_value_t *val, int *ret) {
int err;
double res;
diff --git a/pcilib/view.c b/pcilib/view.c
index e31fdba..985c1b2 100644
--- a/pcilib/view.c
+++ b/pcilib/view.c
@@ -69,8 +69,11 @@ int pcilib_add_views_custom(pcilib_t *ctx, size_t n, const pcilib_view_descripti
return PCILIB_ERROR_MEMORY;
}
+ memcpy(cur, v, v->api->description_size);
+ ctx->views[ctx->num_views + i] = cur;
+
if (v->api->init)
- view_ctx = v->api->init(ctx);
+ view_ctx = v->api->init(ctx, ctx->num_views + i);
else {
view_ctx = (pcilib_view_context_t*)malloc(sizeof(pcilib_view_context_t));
if (view_ctx) memset(view_ctx, 0, sizeof(pcilib_view_context_t));
@@ -83,14 +86,12 @@ int pcilib_add_views_custom(pcilib_t *ctx, size_t n, const pcilib_view_descripti
return PCILIB_ERROR_FAILED;
}
- memcpy(cur, v, v->api->description_size);
- view_ctx->view = ctx->num_views + i;
+ view_ctx->view = ctx->num_views + i;
view_ctx->name = v->name;
- if (refs) refs[i] = view_ctx;
-
HASH_ADD_KEYPTR(hh, ctx->view_hash, view_ctx->name, strlen(view_ctx->name), view_ctx);
- ctx->views[ctx->num_views + i] = cur;
+
+ if (refs) refs[i] = view_ctx;
ptr += v->api->description_size;
}
diff --git a/pcilib/view.h b/pcilib/view.h
index 33d4d96..8b1c07c 100644
--- a/pcilib/view.h
+++ b/pcilib/view.h
@@ -19,7 +19,7 @@ typedef enum {
typedef struct {
pcilib_version_t version; /**< Version */
size_t description_size; /**< The actual size of the description */
- pcilib_view_context_t *(*init)(pcilib_t *ctx); /**< Optional function which should allocated context used by read/write functions */
+ pcilib_view_context_t *(*init)(pcilib_t *ctx, pcilib_view_t view); /**< Optional function which should allocated context used by read/write functions */
void (*free)(pcilib_t *ctx, pcilib_view_context_t *view); /**< Optional function which should clean context */
void (*free_description)(pcilib_t *ctx, pcilib_view_description_t *view); /**< Optional function which shoud clean required parts of the extended description if non-static memory was used to initialize it */
int (*read_from_reg)(pcilib_t *ctx, pcilib_view_context_t *view, pcilib_register_value_t regval, pcilib_value_t *val); /**< Function which computes view value based on the passed the register value (view-based properties should not use register value) */
diff --git a/pcilib/xml.c b/pcilib/xml.c
index 50aaa35..fd12636 100644
--- a/pcilib/xml.c
+++ b/pcilib/xml.c
@@ -40,6 +40,7 @@
#include "xml.h"
#include "error.h"
#include "view.h"
+#include "py.h"
#include "views/enum.h"
#include "views/transform.h"
@@ -48,11 +49,11 @@
#define REGISTERS_PATH ((xmlChar*)"./register") /**< all standard registers nodes */
#define BIT_REGISTERS_PATH ((xmlChar*)"./field") /**< all bits registers nodes */
#define REGISTER_VIEWS_PATH ((xmlChar*)"./view") /**< supported register & field views */
-#define TRANSFORM_VIEWS_PATH ((xmlChar*)"/model/transform") /**< path to complete nodes of views */
+#define TRANSFORM_VIEWS_PATH ((xmlChar*)"/model/transform") /**< path to complete nodes of views */
#define ENUM_VIEWS_PATH ((xmlChar*)"/model/enum") /**< path to complete nodes of views */
#define ENUM_ELEMENTS_PATH ((xmlChar*)"./name") /**< all elements in the enum */
#define UNITS_PATH ((xmlChar*)"/model/unit") /**< path to complete nodes of units */
-#define UNIT_TRANSFORMS_PATH ((xmlChar*)"./transform") /**< all transforms of the unit */
+#define UNIT_TRANSFORMS_PATH ((xmlChar*)"./transform") /**< all transforms of the unit */
@@ -492,6 +493,8 @@ static int pcilib_xml_parse_view(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDoc
xmlAttrPtr cur;
const char *value, *name;
+ int inconsistent = (desc->mode & PCILIB_ACCESS_INCONSISTENT);
+
for (cur = node->properties; cur != NULL; cur = cur->next) {
if (!cur->children) continue;
if (!xmlNodeIsText(cur->children)) continue;
@@ -537,8 +540,14 @@ static int pcilib_xml_parse_view(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDoc
pcilib_error("Invalid access mode (%s) is specified in the XML register description", value);
return PCILIB_ERROR_INVALID_DATA;
}
- }
+ } else if (!strcasecmp(name, "write_verification")) {
+ if (strcmp(value, "0")) inconsistent = 0;
+ else inconsistent = 1;
+ }
}
+
+ if (inconsistent) desc->mode |= PCILIB_ACCESS_INCONSISTENT;
+ else desc->mode &= ~PCILIB_ACCESS_INCONSISTENT;
return 0;
}
@@ -585,10 +594,12 @@ static int pcilib_xml_create_transform_view(pcilib_t *ctx, xmlXPathContextPtr xp
}
desc.write_to_reg = value;
if ((value)&&(*value)) mode |= PCILIB_ACCESS_W;
- }
+ } else if (!strcasecmp(name, "script")) {
+ desc.script = value;
+ break;
+ }
}
-
- desc.base.mode &= mode;
+ desc.base.mode &= (~PCILIB_ACCESS_RW)|mode;
err = pcilib_add_views_custom(ctx, 1, (pcilib_view_description_t*)&desc, &view_ctx);
if (err) return err;
@@ -597,7 +608,6 @@ static int pcilib_xml_create_transform_view(pcilib_t *ctx, xmlXPathContextPtr xp
return 0;
}
-
static int pcilib_xml_parse_value_name(pcilib_t *ctx, xmlXPathContextPtr xpath, xmlDocPtr doc, xmlNodePtr node, pcilib_register_value_name_t *desc) {
xmlAttr *cur;
char *value, *name;