From 21812f8d763fac8ee9bb3fdc593642b06f405a2b Mon Sep 17 00:00:00 2001 From: "Suren A. Chilingaryan" Date: Thu, 8 Oct 2015 20:04:37 +0200 Subject: Base functions for views --- pcilib/CMakeLists.txt | 6 +- pcilib/export.c | 4 + pcilib/export.h | 2 + pcilib/pci.c | 12 ++- pcilib/pci.h | 7 +- pcilib/pcilib.h | 38 +++++++-- pcilib/py.c | 171 +++++++++++++++++++++++++++++++++++++ pcilib/py.h | 19 +++++ pcilib/unit.c | 55 +++++++++++- pcilib/unit.h | 17 +++- pcilib/value.c | 168 ++++++++++++++++++++++++++++++++++++ pcilib/value.h | 15 ++++ pcilib/view.c | 230 +++++++++++++++++++++++++++++++++++++++++++++++--- pcilib/view.h | 14 ++- 14 files changed, 721 insertions(+), 37 deletions(-) create mode 100644 pcilib/py.c create mode 100644 pcilib/py.h create mode 100644 pcilib/value.c create mode 100644 pcilib/value.h (limited to 'pcilib') diff --git a/pcilib/CMakeLists.txt b/pcilib/CMakeLists.txt index beaa253..3fc789e 100644 --- a/pcilib/CMakeLists.txt +++ b/pcilib/CMakeLists.txt @@ -4,12 +4,12 @@ include_directories( ${CMAKE_SOURCE_DIR}/pcilib ${CMAKE_BINARY_DIR}/pcilib ${LIBXML2_INCLUDE_DIRS} - ${PYTHON_INCLUDE_DIRS} + ${PYTHON_INCLUDE_DIR} ${UTHASH_INCLUDE_DIRS} ) -set(HEADERS pcilib.h pci.h export.h bar.h fifo.h model.h bank.h register.h view.h unit.h xml.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 export.c bar.c fifo.c model.c bank.c register.c view.c unit.c xml.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 export.h value.h bar.h fifo.h model.h bank.h register.h view.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 export.c value.c bar.c fifo.c model.c bank.c register.c view.c unit.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) diff --git a/pcilib/export.c b/pcilib/export.c index 7b78e32..ffb1c4b 100644 --- a/pcilib/export.c +++ b/pcilib/export.c @@ -4,6 +4,10 @@ #include "export.h" + +const char *pcilib_data_types[] = { "default", "string", "double", "long" }; + + #include "protocols/default.h" #include "protocols/software.h" diff --git a/pcilib/export.h b/pcilib/export.h index e2e6eca..6fb08c3 100644 --- a/pcilib/export.h +++ b/pcilib/export.h @@ -6,6 +6,8 @@ #include #include +extern const char *pcilib_data_types[]; + extern const pcilib_register_protocol_description_t pcilib_protocols[]; extern const pcilib_dma_description_t pcilib_dma[]; diff --git a/pcilib/pci.c b/pcilib/pci.c index 5c25473..0ba5f51 100644 --- a/pcilib/pci.c +++ b/pcilib/pci.c @@ -137,6 +137,13 @@ pcilib_t *pcilib_open(const char *device, const char *model) { pcilib_close(ctx); return NULL; } + + err = pcilib_init_py(ctx); + if (err) { + pcilib_error("Error (%i) initializing python subsystem", err); + pcilib_close(ctx); + return NULL; + } ctx->alloc_reg = PCILIB_DEFAULT_REGISTER_SPACE; ctx->alloc_views = PCILIB_DEFAULT_VIEW_SPACE; @@ -152,10 +159,9 @@ pcilib_t *pcilib_open(const char *device, const char *model) { return NULL; } - memset(ctx->registers, 0, sizeof(pcilib_register_description_t)); memset(ctx->units, 0, sizeof(pcilib_unit_t)); - memset(ctx->views, 0, sizeof(pcilib_view_t)); + memset(ctx->views, 0, sizeof(pcilib_view_t*)); memset(ctx->banks, 0, sizeof(pcilib_register_bank_description_t)); memset(ctx->ranges, 0, sizeof(pcilib_register_range_t)); @@ -391,6 +397,8 @@ 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); diff --git a/pcilib/pci.h b/pcilib/pci.h index ab80101..88327b3 100644 --- a/pcilib/pci.h +++ b/pcilib/pci.h @@ -30,6 +30,7 @@ #include "export.h" #include "locking.h" #include "xml.h" +#include "py.h" #include "view.h" typedef struct { @@ -41,14 +42,13 @@ typedef struct { struct pcilib_view_context_s { UT_hash_handle hh; pcilib_view_t view; - pcilib_view_api_description_t *api; - pcilib_view_description_t desc; /**< We will allocate more memory and store actual description instance here, so it should be the last member */ +// pcilib_view_description_t desc; /**< We will allocate more memory and store actual description instance here, so it should be the last member */ }; struct pcilib_unit_context_s { UT_hash_handle hh; pcilib_unit_t unit; - pcilib_unit_description_t desc; +// pcilib_unit_description_t desc; }; typedef struct { @@ -109,6 +109,7 @@ struct pcilib_s { struct pcilib_locking_s locks; /**< Context of locking subsystem */ struct pcilib_xml_s xml; /**< XML context */ + struct pcilib_py_s *py; /**< Python execution context */ #ifdef PCILIB_FILE_IO int file_io_handle; diff --git a/pcilib/pcilib.h b/pcilib/pcilib.h index 8e55d00..3909ab4 100644 --- a/pcilib/pcilib.h +++ b/pcilib/pcilib.h @@ -41,10 +41,12 @@ typedef enum { } pcilib_endianess_t; typedef enum { - PCILIB_TYPE_STRING = 0, /**< char* */ - PCILIB_TYPE_DOUBLE = 1, /**< double */ - PCILIB_TYPE_LONG = 2 -} pcilib_data_type_t; + PCILIB_TYPE_INVALID = 0, /**< uninitialized */ + PCILIB_TYPE_DEFAULT = 0, /**< default type */ + PCILIB_TYPE_STRING = 1, /**< char* */ + PCILIB_TYPE_DOUBLE = 2, /**< double */ + PCILIB_TYPE_LONG = 3 +} pcilib_value_type_t; typedef enum { PCILIB_DMA_IRQ = 1, @@ -102,6 +104,23 @@ typedef struct { pcilib_event_info_flags_t flags; /**< flags */ } pcilib_event_info_t; +typedef struct { + pcilib_value_type_t type; + const char *unit; + const char *format; + + union { + long ival; + double fval; + char *sval; + }; + + // This is a private part + size_t size; + void *data; + char str[16]; +} pcilib_value_t; + #define PCILIB_BAR_DETECT ((pcilib_bar_t)-1) #define PCILIB_BAR_INVALID ((pcilib_bar_t)-1) @@ -200,8 +219,15 @@ int pcilib_write_register_by_id(pcilib_t *ctx, pcilib_register_t reg, pcilib_reg int pcilib_read_register(pcilib_t *ctx, const char *bank, const char *regname, pcilib_register_value_t *value); int pcilib_write_register(pcilib_t *ctx, const char *bank, const char *regname, pcilib_register_value_t value); -int pcilib_read_register_view(pcilib_t *ctx, const char *bank, const char *regname, const char *unit, pcilib_data_type_t value_type, size_t value_size, void *value); -int pcilib_write_register_view(pcilib_t *ctx, const char *bank, const char *regname, const char *unit, pcilib_data_type_t value_type, size_t value_size, void *value); +void pcilib_clean_value(pcilib_t *ctx, pcilib_value_t *val); +int pcilib_copy_value(pcilib_t *ctx, pcilib_value_t *dst, const pcilib_value_t *src); +int pcilib_set_value_from_float(pcilib_t *ctx, pcilib_value_t *val, double fval); +int pcilib_set_value_from_int(pcilib_t *ctx, pcilib_value_t *val, long ival); +int pcilib_convert_value_unit(pcilib_t *ctx, pcilib_value_t *val, const char *unit_name); +int pcilib_convert_value_type(pcilib_t *ctx, pcilib_value_t *val, pcilib_value_type_t type); + +int pcilib_read_register_view(pcilib_t *ctx, const char *bank, const char *regname, const char *unit, pcilib_value_t *value); +int pcilib_write_register_view(pcilib_t *ctx, const char *bank, const char *regname, const char *unit, const pcilib_value_t *value); int pcilib_reset(pcilib_t *ctx); int pcilib_trigger(pcilib_t *ctx, pcilib_event_t event, size_t trigger_size, void *trigger_data); diff --git a/pcilib/py.c b/pcilib/py.c new file mode 100644 index 0000000..2248892 --- /dev/null +++ b/pcilib/py.c @@ -0,0 +1,171 @@ +#include + +#include +#include +#include +#include + + +#include "pci.h" +#include "pcilib.h" +#include "py.h" +#include "error.h" + +struct pcilib_py_s { + PyObject *main_module; + PyObject *global_dict; +}; + +int pcilib_init_py(pcilib_t *ctx) { + ctx->py = (pcilib_py_t*)malloc(sizeof(pcilib_py_t)); + if (!ctx->py) return PCILIB_ERROR_MEMORY; + + Py_Initialize(); + + ctx->py->main_module = PyImport_AddModule("__parser__"); + if (!ctx->py->main_module) + return PCILIB_ERROR_FAILED; + + ctx->py->global_dict = PyModule_GetDict(ctx->py->main_module); + if (!ctx->py->global_dict) + return PCILIB_ERROR_FAILED; + + return 0; +} + +void pcilib_free_py(pcilib_t *ctx) { + if (ctx->py) { + // Dict and module references are borrowed + free(ctx->py); + ctx->py = NULL; + } + + Py_Finalize(); +} + +/* +static int pcilib_py_realloc_string(pcilib_t *ctx, size_t required, size_t *size, char **str) { + char *ptr; + size_t cur = *size; + + if ((required + 1) > cur) { + while (cur < required) cur *= 2; + ptr = (char*)realloc(*str, cur); + if (!ptr) return PCILIB_ERROR_MEMORY; + *size = cur; + *str = ptr; + } + ] + return 0; +} +*/ + +static char *pcilib_py_parse_string(pcilib_t *ctx, const char *codestr, pcilib_value_t *value) { + int i; + int err = 0; + pcilib_value_t val; + pcilib_register_value_t regval; + + char save; + char *reg, *cur; + size_t offset = 0; + + size_t size; + char *src; + char *dst; + + size_t max_repl = 2 + 2 * sizeof(pcilib_value_t); // the text representation of largest integer + + if (value) { + err = pcilib_copy_value(ctx, &val, value); + if (err) return NULL; + + err = pcilib_convert_value_type(ctx, &val, PCILIB_TYPE_STRING); + if (err) return NULL; + + if (strlen(val.sval) > max_repl) + max_repl = strlen(val.sval); + } + + size = ((max_repl + 1) / 3 + 1) * strlen(codestr); // minimum register length is 3 symbols ($a + delimiter space), it is replaces with (max_repl+1) symbols + + src = strdup(codestr); + dst = (char*)malloc(size); // allocating maximum required space + + if ((!src)||(!dst)) { + if (src) free(src); + if (dst) free(dst); + pcilib_error("Failed to allocate memory for string formulas"); + return NULL; + } + + cur = src; + reg = strchr(src, '$'); + while (reg) { + strcpy(dst + offset, cur); + offset += reg - cur; + + // find the end of the register name + reg++; + for (i = 0; isalnum(reg[i]); i++); + save = reg[i]; + reg[i] = 0; + + // determine replacement value + if (!strcasecmp(reg, "value")) { + if (!value) { + pcilib_error("Python formula (%s) relies on the value of register, but it is not provided", codestr); + err = PCILIB_ERROR_INVALID_REQUEST; + break; + } + + strcpy(dst + offset, val.sval); + } else { + err = pcilib_read_register(ctx, NULL, reg, ®val); + if (err) break; + + sprintf(dst + offset, "0x%x", regval); + } + + offset += strlen(dst + offset); + reg[i] = save; + + // Advance to the next register if any + cur = reg + i; + reg = strchr(cur, '$'); + } + + strcpy(dst + offset, cur); + + free(src); + + if (err) { + free(dst); + return NULL; + } + + return dst; +} + +int pcilib_py_eval_string(pcilib_t *ctx, const char *codestr, pcilib_value_t *value) { + PyGILState_STATE gstate; + char *code; + PyObject* obj; + + code = pcilib_py_parse_string(ctx, codestr, value); + if (!code) { + pcilib_error("Failed to parse registers in the code: %s", codestr); + return PCILIB_ERROR_FAILED; + } + + gstate = PyGILState_Ensure(); + obj = PyRun_String(code, Py_eval_input, ctx->py->global_dict, ctx->py->global_dict); + PyGILState_Release(gstate); + + if (!obj) { + pcilib_error("Failed to run the Python code: %s", code); + return PCILIB_ERROR_FAILED; + } + + return pcilib_set_value_from_float(ctx, value, PyFloat_AsDouble(obj)); +} diff --git a/pcilib/py.h b/pcilib/py.h new file mode 100644 index 0000000..21c31e9 --- /dev/null +++ b/pcilib/py.h @@ -0,0 +1,19 @@ +#ifndef _PCILIB_PY_H +#define _PCILIB_PY_H + +typedef struct pcilib_py_s pcilib_py_t; + +#ifdef __cplusplus +extern "C" { +#endif + +int pcilib_init_py(pcilib_t *ctx); +int pcilib_py_eval_string(pcilib_t *ctx, const char *codestr, pcilib_value_t *value); +void pcilib_free_py(pcilib_t *ctx); + +#ifdef __cplusplus +} +#endif + + +#endif /* _PCILIB_PY_H */ diff --git a/pcilib/unit.c b/pcilib/unit.c index 2dd7113..6817afc 100644 --- a/pcilib/unit.c +++ b/pcilib/unit.c @@ -9,16 +9,38 @@ #include "error.h" -pcilib_unit_t pcilib_find_unit_by_name(pcilib_t *ctx, const char *unit) { +static pcilib_unit_transform_t pcilib_unit_transform_null = { NULL, NULL }; + +pcilib_unit_t pcilib_find_unit_by_name(pcilib_t *ctx, const char *name) { pcilib_unit_t i; for(i = 0; ctx->units[i].name; i++) { - if (!strcasecmp(ctx->units[i].name, unit)) + if (!strcasecmp(ctx->units[i].name, name)) return i; } return PCILIB_UNIT_INVALID; } +pcilib_unit_transform_t *pcilib_find_transform_by_unit_names(pcilib_t *ctx, const char *from, const char *to) { + int i; + pcilib_unit_t unit; + + if ((!from)||(!to)) + return NULL; + + if (!strcasecmp(from, to)) + return &pcilib_unit_transform_null; + + unit = pcilib_find_unit_by_name(ctx, from); + if (unit == PCILIB_UNIT_INVALID) return NULL; + + for (i = 0; ctx->units[unit].transforms[i].unit; i++) { + if (!strcasecmp(ctx->units[unit].transforms[i].unit, to)) + return &ctx->units[unit].transforms[i]; + } + + return NULL; +} int pcilib_add_units(pcilib_t *ctx, size_t n, const pcilib_unit_description_t *desc) { if (!n) { @@ -47,3 +69,32 @@ int pcilib_add_units(pcilib_t *ctx, size_t n, const pcilib_unit_description_t *d return 0; } + + +int pcilib_transform_unit(pcilib_t *ctx, pcilib_unit_transform_t *trans, pcilib_value_t *value) { + int err; + + err = pcilib_py_eval_string(ctx, trans->transform, value); + if (err) return err; + + value->unit = trans->unit; + return 0; +} + + +int pcilib_transform_unit_by_name(pcilib_t *ctx, const char *to, pcilib_value_t *value) { + pcilib_unit_transform_t *trans; + + if (!value->unit) { + pcilib_warning("Can't transform unit of the value with unspecified unit"); + return PCILIB_ERROR_INVALID_ARGUMENT; + } + + trans = pcilib_find_transform_by_unit_names(ctx, value->unit, to); + if (!trans) { + pcilib_warning("Can't transform unit (%s) to (%s)", value->unit, to); + return PCILIB_ERROR_NOTSUPPORTED; + } + + return pcilib_transform_unit(ctx, trans, value); +} diff --git a/pcilib/unit.h b/pcilib/unit.h index 9c62ff3..e0eeefc 100644 --- a/pcilib/unit.h +++ b/pcilib/unit.h @@ -4,6 +4,8 @@ #include #define PCILIB_UNIT_INVALID ((pcilib_unit_t)-1) +#define PCILIB_UNIT_TRANSFORM_INVALID ((pcilib_unit_transform_t)-1) + #define PCILIB_MAX_TRANSFORMS_PER_UNIT 16 /**< Limits number of supported transforms per unit */ typedef struct pcilib_unit_context_s *pcilib_unit_context_t; @@ -12,13 +14,13 @@ typedef struct pcilib_unit_context_s *pcilib_unit_context_t; * unit transformation routines */ typedef struct { - char *unit; /**< Name of the resulting unit */ - char *transform; /**< String, similar to view formula, explaining transform to this unit */ + char *unit; /**< Name of the resulting unit */ + char *transform; /**< String, similar to view formula, explaining transform to this unit */ } pcilib_unit_transform_t; typedef struct { - char *name; /**< Unit name */ - pcilib_unit_transform_t transforms[PCILIB_MAX_TRANSFORMS_PER_UNIT + 1]; /**< Transforms to other units */ + char *name; /**< Unit name */ + pcilib_unit_transform_t transforms[PCILIB_MAX_TRANSFORMS_PER_UNIT + 1]; /**< Transforms to other units */ } pcilib_unit_description_t; #ifdef __cplusplus @@ -26,7 +28,14 @@ extern "C" { #endif int pcilib_add_units(pcilib_t *ctx, size_t n, const pcilib_unit_description_t *desc); + pcilib_unit_t pcilib_find_unit_by_name(pcilib_t *ctx, const char *unit); +pcilib_unit_transform_t *pcilib_find_transform_by_unit_names(pcilib_t *ctx, const char *from, const char *to); + + // value is modified +int pcilib_transform_unit(pcilib_t *ctx, pcilib_unit_transform_t *trans, pcilib_value_t *value); +int pcilib_transform_unit_by_name(pcilib_t *ctx, const char *to, pcilib_value_t *value); + #ifdef __cplusplus } diff --git a/pcilib/value.c b/pcilib/value.c new file mode 100644 index 0000000..cbf347b --- /dev/null +++ b/pcilib/value.c @@ -0,0 +1,168 @@ +#include +#include +#include +#include + + +#include "pcilib.h" +#include "value.h" +#include "error.h" +#include "unit.h" + +void pcilib_clean_value(pcilib_t *ctx, pcilib_value_t *val) { + if (!val) return; + + if (val->data) { + free(val->data); + val->data = NULL; + } + + memset(val, 0, sizeof(pcilib_value_t)); +} + +int pcilib_copy_value(pcilib_t *ctx, pcilib_value_t *dst, const pcilib_value_t *src) { + if (dst->type != PCILIB_TYPE_INVALID) + pcilib_clean_value(ctx, dst); + + memcpy(dst, src, sizeof(pcilib_value_t)); + + if ((src->size)&&(src->data)) { + dst->data = malloc(src->size); + if (!dst->data) { + dst->type = PCILIB_TYPE_INVALID; + return PCILIB_ERROR_MEMORY; + } + + memcpy(dst->data, src->data, src->size); + } + + return 0; +} + +int pcilib_set_value_from_float(pcilib_t *ctx, pcilib_value_t *value, double fval) { + pcilib_clean_value(ctx, value); + + value->type = PCILIB_TYPE_DOUBLE; + value->fval = fval; + + return 0; +} + +int pcilib_set_value_from_int(pcilib_t *ctx, pcilib_value_t *value, long ival) { + pcilib_clean_value(ctx, value); + + value->type = PCILIB_TYPE_LONG; + value->ival = ival; + + return 0; +} + +/* +double pcilib_value_get_float(pcilib_value_t *val) { + pcilib_value_t copy; + + if (val->type == PCILIB_TYPE_DOUBLE) + return val->fval; + + err = pcilib_copy_value(©, val); + if (err) ??? +} + + +long pcilib_value_get_int(pcilib_value_t *val) { +} +*/ + +int pcilib_convert_value_unit(pcilib_t *ctx, pcilib_value_t *val, const char *unit_name) { + if (val->type == PCILIB_TYPE_INVALID) { + pcilib_error("Can't convert uninitialized value"); + return PCILIB_ERROR_NOTINITIALIZED; + } + + if ((val->type != PCILIB_TYPE_DOUBLE)&&(val->type != PCILIB_TYPE_LONG)) { + pcilib_error("Can't convert value of type %u, only values with integer and float types can be converted to different units", val->type); + return PCILIB_ERROR_INVALID_ARGUMENT; + } + + if (!val->unit) { + pcilib_error("Can't convert value with the unspecified unit"); + return PCILIB_ERROR_INVALID_ARGUMENT; + } + + pcilib_unit_t unit = pcilib_find_unit_by_name(ctx, val->unit); + if (unit == PCILIB_UNIT_INVALID) { + pcilib_error("Can't convert unrecognized unit %s", val->unit); + return PCILIB_ERROR_NOTFOUND; + } + + return pcilib_transform_unit_by_name(ctx, unit_name, val); +} + +int pcilib_convert_value_type(pcilib_t *ctx, pcilib_value_t *val, pcilib_value_type_t type) { + if (val->type == PCILIB_TYPE_INVALID) { + pcilib_error("Can't convert uninitialized value"); + return PCILIB_ERROR_NOTINITIALIZED; + } + + switch (type) { + case PCILIB_TYPE_STRING: + switch (val->type) { + case PCILIB_TYPE_STRING: + break; + case PCILIB_TYPE_DOUBLE: + sprintf(val->str, (val->format?val->format:"%lf"), val->fval); + val->format = NULL; + break; + case PCILIB_TYPE_LONG: + sprintf(val->str, (val->format?val->format:"%li"), val->ival); + val->format = NULL; + break; + default: + return PCILIB_ERROR_NOTSUPPORTED; + } + val->sval = val->str; + break; + case PCILIB_TYPE_DOUBLE: + switch (val->type) { + case PCILIB_TYPE_STRING: + if (sscanf(val->sval, "%lf", &val->fval) != 1) { + pcilib_warning("Can't convert string (%s) to float", val->sval); + return PCILIB_ERROR_INVALID_DATA; + } + val->format = NULL; + break; + case PCILIB_TYPE_DOUBLE: + break; + case PCILIB_TYPE_LONG: + val->fval = val->ival; + val->format = NULL; + break; + default: + return PCILIB_ERROR_NOTSUPPORTED; + } + break; + case PCILIB_TYPE_LONG: + switch (val->type) { + case PCILIB_TYPE_STRING: + if (sscanf(val->sval, "%li", &val->ival) != 1) { + pcilib_warning("Can't convert string (%s) to int", val->sval); + return PCILIB_ERROR_INVALID_DATA; + } + val->format = NULL; + break; + case PCILIB_TYPE_DOUBLE: + val->ival = round(val->fval); + val->format = NULL; + break; + case PCILIB_TYPE_LONG: + break; + default: + return PCILIB_ERROR_NOTSUPPORTED; + } + break; + default: + return PCILIB_ERROR_NOTSUPPORTED; + } + + return 0; +} diff --git a/pcilib/value.h b/pcilib/value.h new file mode 100644 index 0000000..249d0db --- /dev/null +++ b/pcilib/value.h @@ -0,0 +1,15 @@ +#ifndef _PCILIB_VALUE_H +#define _PCILIB_VALUE_H + +#define pcilib_get_type_name(type) (pcilib_data_types[type]) + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef __cplusplus +} +#endif + +#endif /* _PCILIB_VALUE_H */ diff --git a/pcilib/view.c b/pcilib/view.c index 1179808..d121f34 100644 --- a/pcilib/view.c +++ b/pcilib/view.c @@ -2,25 +2,13 @@ #include #include #include +#include #include "pci.h" #include "pcilib.h" #include "view.h" #include "error.h" - - -pcilib_view_t pcilib_find_view_by_name(pcilib_t *ctx, const char *view) { - pcilib_view_t i; - - for(i = 0; ctx->views[i]; i++) { - if (!strcasecmp(ctx->views[i]->name, view)) - return i; - } - - return PCILIB_VIEW_INVALID; -} - - +#include "value.h" int pcilib_add_views(pcilib_t *ctx, size_t n, const pcilib_view_description_t *desc) { size_t i; @@ -72,3 +60,217 @@ int pcilib_add_views(pcilib_t *ctx, size_t n, const pcilib_view_description_t *d return 0; } + + +pcilib_view_t pcilib_find_view_by_name(pcilib_t *ctx, const char *name) { + pcilib_view_t i; + + for(i = 0; ctx->views[i]; i++) { + if (!strcasecmp(ctx->views[i]->name, name)) + return i; + } + + return PCILIB_VIEW_INVALID; +} + +pcilib_view_t pcilib_find_register_view_by_name(pcilib_t *ctx, pcilib_register_t reg, const char *name) { + pcilib_view_t i; + pcilib_register_context_t *regctx = &ctx->register_ctx[reg]; + + if (!regctx->views) return PCILIB_VIEW_INVALID; + + for (i = 0; regctx->views[i].name; i++) { + if (strcasecmp(name, regctx->views[i].name)) { + return pcilib_find_view_by_name(ctx, regctx->views[i].view); + } + } + + return PCILIB_VIEW_INVALID; +} + + // We expect symmetric units. Therefore, we don't distringuish if we read or write +pcilib_view_t pcilib_find_register_view(pcilib_t *ctx, pcilib_register_t reg, const char *name) { + pcilib_view_t i; + pcilib_register_context_t *regctx = &ctx->register_ctx[reg]; + + if (!regctx->views) return PCILIB_VIEW_INVALID; + + // Check if view is just a name of listed view + i = pcilib_find_register_view_by_name(ctx, reg, name); + if (i != PCILIB_VIEW_INVALID) return i; + + // Check if view is a unit + for (i = 0; regctx->views[i].name; i++) { + pcilib_unit_transform_t *trans; + pcilib_view_t view = pcilib_find_view_by_name(ctx, regctx->views[i].view); + if (view == PCILIB_VIEW_INVALID) continue; + + if (ctx->views[view]->unit) { + trans = pcilib_find_transform_by_unit_names(ctx, ctx->views[view]->unit, name); + if (trans) return view; + } + } + + return PCILIB_VIEW_INVALID; +} + + +typedef struct { + pcilib_register_t reg; + pcilib_view_t view; + pcilib_unit_transform_t *trans; +} pcilib_view_configuration_t; + +static int pcilib_detect_view_configuration(pcilib_t *ctx, const char *bank, const char *regname, const char *view_cname, int write_direction, pcilib_view_configuration_t *cfg) { + pcilib_view_t view; + pcilib_register_t reg = PCILIB_REGISTER_INVALID; + pcilib_unit_transform_t *trans = NULL; + + char *view_name = alloca(strlen(view_cname) + 1); + char *unit_name; + + + strcpy(view_name, view_cname); + + unit_name = strchr(view_name, ':'); + if (unit_name) { + *unit_name = 0; + unit_name++; + } + + if (regname) { + reg = pcilib_find_register(ctx, bank, regname); + if (reg == PCILIB_REGISTER_INVALID) { + pcilib_error("Can't find the specified register %s", regname); + return PCILIB_ERROR_NOTFOUND; + } + + // get value + + if (unit_name) view = pcilib_find_register_view_by_name(ctx, reg, view_name); + else view = pcilib_find_register_view(ctx, reg, view_name); + + if (view == PCILIB_VIEW_INVALID) { + pcilib_error("Can't find the specified view %s for register %s", view_name, regname); + return PCILIB_ERROR_NOTFOUND; + } + } else { + view = pcilib_find_view_by_name(ctx, view_name); + if (view == PCILIB_VIEW_INVALID) { + pcilib_error("Can't find the specified view %s", view_name); + return PCILIB_ERROR_NOTFOUND; + } + } + + if (unit_name) { + if (write_direction) trans = pcilib_find_transform_by_unit_names(ctx, unit_name, ctx->views[view]->unit); + else trans = pcilib_find_transform_by_unit_names(ctx, ctx->views[view]->unit, unit_name); + + if (!trans) { + pcilib_error("Don't know how to get the requested unit %s for view %s", unit_name, ctx->views[view]->name); + return PCILIB_ERROR_NOTFOUND; + } + // No transform is required + if (!trans->transform) trans = NULL; + } + + cfg->reg = reg; + cfg->view = view; + cfg->trans = trans; + + return 0; +} + + +int pcilib_read_register_view(pcilib_t *ctx, const char *bank, const char *regname, const char *view, pcilib_value_t *val) { + int err; + + pcilib_view_configuration_t cfg; + pcilib_register_value_t regvalue = 0; + + err = pcilib_detect_view_configuration(ctx, bank, regname, view, 0, &cfg); + if (err) return err; + + if (!ctx->views[cfg.view]->api->read_from_reg) { + pcilib_error("The view (%s) does not support reading from the register", view); + return PCILIB_ERROR_NOTSUPPORTED; + } + + if (regname) { + err = pcilib_read_register_by_id(ctx, cfg.reg, ®value); + if (err) { + pcilib_error("Error (%i) reading register %s", err, regname); + return err; + } + } + + pcilib_clean_value(ctx, val); + + err = ctx->views[cfg.view]->api->read_from_reg(ctx, NULL /*???*/, ®value, val); + if (err) { + if (regname) + pcilib_error("Error (%i) computing view (%s) of register %s", err, view, regname); + else + pcilib_error("Error (%i) computing view %s", err, view); + return err; + } + + if (cfg.trans) { + err = pcilib_transform_unit(ctx, cfg.trans, val); + if (err) return err; + } + + return 0; +} + + +int pcilib_write_register_view(pcilib_t *ctx, const char *bank, const char *regname, const char *view, const pcilib_value_t *valarg) { + int err; + pcilib_value_t val; + + pcilib_view_configuration_t cfg; + pcilib_register_value_t regvalue = 0; + + err = pcilib_detect_view_configuration(ctx, bank, regname, view, 1, &cfg); + if (err) return err; + + if (!ctx->views[cfg.view]->api->write_to_reg) { + pcilib_error("The view (%s) does not support reading from the register", view); + return PCILIB_ERROR_NOTSUPPORTED; + } + + err = pcilib_copy_value(ctx, &val, valarg); + if (err) return err; + + err = pcilib_convert_value_type(ctx, &val, ctx->views[cfg.view]->type); + if (err) { + pcilib_error("Error (%i) converting the value of type (%s) to type (%s) used by view (%s)", pcilib_get_type_name(val.type), pcilib_get_type_name(ctx->views[cfg.view]->type), view); + return err; + } + + if (cfg.trans) { + err = pcilib_transform_unit(ctx, cfg.trans, &val); + if (err) return err; + } + + + err = ctx->views[cfg.view]->api->write_to_reg(ctx, NULL /*???*/, ®value, &val); + if (err) { + if (regname) + pcilib_error("Error (%i) computing view (%s) of register %s", err, view, regname); + else + pcilib_error("Error (%i) computing view %s", err, view); + return err; + } + + + if (regname) { + err = pcilib_write_register_by_id(ctx, cfg.reg, regvalue); + if (err) { + pcilib_error("Error (%i) reading register %s", err, regname); + return err; + } + } + + return 0; +} diff --git a/pcilib/view.h b/pcilib/view.h index 7a78a1d..bf0ea28 100644 --- a/pcilib/view.h +++ b/pcilib/view.h @@ -9,18 +9,23 @@ //typedef void *pcilib_view_context_t; typedef struct pcilib_view_context_s *pcilib_view_context_t; +typedef enum { + PCILIB_VIEW_FLAG_PROPERTY = 1 /**< Indicates that view does not depend on a value and is independent property */ +} pcilib_view_flags_t; + typedef struct { pcilib_version_t version; size_t description_size; pcilib_view_context_t (*init)(pcilib_t *ctx); void (*free)(pcilib_t *ctx, pcilib_view_context_t *view); - int (*read_from_reg)(pcilib_t *ctx, pcilib_view_context_t *view, const pcilib_register_value_t *regval, pcilib_data_type_t viewval_type, size_t viewval_size, void *viewval); - int (*write_to_reg)(pcilib_t *ctx, pcilib_view_context_t *view, pcilib_register_value_t *regval, pcilib_data_type_t viewval_type, size_t viewval_size, const void *viewval); + int (*read_from_reg)(pcilib_t *ctx, pcilib_view_context_t *view, const pcilib_register_value_t *regval, pcilib_value_t *val); + int (*write_to_reg)(pcilib_t *ctx, pcilib_view_context_t *view, pcilib_register_value_t *regval, const pcilib_value_t *val); } pcilib_view_api_description_t; typedef struct { const pcilib_view_api_description_t *api; - pcilib_data_type_t type; /**< The default data type returned by operation, PCILIB_VIEW_TYPE_STRING is supported by all operations */ + pcilib_value_type_t type; /**< The default data type returned by operation, PCILIB_VIEW_TYPE_STRING is supported by all operations */ + pcilib_view_flags_t flags; /**< Flags specifying type of the view */ const char *unit; /**< Returned unit (if any) */ const char *name; /**< Name of the view */ const char *description; /**< Short description */ @@ -31,7 +36,10 @@ extern "C" { #endif int pcilib_add_views(pcilib_t *ctx, size_t n, const pcilib_view_description_t *desc); + pcilib_view_t pcilib_find_view_by_name(pcilib_t *ctx, const char *view); +pcilib_view_t pcilib_find_register_view_by_name(pcilib_t *ctx, pcilib_register_t reg, const char *name); +pcilib_view_t pcilib_find_register_view(pcilib_t *ctx, pcilib_register_t reg, const char *name); #ifdef __cplusplus } -- cgit v1.2.3