summaryrefslogtreecommitdiffstats
path: root/pcilib
diff options
context:
space:
mode:
authorSuren A. Chilingaryan <csa@suren.me>2015-10-08 20:04:37 +0200
committerSuren A. Chilingaryan <csa@suren.me>2015-10-08 20:04:37 +0200
commit21812f8d763fac8ee9bb3fdc593642b06f405a2b (patch)
treea55e99115e8c238e6b34159e063ac7d01ba65d54 /pcilib
parente28e74adf3d58deb95ce84c66423f347cbe2f859 (diff)
downloadpcitool-21812f8d763fac8ee9bb3fdc593642b06f405a2b.tar.gz
pcitool-21812f8d763fac8ee9bb3fdc593642b06f405a2b.tar.bz2
pcitool-21812f8d763fac8ee9bb3fdc593642b06f405a2b.tar.xz
pcitool-21812f8d763fac8ee9bb3fdc593642b06f405a2b.zip
Base functions for views
Diffstat (limited to 'pcilib')
-rw-r--r--pcilib/CMakeLists.txt6
-rw-r--r--pcilib/export.c4
-rw-r--r--pcilib/export.h2
-rw-r--r--pcilib/pci.c12
-rw-r--r--pcilib/pci.h7
-rw-r--r--pcilib/pcilib.h38
-rw-r--r--pcilib/py.c171
-rw-r--r--pcilib/py.h19
-rw-r--r--pcilib/unit.c55
-rw-r--r--pcilib/unit.h17
-rw-r--r--pcilib/value.c168
-rw-r--r--pcilib/value.h15
-rw-r--r--pcilib/view.c230
-rw-r--r--pcilib/view.h14
14 files changed, 721 insertions, 37 deletions
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 <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[];
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 <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));
+}
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 <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
}
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 <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;
+}
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 <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;
+}
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
}