diff options
Diffstat (limited to 'pcilib')
-rw-r--r-- | pcilib/CMakeLists.txt | 4 | ||||
-rw-r--r-- | pcilib/config.h.in | 1 | ||||
-rw-r--r-- | pcilib/error.c | 12 | ||||
-rw-r--r-- | pcilib/error.h | 14 | ||||
-rw-r--r-- | pcilib/pci.c | 15 | ||||
-rw-r--r-- | pcilib/pcilib.h | 14 | ||||
-rw-r--r-- | pcilib/property.c | 5 | ||||
-rw-r--r-- | pcilib/py.c | 433 | ||||
-rw-r--r-- | pcilib/py.h | 109 | ||||
-rw-r--r-- | pcilib/value.c | 22 | ||||
-rw-r--r-- | pcilib/view.c | 13 | ||||
-rw-r--r-- | pcilib/view.h | 2 | ||||
-rw-r--r-- | pcilib/xml.c | 30 |
13 files changed, 623 insertions, 51 deletions
diff --git a/pcilib/CMakeLists.txt b/pcilib/CMakeLists.txt index a7557b7..27543e4 100644 --- a/pcilib/CMakeLists.txt +++ b/pcilib/CMakeLists.txt @@ -8,7 +8,7 @@ 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 build.h) +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 config.h version.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 build dma protocols views) @@ -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/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 6ec8c9d..ec40c95 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..3e1f38d 100644 --- a/pcilib/py.c +++ b/pcilib/py.c @@ -1,10 +1,14 @@ -#include <Python.h> +#include "config.h" + +#ifdef HAVE_PYTHON +# include <Python.h> +#endif /* HAVE_PYTHON */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <strings.h> - +#include <alloca.h> #include "pci.h" #include "debug.h" @@ -12,55 +16,370 @@ #include "py.h" #include "error.h" +#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 + PyGILState_STATE gstate; + PyObject *pytype = NULL; + PyObject *pyval = NULL; + PyObject *pytraceback = NULL; + + + gstate = PyGILState_Ensure(); + if (PyErr_Occurred()) { + PyErr_Fetch(&pytype, &pyval, &pytraceback); + type = PyString_AsString(pytype); + val = PyString_AsString(pyval); + } + PyGILState_Release(gstate); +#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 + if (pytype) Py_DECREF(pytype); + if (pyval) Py_DECREF(pyval); + if (pytraceback) Py_DECREF(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()) { + 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->finalyze = 1; + } + 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"); + PyObject *pyctx = PyCObject_FromVoidPtr(ctx, NULL); + ctx->py->pcilib_pywrap = PyObject_CallMethodObjArgs(pywrap, mod_name, pyctx, NULL); + Py_XDECREF(pyctx); + 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 + int err = 0; + PyObject *pypath, *pynewdir; + PyObject *pydict, *pystr, *pyret = NULL; + 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; + } + + pynewdir = PyString_FromString(script_dir); + if (!pynewdir) { + pcilib_python_error("Can't create python string"); + return PCILIB_ERROR_MEMORY; + } + + // Checking if the directory already in the path? + pydict = PyDict_New(); + if (pydict) { + pystr = PyString_FromString("cur"); + if (pystr) { + PyDict_SetItem(pydict, pystr, pynewdir); + Py_DECREF(pystr); + } + + pystr = PyString_FromString("path"); + if (pystr) { + PyDict_SetItem(pydict, pystr, pypath); + Py_DECREF(pystr); + } + + pyret = PyRun_String("cur in path", Py_eval_input, ctx->py->global_dict, pydict); + Py_DECREF(pydict); + } + + if ((pyret == Py_False)&&(PyList_Append(pypath, pynewdir) == -1)) + err = PCILIB_ERROR_FAILED; + + if (pyret) Py_DECREF(pyret); + Py_DECREF(pynewdir); + + if (err) { + pcilib_python_error("Can't add directory (%s) to python path", script_dir); + return err; + } +#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) { + Py_DECREF(script->module); + HASH_DEL(ctx->py->script_hash, script); + free(script); + } + ctx->py->script_hash = NULL; + } + + if (ctx->py->pcilib_pywrap) + Py_DECREF(ctx->py->pcilib_pywrap); + 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; + } - Py_Finalize(); + 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; } -/* -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_DECREF(pystr); + } + + pystr = PyString_FromString("write_to_register"); + if (pystr) { + if (PyDict_Contains(dict, pystr)) mode |= PCILIB_ACCESS_W; + Py_DECREF(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; + PyGILState_STATE gstate; + + long ival; + double fval; + + gstate = PyGILState_Ensure(); + 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: + PyGILState_Release(gstate); + pcilib_error("Can't convert pcilib value of type (%lu) to PyObject", val->type); + if (ret) *ret = PCILIB_ERROR_NOTSUPPORTED; + return NULL; + } + PyGILState_Release(gstate); + + 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; + PyGILState_STATE gstate; + + gstate = PyGILState_Ensure(); + 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 { + PyGILState_Release(gstate); + pcilib_error("Can't convert PyObject to polymorphic pcilib value"); + return PCILIB_ERROR_NOTSUPPORTED; + } + PyGILState_Release(gstate); + + 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 +485,12 @@ 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 + int err; + PyGILState_STATE gstate; char *code; PyObject* obj; @@ -184,9 +507,71 @@ int pcilib_py_eval_string(pcilib_t *ctx, const char *codestr, pcilib_value_t *va if (!obj) { pcilib_error("Failed to run the Python code: %s", code); + free(code); return PCILIB_ERROR_FAILED; } 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)); + err = pcilib_set_value_from_float(ctx, value, PyFloat_AsDouble(obj)); + + Py_DECREF(obj); + free(code); + + return err; +#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; + } + + PyGILState_STATE gstate = PyGILState_Ensure(); + + pyfunc = PyUnicode_FromString(func_name); + if (!pyfunc) { + if (pyval) Py_DECREF(pyval); + PyGILState_Release(gstate); + return PCILIB_ERROR_MEMORY; + } + + pyret = PyObject_CallMethodObjArgs(module->module, pyfunc, ctx->py->pcilib_pywrap, pyval, NULL); + + Py_DECREF(pyfunc); + Py_DECREF(pyval); + + if (!pyret) { + PyGILState_Release(gstate); + 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_DECREF(pyret); + PyGILState_Release(gstate); + + 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..b980a83 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; @@ -605,7 +615,7 @@ static int pcilib_xml_parse_value_name(pcilib_t *ctx, xmlXPathContextPtr xpath, int min_set = 0, max_set = 0; pcilib_register_value_t val; - + for (cur = node->properties; cur != NULL; cur = cur->next) { if(!cur->children) continue; if(!xmlNodeIsText(cur->children)) continue; @@ -703,7 +713,7 @@ static int pcilib_xml_create_enum_view(pcilib_t *ctx, xmlXPathContextPtr xpath, pcilib_error("No names is defined for enum view (%s)", desc.base.name); return PCILIB_ERROR_INVALID_DATA; } - + memset(desc.names, 0, (nodeset->nodeNr + 1) * sizeof(pcilib_register_value_name_t)); for (i = 0; i < nodeset->nodeNr; i++) { err = pcilib_xml_parse_value_name(ctx, xpath, doc, nodeset->nodeTab[i], &desc.names[i]); @@ -713,11 +723,9 @@ static int pcilib_xml_create_enum_view(pcilib_t *ctx, xmlXPathContextPtr xpath, return err; } } - memset(&desc.names[nodeset->nodeNr], 0, sizeof(pcilib_register_value_name_t)); xmlXPathFreeObject(nodes); - err = pcilib_add_views_custom(ctx, 1, (pcilib_view_description_t*)&desc, &view_ctx); if (err) { free(desc.names); |