Browse Source

Base functions for views

Suren A. Chilingaryan 8 years ago
parent
commit
21812f8d76
19 changed files with 731 additions and 41 deletions
  1. 2 0
      dma/CMakeLists.txt
  2. 3 3
      pcilib/CMakeLists.txt
  3. 4 0
      pcilib/export.c
  4. 2 0
      pcilib/export.h
  5. 10 2
      pcilib/pci.c
  6. 4 3
      pcilib/pci.h
  7. 32 6
      pcilib/pcilib.h
  8. 171 0
      pcilib/py.c
  9. 19 0
      pcilib/py.h
  10. 53 2
      pcilib/unit.c
  11. 13 4
      pcilib/unit.h
  12. 168 0
      pcilib/value.c
  13. 15 0
      pcilib/value.h
  14. 216 14
      pcilib/view.c
  15. 11 3
      pcilib/view.h
  16. 2 0
      protocols/CMakeLists.txt
  17. 2 0
      views/CMakeLists.txt
  18. 2 2
      views/enum.c
  19. 2 2
      views/transform.c

+ 2 - 0
dma/CMakeLists.txt

@@ -4,6 +4,8 @@ include_directories(
     ${CMAKE_SOURCE_DIR}/pcilib
     ${CMAKE_BINARY_DIR}/pcilib
     ${LIBXML2_INCLUDE_DIRS}
+    ${PYTHON_INCLUDE_DIR}
+    ${UTHASH_INCLUDE_DIRS}
 )
 
 set(HEADERS ${HEADERS} nwl.h nwl_private.h nwl_engine.h nwl_irq.h nwl_loopback.h ipe.h ipe_private.h)

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

+ 4 - 0
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"
 

+ 2 - 0
pcilib/export.h

@@ -6,6 +6,8 @@
 #include <pcilib/bank.h>
 #include <pcilib/dma.h>
 
+extern const char *pcilib_data_types[];
+
 extern const pcilib_register_protocol_description_t pcilib_protocols[];
 extern const pcilib_dma_description_t pcilib_dma[];
 

+ 10 - 2
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);

+ 4 - 3
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;

+ 32 - 6
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);

+ 171 - 0
pcilib/py.c

@@ -0,0 +1,171 @@
+#include <Python.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+
+#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, &regval);
+            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));
+}

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

+ 53 - 2
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);
+}

+ 13 - 4
pcilib/unit.h

@@ -4,6 +4,8 @@
 #include <pcilib.h>
 
 #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
 }

+ 168 - 0
pcilib/value.c

@@ -0,0 +1,168 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+
+#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(&copy, 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;
+}

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

+ 216 - 14
pcilib/view.c

@@ -2,25 +2,13 @@
 #include <stdlib.h>
 #include <string.h>
 #include <strings.h>
+#include <alloca.h>
 
 #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, &regvalue);
+        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 /*???*/, &regvalue, 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 /*???*/, &regvalue, &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;
+}

+ 11 - 3
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
 }

+ 2 - 0
protocols/CMakeLists.txt

@@ -4,6 +4,8 @@ include_directories(
     ${CMAKE_SOURCE_DIR}/pcilib
     ${CMAKE_BINARY_DIR}/pcilib
     ${LIBXML2_INCLUDE_DIRS}
+    ${PYTHON_INCLUDE_DIR}
+    ${UTHASH_INCLUDE_DIRS}
 )
 
 set(HEADERS ${HEADERS} default.h software.h)

+ 2 - 0
views/CMakeLists.txt

@@ -4,6 +4,8 @@ include_directories(
     ${CMAKE_SOURCE_DIR}/pcilib
     ${CMAKE_BINARY_DIR}/pcilib
     ${LIBXML2_INCLUDE_DIRS}
+    ${PYTHON_INCLUDE_DIR}
+    ${UTHASH_INCLUDE_DIRS}
 )
 
 set(HEADERS ${HEADERS} enum.h transform.h)

+ 2 - 2
views/enum.c

@@ -12,7 +12,7 @@
 static void pcilib_enum_view_free(pcilib_t *ctx, pcilib_view_context_t *view) {
 }
 
-static int pcilib_enum_view_read(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) {
+static int pcilib_enum_view_read(pcilib_t *ctx, pcilib_view_context_t *view, const pcilib_register_value_t *regval, pcilib_value_t *val) {
 /*        for(j=0; ((pcilib_enum_t*)(params))[j].name; j++) {
             if (*regval<=((pcilib_enum_t*)(params))[j].max && *regval>=((pcilib_enum_t*)(params))[j].min) {
                 if(viewval_size<strlen(((pcilib_enum_t*)(params))[j].name)) {
@@ -29,7 +29,7 @@ static int pcilib_enum_view_read(pcilib_t *ctx, pcilib_view_context_t *view, con
     return PCILIB_ERROR_INVALID_REQUEST;*/
 }
 
-static int pcilib_enum_view_write(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) {
+static int pcilib_enum_view_write(pcilib_t *ctx, pcilib_view_context_t *view, pcilib_register_value_t *regval, pcilib_value_t *val) {
 /*    int j,k;
 
     if(view2reg==1) {

+ 2 - 2
views/transform.c

@@ -10,7 +10,7 @@
 #include "transform.h"
 
 
-static int pcilib_transform_view_read(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) {
+static int pcilib_transform_view_read(pcilib_t *ctx, pcilib_view_context_t *view, const pcilib_register_value_t *regval, pcilib_value_t *val) {
 /*    int j=0;
     pcilib_register_value_t value=0;
     char* formula=NULL;
@@ -43,7 +43,7 @@ static int pcilib_transform_view_read(pcilib_t *ctx, pcilib_view_context_t *view
         }*/
 }
 
-static int pcilib_transform_view_write(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) {
+static int pcilib_transform_view_write(pcilib_t *ctx, pcilib_view_context_t *view, pcilib_register_value_t *regval, pcilib_value_t *val) {
 /*        if(!(strcasecmp(unit, ((pcilib_view_t*)viewval)->base_unit.name))) {
             formula=malloc(sizeof(char)*strlen(((pcilib_formula_t*)params)->write_formula));
             strncpy(formula,((pcilib_formula_t*)params)->write_formula,strlen(((pcilib_formula_t*)params)->write_formula));