summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/ToDo23
-rw-r--r--pcilib/xml.c230
-rw-r--r--pcilib/xml.h43
-rw-r--r--xml/model.xsd2
-rw-r--r--xml/references.xsd19
-rw-r--r--xml/test/camera.xml97
-rw-r--r--xml/test/cmosis.xml50
-rw-r--r--xml/test/dma.xml4
-rw-r--r--xml/test/names.xml16
-rw-r--r--xml/test/props.xml4
-rw-r--r--xml/test/units.xml35
-rw-r--r--xml/test/views.xml6
12 files changed, 324 insertions, 205 deletions
diff --git a/docs/ToDo b/docs/ToDo
index c42e000..0c54eea 100644
--- a/docs/ToDo
+++ b/docs/ToDo
@@ -1,23 +1,30 @@
High Priority (we would need it for IPE Camera)
=============
- 1. Join multiple XML files and on error use simplified XSD scheme on all files to find the file causing error
+ 1. DMA without ring buffer, just send data in the newly configured buffers while there is the space...
+ * We need a way to add (remove?) pages into the same use. Some times in the middle of existing pages, i.e. tructuring seems complicated.
+ * vmsplice them out trough the device?
+ 2. Allow DMA into the user pages
+ * Dangerous as hardware accessed memory is only valid during life-time of one application. Instead the kernel pages can be re-assembled as big buffer using vmmngr_map_page (?)
+ 3. Use huge-pages + dynamicaly configure DMA page size
+ 4. DirectGMA/GPUDirect support
+ 5. High-speed interface to Infiniband
Normal Priority (it would make just few things a bit easier)
===============
- 1. Implement pcilib_configure_autotrigger
- 2. Provide OR and AND operations on registers in cli
- 3. Support writting a data from a binary file in cli
- 4. Support Python-scripts in a views, we need to provide python function to read registers/properties...
- 5. Really check the specified min, max values while setting registers
+ 1. Support Python-scripts in the views (we need to provide python API to read registers/properties)
+ 2. Integrate base streaming model into the pcitool
+ 3. Implement pcilib_configure_autotrigger
+ 4. Really check the specified min, max values while setting registers
+ 5. Provide OR and AND operations on registers in cli
+ 6. Support writting a data from a binary file in cli
Low Priority (only as generalization for other projects)
============
- 1. Shall we allow overriding of registers?
+ 1. We managed kmem performance using next kmem prediction, but it is still wise to provide additionally a binary tree for faster search
2. Support for Network Registers and Network DMA
3. Define a syntax for register dependencies / delays (?)
4. Use pthread_condition_t instead of polling
5. Support FIFO reads/writes from/to registers
- 6. We managed kmem performance using next kmem prediction, but it is still wise to provide additionally a binary tree for faster search
Performance
===========
diff --git a/pcilib/xml.c b/pcilib/xml.c
index 1238ba8..bc48a34 100644
--- a/pcilib/xml.c
+++ b/pcilib/xml.c
@@ -78,6 +78,17 @@ static xmlNodePtr pcilib_xml_get_parent_register_node(xmlDocPtr doc, xmlNodePtr
}
*/
+int pcilib_get_xml_attr(pcilib_t *ctx, pcilib_xml_node_t *node, const char *attr, pcilib_value_t *val) {
+ xmlAttr *prop;
+ xmlChar *str;
+
+ prop = xmlHasProp(node, BAD_CAST attr);
+ if ((!prop)||(!prop->children)) return PCILIB_ERROR_NOTFOUND;
+
+ str = prop->children->content;
+ return pcilib_set_value_from_static_string(ctx, val, (const char*)str);
+}
+
static int pcilib_xml_parse_view_reference(pcilib_t *ctx, xmlDocPtr doc, xmlNodePtr node, pcilib_view_reference_t *desc) {
xmlAttr *cur;
char *value, *name;
@@ -873,11 +884,14 @@ static int pcilib_xml_process_document(pcilib_t *ctx, xmlDocPtr doc, xmlXPathCon
return 0;
}
-static int pcilib_xml_load_xsd(pcilib_t *ctx, char *xsd_filename) {
+static int pcilib_xml_load_xsd_file(pcilib_t *ctx, char *xsd_filename, xmlSchemaPtr *schema, xmlSchemaValidCtxtPtr *validator) {
int err;
xmlSchemaParserCtxtPtr ctxt;
+ *schema = NULL;
+ *validator = NULL;
+
/** we first parse the xsd file for AST with validation*/
ctxt = xmlSchemaNewParserCtxt(xsd_filename);
if (!ctxt) {
@@ -887,8 +901,8 @@ static int pcilib_xml_load_xsd(pcilib_t *ctx, char *xsd_filename) {
return PCILIB_ERROR_FAILED;
}
- ctx->xml.schema = xmlSchemaParse(ctxt);
- if (!ctx->xml.schema) {
+ *schema = xmlSchemaParse(ctxt);
+ if (!*schema) {
xmlErrorPtr xmlerr = xmlGetLastError();
xmlSchemaFreeParserCtxt(ctxt);
if (xmlerr) pcilib_error("Failed to parse XML schema, xmlSchemaParse reported error %d - %s", xmlerr->code, xmlerr->message);
@@ -898,15 +912,15 @@ static int pcilib_xml_load_xsd(pcilib_t *ctx, char *xsd_filename) {
xmlSchemaFreeParserCtxt(ctxt);
- ctx->xml.validator = xmlSchemaNewValidCtxt(ctx->xml.schema);
- if (!ctx->xml.validator) {
+ *validator = xmlSchemaNewValidCtxt(*schema);
+ if (!*validator) {
xmlErrorPtr xmlerr = xmlGetLastError();
if (xmlerr) pcilib_error("xmlSchemaNewValidCtxt reported error %d - %s", xmlerr->code, xmlerr->message);
else pcilib_error("Failed to create a validation context");
return PCILIB_ERROR_FAILED;
}
- err = xmlSchemaSetValidOptions(ctx->xml.validator, XML_SCHEMA_VAL_VC_I_CREATE);
+ err = xmlSchemaSetValidOptions(*validator, XML_SCHEMA_VAL_VC_I_CREATE);
if (err) {
xmlErrorPtr xmlerr = xmlGetLastError();
if (xmlerr) pcilib_error("xmlSchemaSetValidOptions reported error %d - %s", xmlerr->code, xmlerr->message);
@@ -917,16 +931,45 @@ static int pcilib_xml_load_xsd(pcilib_t *ctx, char *xsd_filename) {
return 0;
}
-static int pcilib_xml_load_file(pcilib_t *ctx, const char *path, const char *name) {
+
+static int pcilib_xml_load_xsd(pcilib_t *ctx, char *model_dir) {
+ int err;
+
+ struct stat st;
+ char *xsd_path;
+
+ xsd_path = (char*)alloca(strlen(model_dir) + 32);
+ if (!xsd_path) return PCILIB_ERROR_MEMORY;
+
+ sprintf(xsd_path, "%s/model.xsd", model_dir);
+ if (stat(xsd_path, &st)) {
+ pcilib_info("XML models are not present, missing parts schema");
+ return PCILIB_ERROR_NOTFOUND;
+ }
+
+ err = pcilib_xml_load_xsd_file(ctx, xsd_path, &ctx->xml.parts_schema, &ctx->xml.parts_validator);
+ if (err) return err;
+
+ sprintf(xsd_path, "%s/references.xsd", model_dir);
+ if (stat(xsd_path, &st)) {
+ pcilib_info("XML models are not present, missing schema");
+ return PCILIB_ERROR_NOTFOUND;
+ }
+
+ return pcilib_xml_load_xsd_file(ctx, xsd_path, &ctx->xml.schema, &ctx->xml.validator);
+}
+
+
+
+static xmlDocPtr pcilib_xml_load_file(pcilib_t *ctx, const char *path, const char *name) {
int err;
char *full_name;
xmlDocPtr doc;
- xmlXPathContextPtr xpath;
full_name = (char*)alloca(strlen(path) + strlen(name) + 2);
if (!name) {
pcilib_error("Error allocating %zu bytes of memory in stack to create a file name", strlen(path) + strlen(name) + 2);
- return PCILIB_ERROR_MEMORY;
+ return NULL;
}
sprintf(full_name, "%s/%s", path, name);
@@ -936,104 +979,139 @@ static int pcilib_xml_load_file(pcilib_t *ctx, const char *path, const char *nam
xmlErrorPtr xmlerr = xmlCtxtGetLastError(ctx->xml.parser);
if (xmlerr) pcilib_error("Error parsing %s, xmlCtxtReadFile reported error %d - %s", full_name, xmlerr->code, xmlerr->message);
else pcilib_error("Error parsing %s", full_name);
- return PCILIB_ERROR_INVALID_DATA;
+ return NULL;
}
- err = xmlSchemaValidateDoc(ctx->xml.validator, doc);
+ err = xmlSchemaValidateDoc(ctx->xml.parts_validator, doc);
if (err) {
xmlErrorPtr xmlerr = xmlCtxtGetLastError(ctx->xml.parser);
xmlFreeDoc(doc);
if (xmlerr) pcilib_error("Error validating %s, xmlSchemaValidateDoc reported error %d - %s", full_name, xmlerr->code, xmlerr->message);
else pcilib_error("Error validating %s", full_name);
- return PCILIB_ERROR_VERIFY;
- }
-
- xpath = xmlXPathNewContext(doc);
- if (!xpath) {
- xmlErrorPtr xmlerr = xmlGetLastError();
- xmlFreeDoc(doc);
- if (xmlerr) pcilib_error("Document %s: xmlXpathNewContext reported error %d - %s for document %s", full_name, xmlerr->code, xmlerr->message);
- else pcilib_error("Error creating XPath context for %s", full_name);
- return PCILIB_ERROR_FAILED;
- }
-
- // This can only partially fail... Therefore we need to keep XML and just return the error...
- err = pcilib_xml_process_document(ctx, doc, xpath);
-
- if (ctx->xml.num_files == PCILIB_MAX_MODEL_FILES) {
- xmlFreeDoc(doc);
- xmlXPathFreeContext(xpath);
- pcilib_error("Too many XML files for a model, only up to %zu are supported", PCILIB_MAX_MODEL_FILES);
- return PCILIB_ERROR_TOOBIG;
+ return NULL;
}
- ctx->xml.docs[ctx->xml.num_files] = doc;
- ctx->xml.xpath[ctx->xml.num_files] = xpath;
- ctx->xml.num_files++;
-
- return err;
+ return doc;
}
-
-int pcilib_process_xml(pcilib_t *ctx, const char *location) {
+static int pcilib_process_xml_internal(pcilib_t *ctx, const char *model, const char *location) {
int err;
DIR *rep;
struct dirent *file = NULL;
char *model_dir, *model_path;
+ xmlDocPtr doc = NULL;
+ xmlNodePtr root = NULL;
+ xmlXPathContextPtr xpath;
+
+ if (ctx->xml.num_files == PCILIB_MAX_MODEL_FILES) {
+ pcilib_error("Too many XML locations for a model, only up to %zu are supported", PCILIB_MAX_MODEL_FILES);
+ return PCILIB_ERROR_TOOBIG;
+ }
+
model_dir = getenv("PCILIB_MODEL_DIR");
if (!model_dir) model_dir = PCILIB_MODEL_DIR;
- model_path = (char*)alloca(strlen(model_dir) + strlen(location) + 2);
+ if (!model) model = ctx->model;
+ if (!location) location = "";
+
+ model_path = (char*)alloca(strlen(model_dir) + strlen(model) + strlen(location) + 3);
if (!model_path) return PCILIB_ERROR_MEMORY;
- sprintf(model_path, "%s/%s", model_dir, location);
+ sprintf(model_path, "%s/%s/%s", model_dir, model, location);
rep = opendir(model_path);
if (!rep) return PCILIB_ERROR_NOTFOUND;
while ((file = readdir(rep)) != NULL) {
+ xmlDocPtr newdoc;
+
size_t len = strlen(file->d_name);
if ((len < 4)||(strcasecmp(file->d_name + len - 4, ".xml"))) continue;
if (file->d_type != DT_REG) continue;
- err = pcilib_xml_load_file(ctx, model_path, file->d_name);
- if (err) pcilib_error("Error processing XML file %s", file->d_name);
- }
+ newdoc = pcilib_xml_load_file(ctx, model_path, file->d_name);
+ if (!newdoc) {
+ pcilib_error("Error processing XML file %s", file->d_name);
+ continue;
+ }
+
+ if (doc) {
+ xmlNodePtr node;
+ node = xmlDocGetRootElement(newdoc);
+ if (node) node = xmlFirstElementChild(node);
+ if (node) node = xmlDocCopyNodeList(doc, node);
+ xmlFreeDoc(newdoc);
+
+ if ((!node)||(!xmlAddChildList(root, node))) {
+ xmlErrorPtr xmlerr = xmlCtxtGetLastError(ctx->xml.parser);
+ if (node) xmlFreeNode(node);
+ if (xmlerr) pcilib_error("Error manipulating XML tree of %s, libXML2 reported error %d - %s", file->d_name, xmlerr->code, xmlerr->message);
+ else pcilib_error("Error manipulating XML tree of %s", file->d_name);
+ continue;
+ }
+ } else {
+ root = xmlDocGetRootElement(newdoc);
+ if (!root) {
+ xmlErrorPtr xmlerr = xmlCtxtGetLastError(ctx->xml.parser);
+ xmlFreeDoc(newdoc);
+ if (xmlerr) pcilib_error("Error manipulating XML tree of %s, libXML2 reported error %d - %s", file->d_name, xmlerr->code, xmlerr->message);
+ else pcilib_error("Error manipulating XML tree of %s", file->d_name);
+ continue;
+ }
+ doc = newdoc;
+ // This is undocumented, but should be fine...
+ if (doc->URL) xmlFree((xmlChar*)doc->URL);
+ doc->URL = xmlStrdup(BAD_CAST model_path);
+ }
+ }
closedir(rep);
- return 0;
+ if (!doc)
+ return 0;
+
+ err = xmlSchemaValidateDoc(ctx->xml.validator, doc);
+ if (err) {
+ xmlErrorPtr xmlerr = xmlCtxtGetLastError(ctx->xml.parser);
+ xmlFreeDoc(doc);
+ if (xmlerr) pcilib_error("Error validating %s, xmlSchemaValidateDoc reported error %d - %s", model_path, xmlerr->code, xmlerr->message);
+ else pcilib_error("Error validating %s", model_path);
+ return PCILIB_ERROR_VERIFY;
+ }
+
+ xpath = xmlXPathNewContext(doc);
+ if (!xpath) {
+ xmlErrorPtr xmlerr = xmlGetLastError();
+ xmlFreeDoc(doc);
+ if (xmlerr) pcilib_error("Document %s: xmlXpathNewContext reported error %d - %s for document %s", model_path, xmlerr->code, xmlerr->message);
+ else pcilib_error("Error creating XPath context for %s", model_path);
+ return PCILIB_ERROR_FAILED;
+ }
+
+ // This can only partially fail... Therefore we need to keep XML and just return the error...
+ err = pcilib_xml_process_document(ctx, doc, xpath);
+
+ ctx->xml.docs[ctx->xml.num_files] = doc;
+ ctx->xml.xpath[ctx->xml.num_files] = xpath;
+ ctx->xml.num_files++;
+
+ return err;
}
+int pcilib_process_xml(pcilib_t *ctx, const char *location) {
+ return pcilib_process_xml_internal(ctx, NULL, location);
+}
-/** pcilib_init_xml
- * this function will initialize the registers and banks from the xml files
- * @param[in,out] ctx the pciilib_t running that gets filled with structures
- * @param[in] model the current model of ctx
- * @return an error code
- */
int pcilib_init_xml(pcilib_t *ctx, const char *model) {
int err;
char *model_dir;
- char *xsd_path;
-
- struct stat st;
model_dir = getenv("PCILIB_MODEL_DIR");
if (!model_dir) model_dir = PCILIB_MODEL_DIR;
- xsd_path = (char*)alloca(strlen(model_dir) + 16);
- if (!xsd_path) return PCILIB_ERROR_MEMORY;
-
- sprintf(xsd_path, "%s/model.xsd", model_dir);
- if (stat(xsd_path, &st)) {
- pcilib_info("XML models are not present");
- return PCILIB_ERROR_NOTFOUND;
- }
-
ctx->xml.parser = xmlNewParserCtxt();
if (!ctx->xml.parser) {
xmlErrorPtr xmlerr = xmlGetLastError();
@@ -1042,16 +1120,12 @@ int pcilib_init_xml(pcilib_t *ctx, const char *model) {
return PCILIB_ERROR_FAILED;
}
- err = pcilib_xml_load_xsd(ctx, xsd_path);
+ err = pcilib_xml_load_xsd(ctx, model_dir);
if (err) return err;
- return pcilib_process_xml(ctx, model);
+ return pcilib_process_xml_internal(ctx, model, NULL);
}
-/** pcilib_free_xml
- * this function free the xml parts of the pcilib_t running, and some libxml ashes
- * @param[in] pci the pcilib_t running
-*/
void pcilib_free_xml(pcilib_t *ctx) {
int i;
@@ -1085,7 +1159,16 @@ void pcilib_free_xml(pcilib_t *ctx) {
if (ctx->xml.schema) {
xmlSchemaFree(ctx->xml.schema);
ctx->xml.schema = NULL;
+ }
+
+ if (ctx->xml.parts_validator) {
+ xmlSchemaFreeValidCtxt(ctx->xml.parts_validator);
+ ctx->xml.parts_validator = NULL;
+ }
+ if (ctx->xml.parts_schema) {
+ xmlSchemaFree(ctx->xml.parts_schema);
+ ctx->xml.parts_schema = NULL;
}
if (ctx->xml.parser) {
@@ -1099,14 +1182,3 @@ void pcilib_free_xml(pcilib_t *ctx) {
xmlMemoryDump();
*/
}
-
-int pcilib_get_xml_attr(pcilib_t *ctx, pcilib_xml_node_t *node, const char *attr, pcilib_value_t *val) {
- xmlAttr *prop;
- xmlChar *str;
-
- prop = xmlHasProp(node, BAD_CAST attr);
- if ((!prop)||(!prop->children)) return PCILIB_ERROR_NOTFOUND;
-
- str = prop->children->content;
- return pcilib_set_value_from_static_string(ctx, val, (const char*)str);
-}
diff --git a/pcilib/xml.h b/pcilib/xml.h
index 10bc154..e4a5744 100644
--- a/pcilib/xml.h
+++ b/pcilib/xml.h
@@ -28,8 +28,10 @@ struct pcilib_xml_s {
xmlXPathContextPtr xpath[PCILIB_MAX_MODEL_FILES]; /**< Per-file XPath context */
xmlParserCtxtPtr parser; /**< Pointer to the XML parser context */
- xmlSchemaPtr schema; /**< Pointer to the parsed xsd schema */
+ xmlSchemaPtr schema; /**< Pointer to the parsed xsd schema */
xmlSchemaValidCtxtPtr validator; /**< Pointer to the XML validation context */
+ xmlSchemaPtr parts_schema; /**< Pointer to the parsed xsd schema capable of validating individual XML files - no check for cross-references */
+ xmlSchemaValidCtxtPtr parts_validator; /**< Pointer to the XML validation context capable of validating individual XML files - no check for cross-references */
xmlNodePtr bank_nodes[PCILIB_MAX_REGISTER_BANKS]; /**< pointer to xml nodes of banks in the xml file */
};
@@ -38,27 +40,46 @@ struct pcilib_xml_s {
extern "C" {
#endif
-/**
- * this function gets the xml files and validates them, before filling the pcilib_t struct with the registers and banks of those files
- *@param[in,out] ctx the pcilib_t struct running that gets filled with banks and registers
- *@param[in] model the name of the model
+/** pcilib_init_xml
+ * Initializes XML stack and loads a default set of XML files. The default location for model XML files is
+ * /usr/local/share/pcilib/models/<current_model>. This can be altered using CMake PCILIB_MODEL_DIR variable
+ * while building or using PCILIB_MODEL_DIR environmental variable dynamicly. More XML files can be added
+ * later using pcilib_process_xml call.
+ * @param[in,out] ctx - pcilib context
+ * @param[in] model - the name of the model
+ * @return - error or 0 on success
*/
int pcilib_init_xml(pcilib_t *ctx, const char *model);
/** pcilib_free_xml
* this function free the xml parts of the pcilib_t running, and some libxml ashes
* @param[in] ctx the pcilib_t running
-*/
+ */
void pcilib_free_xml(pcilib_t *ctx);
-
/** pcilib_process_xml
- * this function free the xml parts of the pcilib_t running, and some libxml ashes
- * @param[in] ctx the pcilib_t running
- * @param[in] location of XML files relative to the PCILIB_MODEL_DIR
-*/
+ * Processes a bunch of XML files in the specified directory. During the initialization, all XML files
+ * in the corresponding model directory will be loaded. This function allows to additionally load XML
+ * files from the specified subdirectories of the model directory. I.e. the XML files from the
+ * /usr/local/share/pcilib/models/<current_model>/<location> will be loaded. As with pcilib_init_xml,
+ * the directory can be adjusted using CMake build configuration or PCILIB_MODEL_DIR environmental
+ * variable.
+ * @param[in] ctx - pcilib context
+ * @param[in] location - Specifies sub-directory with XML files relative to the model directory.
+ * @return - error or 0 on success
+ */
int pcilib_process_xml(pcilib_t *ctx, const char *location);
+/** pcilib_get_xml_attr
+ * This is an internal function which returns a specified node attribute in the pcilib_value_t structure.
+ * This function should not be used directly. Instead subsystem specific calls like pcilib_get_register_attr,
+ * pcilib_get_property_attr, ...have to be used.
+ * @param[in] ctx - pcilib context
+ * @param[in] node - LibXML2 node
+ * @param[in] attr - attribute name
+ * @param[out] val - the result will be returned in this variable. Prior to first usage pcilib_value_t variable should be initalized to 0.
+ * @return - error or 0 on success
+ */
int pcilib_get_xml_attr(pcilib_t *ctx, pcilib_xml_node_t *node, const char *attr, pcilib_value_t *val);
diff --git a/xml/model.xsd b/xml/model.xsd
index 1440032..164e887 100644
--- a/xml/model.xsd
+++ b/xml/model.xsd
@@ -4,7 +4,7 @@
<xsd:element name="model">
<xsd:complexType>
- <xsd:choice minOccurs="0" maxOccurs="unbounded">
+ <xsd:choice minOccurs="1" maxOccurs="unbounded">
<xsd:element name="bank" type="pcilib_bank_t" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="transform" type="pcilib_transform_view_t" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="enum" type="pcilib_enum_view_t" minOccurs="0" maxOccurs="unbounded" />
diff --git a/xml/references.xsd b/xml/references.xsd
index f382840..4474141 100644
--- a/xml/references.xsd
+++ b/xml/references.xsd
@@ -1,9 +1,9 @@
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:include schemaLocation="types.xsd"/>
-
+
<xsd:element name="model">
<xsd:complexType>
- <xsd:choice minOccurs="0" maxOccurs="unbounded">
+ <xsd:choice minOccurs="1" maxOccurs="unbounded">
<xsd:element name="bank" type="pcilib_bank_t" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="transform" type="pcilib_transform_view_t" minOccurs="0" maxOccurs="unbounded" />
<xsd:element name="enum" type="pcilib_enum_view_t" minOccurs="0" maxOccurs="unbounded">
@@ -25,30 +25,31 @@
<xsd:selector xpath="bank" />
<xsd:field xpath="@name" />
</xsd:key>
+<!-- Currently, we define all registers, banks, views, and units as xsd:ID which prevents them from sharing name anyway.
+Currently it seems fine, but later it could turn out too be to strict. Then, we get problem also here as transform[@name]
+is ID of view, not register. But how can we restrict transform field to @register only? -->
<xsd:key name="pcilib_register_key">
- <xsd:selector xpath="bank/register|bank/register/field" />
- <xsd:field xpath="@name" />
+ <xsd:selector xpath="bank/register|bank/register/field|transform" />
+ <xsd:field xpath="@name|@register" />
</xsd:key>
<xsd:key name="pcilib_view_key">
<xsd:selector xpath="transform|enum" />
- <xsd:field xpath="@name" />
+ <xsd:field xpath="@name|@path" />
</xsd:key>
<xsd:key name="pcilib_unit_key">
<xsd:selector xpath="unit" />
<xsd:field xpath="@name" />
</xsd:key>
- <xsd:key name="pcilib_path_key">
- <xsd:selector xpath="transform" />
- <xsd:field xpath="@path" />
- </xsd:key>
<xsd:keyref name="pcilib_register_view_ref" refer="pcilib_view_key">
<xsd:selector xpath="bank/register/view|bank/register/field/view" />
<xsd:field xpath="@view" />
</xsd:keyref>
+<!-- Actually, it is no problem to reference non-existing unit just for informative purposes
<xsd:keyref name="pcilib_unit_ref" refer="pcilib_unit_key">
<xsd:selector xpath="transform|enum" />
<xsd:field xpath="@unit" />
</xsd:keyref>
+-->
</xsd:element>
</xsd:schema>
diff --git a/xml/test/camera.xml b/xml/test/camera.xml
index a84299a..6568f17 100644
--- a/xml/test/camera.xml
+++ b/xml/test/camera.xml
@@ -1,52 +1,5 @@
<?xml version="1.0"?>
<model xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
- <bank bar="0" size="128" protocol="software_registers" read_address="0x9010" write_address="0x9000" word_size="8" endianess="little" format="%lu" name="cmosis" description="CMOSIS CMV2000 Registers">
- <register address="1" offset="0" size="16" default="1088" rwmask="0" mode="RW" name="cmosis_number_lines" description="test"/>
- <register address="3" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_start1"/>
- <register address="5" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_start2"/>
- <register address="7" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_start3"/>
- <register address="9" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_start4"/>
- <register address="11" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_start5"/>
- <register address="13" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_start6"/>
- <register address="15" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_start7"/>
- <register address="17" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_start8"/>
- <register address="19" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_number_lines1"/>
- <register address="21" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_number_lines2"/>
- <register address="23" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_number_lines3"/>
- <register address="25" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_number_lines4"/>
- <register address="27" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_number_lines5"/>
- <register address="29" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_number_lines6"/>
- <register address="31" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_number_lines7"/>
- <register address="33" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_number_lines8"/>
- <register address="35" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_sub_s"/>
- <register address="37" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_sub_a"/>
- <register address="39" offset="0" size="1" default="1" rwmask="0" mode="RW" name="cmosis_color"/>
- <register address="40" offset="0" size="2" default="0" rwmask="0" mode="RW" name="cmosis_image_flipping"/>
- <register address="41" offset="0" size="2" default="0" rwmask="0" mode="RW" name="cmosis_exp_flags"/>
- <register address="42" offset="0" size="24" default="1088" rwmask="0" mode="RW" name="cmosis_exp_time"><view view="formuu3"/><view view="enumm3"/></register>
- <register address="45" offset="0" size="24" default="1088" rwmask="0" mode="RW" name="cmosis_exp_step"/>
- <register address="48" offset="0" size="24" default="1" rwmask="0" mode="RW" name="cmosis_exp_kp1"/>
- <register address="51" offset="0" size="24" default="1" rwmask="0" mode="RW" name="cmosis_exp_kp2"/>
- <register address="54" offset="0" size="2" default="1" rwmask="0" mode="RW" name="cmosis_nr_slopes"/>
- <register address="55" offset="0" size="8" default="1" rwmask="0" mode="RW" name="cmosis_exp_seq"/>
- <register address="56" offset="0" size="24" default="1088" rwmask="0" mode="RW" name="cmosis_exp_time2"/>
- <register address="59" offset="0" size="24" default="1088" rwmask="0" mode="RW" name="cmosis_exp_step2"/>
- <register address="68" offset="0" size="2" default="1" rwmask="0" mode="RW" name="cmosis_nr_slopes2"/>
- <register address="69" offset="0" size="8" default="1" rwmask="0" mode="RW" name="cmosis_exp_seq2"/>
- <register address="70" offset="0" size="16" default="1" rwmask="0" mode="RW" name="cmosis_number_frames"/>
- <register address="72" offset="0" size="2" default="0" rwmask="0" mode="RW" name="cmosis_output_mode"/>
- <register address="78" offset="0" size="12" default="85" rwmask="0" mode="RW" name="cmosis_training_pattern"/>
- <register address="80" offset="0" size="18" default="0x3FFFF" rwmask="0" mode="RW" name="cmosis_channel_en"/>
- <register address="82" offset="0" size="3" default="7" rwmask="0" mode="RW" name="cmosis_special_82"/>
- <register address="89" offset="0" size="8" default="96" rwmask="0" mode="RW" name="cmosis_vlow2"/>
- <register address="90" offset="0" size="8" default="96" rwmask="0" mode="RW" name="cmosis_vlow3"/>
- <register address="100" offset="0" size="14" default="16260" rwmask="0" mode="RW" name="cmosis_offset"/>
- <register address="102" offset="0" size="2" default="0" rwmask="0" mode="RW" name="cmosis_pga"/>
- <register address="103" offset="0" size="8" default="32" rwmask="0" mode="RW" name="cmosis_adc_gain"/>
- <register address="111" offset="0" size="1" default="1" rwmask="0" mode="RW" name="cmosis_bit_mode"/>
- <register address="112" offset="0" size="2" default="0" rwmask="0" mode="RW" name="cmosis_adc_resolution"/>
- <register address="115" offset="0" size="1" default="1" rwmask="0" mode="RW" name="cmosis_special_115"/>
- </bank>
<bank bar="0" size="0x0200" protocol="software_registers" read_address="0x9000" write_address="0x9000" word_size="32" endianess="little" format="0x%lx" name="fpga" description="IPECamera Registers">
<register address="0x00" offset="0" size="32" default="0" rwmask="0" mode="RW" name="spi_conf_input"/>
<register address="0x10" offset="0" size="32" default="0" rwmask="0" mode="R" name="spi_conf_output"/>
@@ -105,54 +58,4 @@
<register address="0x1a0" offset="0" size="32" default="0x64" rwmask="0" mode="RW" name="ddr_max_frames"/>
<register address="0x1b0" offset="0" size="32" default="0" rwmask="0" mode="R" name="ddr_num_frames"/>
</bank>
- <bank bar="0" size="0x0200" protocol="software_registers" read_address="0x0" write_address="0x0" word_size="32" endianess="little" format="0x%lx" name="dma" description="DMA Registers"/>
- <transform path="/test/prop1" register="test_prop1" unit="C" read_from_register="(503975./1024000)*${/registers/fpga/sensor_temperature:C} - 27315./100" description="formula to get real fpga temperature from the fpga_temperature register in decimal"/>
- <transform name="formuu1" unit="C" read_from_register="(503975./1024000)*$value - 27315./100" write_to_register="($value + 27315./100)*(1024000./503975)" description="formula to get real fpga temperature from the fpga_temperature register in decimal"/>
- <transform name="formuu2" unit="C1" read_from_register="((1./4)*($value - 1200)) if $freq==0 else ((3./10)*($value - 1000))" write_to_register="4*$value + 1200 if $freq==0 else (10./3)*$value + 1000" description="formula to get real sensor temperature from the sensor_temperature register in decimal"/>
- <transform name="formuu3" unit="us" read_from_register="($value+(43./100))*129./(40*1000000)if $freq==0 else ($value+(43./100))*129./(48*1000000)" write_to_register="$value/129.*(40*1000000) - 43./100 if $freq==0 else $value/129.*(48*1000000) - 43./100" description="formula to get real exposure time from the cmosis_exp_time register in decimal"/>
- <enum name="enumm1" description="enum towards temperatures register">
- <name name="high" value="0x100" min="0x2" max="0x300"/>
- <name name="low" value="0x010"/>
- </enum>
- <enum name="enumm2" description="enum towards sensor_temperature register">
- <name name="high" value="0x120"/>
- <name name="low" value="0x010" min="0x00" max="0x020"/>
- </enum>
- <enum name="enumm3" description="enum towards cmosis_exp_register register">
- <name name="short" value="0x000"/>
- <name name="mid" value="0x010"/>
- <name name="long" value="0x100" min="0x0F0"/>
- </enum>
- <unit name="C">
- <transform unit="K" transform="$value+273.15"/>
- <transform unit="F" transform="$value*(9./5)+32"/>
- </unit>
- <unit name="K">
- <transform unit="C" transform="$value-273.15"/>
- <transform unit="F" transform="($value-273.15)*(9./5)+32"/>
- </unit>
- <unit name="F">
- <transform unit="C" transform="($value-32)*5./9"/>
- <transform unit="K" transform="($value+273.15-32)*5./9"/>
- </unit>
- <unit name="s">
- <transform unit="ms" transform="$value*1000"/>
- <transform unit="us" transform="$value*1000000"/>
- <transform unit="ns" transform="$value*1000000000"/>
- </unit>
- <unit name="ms">
- <transform unit="s" transform="$value/1000"/>
- <transform unit="us" transform="$value*1000"/>
- <transform unit="ns" transform="$value*1000000"/>
- </unit>
- <unit name="us">
- <transform unit="s" transform="$value/1000000"/>
- <transform unit="ms" transform="$value/1000"/>
- <transform unit="ns" transform="$value*1000"/>
- </unit>
- <unit name="ns">
- <transform unit="s" transform="$value/1000000000"/>
- <transform unit="ms" transform="$value/1000000"/>
- <transform unit="us" transform="$value/1000"/>
- </unit>
</model>
diff --git a/xml/test/cmosis.xml b/xml/test/cmosis.xml
new file mode 100644
index 0000000..45d2f6e
--- /dev/null
+++ b/xml/test/cmosis.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<model xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <bank bar="0" size="128" protocol="software_registers" read_address="0x9010" write_address="0x9000" word_size="8" endianess="little" format="%lu" name="cmosis" description="CMOSIS CMV2000 Registers">
+ <register address="1" offset="0" size="16" default="1088" rwmask="0" mode="RW" name="cmosis_number_lines" description="test"/>
+ <register address="3" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_start1"/>
+ <register address="5" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_start2"/>
+ <register address="7" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_start3"/>
+ <register address="9" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_start4"/>
+ <register address="11" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_start5"/>
+ <register address="13" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_start6"/>
+ <register address="15" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_start7"/>
+ <register address="17" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_start8"/>
+ <register address="19" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_number_lines1"/>
+ <register address="21" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_number_lines2"/>
+ <register address="23" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_number_lines3"/>
+ <register address="25" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_number_lines4"/>
+ <register address="27" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_number_lines5"/>
+ <register address="29" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_number_lines6"/>
+ <register address="31" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_number_lines7"/>
+ <register address="33" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_number_lines8"/>
+ <register address="35" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_sub_s"/>
+ <register address="37" offset="0" size="16" default="0" rwmask="0" mode="RW" name="cmosis_sub_a"/>
+ <register address="39" offset="0" size="1" default="1" rwmask="0" mode="RW" name="cmosis_color"/>
+ <register address="40" offset="0" size="2" default="0" rwmask="0" mode="RW" name="cmosis_image_flipping"/>
+ <register address="41" offset="0" size="2" default="0" rwmask="0" mode="RW" name="cmosis_exp_flags"/>
+ <register address="42" offset="0" size="24" default="1088" rwmask="0" mode="RW" name="cmosis_exp_time"><view view="formuu3"/><view view="enumm3"/></register>
+ <register address="45" offset="0" size="24" default="1088" rwmask="0" mode="RW" name="cmosis_exp_step"/>
+ <register address="48" offset="0" size="24" default="1" rwmask="0" mode="RW" name="cmosis_exp_kp1"/>
+ <register address="51" offset="0" size="24" default="1" rwmask="0" mode="RW" name="cmosis_exp_kp2"/>
+ <register address="54" offset="0" size="2" default="1" rwmask="0" mode="RW" name="cmosis_nr_slopes"/>
+ <register address="55" offset="0" size="8" default="1" rwmask="0" mode="RW" name="cmosis_exp_seq"/>
+ <register address="56" offset="0" size="24" default="1088" rwmask="0" mode="RW" name="cmosis_exp_time2"/>
+ <register address="59" offset="0" size="24" default="1088" rwmask="0" mode="RW" name="cmosis_exp_step2"/>
+ <register address="68" offset="0" size="2" default="1" rwmask="0" mode="RW" name="cmosis_nr_slopes2"/>
+ <register address="69" offset="0" size="8" default="1" rwmask="0" mode="RW" name="cmosis_exp_seq2"/>
+ <register address="70" offset="0" size="16" default="1" rwmask="0" mode="RW" name="cmosis_number_frames"/>
+ <register address="72" offset="0" size="2" default="0" rwmask="0" mode="RW" name="cmosis_output_mode"/>
+ <register address="78" offset="0" size="12" default="85" rwmask="0" mode="RW" name="cmosis_training_pattern"/>
+ <register address="80" offset="0" size="18" default="0x3FFFF" rwmask="0" mode="RW" name="cmosis_channel_en"/>
+ <register address="82" offset="0" size="3" default="7" rwmask="0" mode="RW" name="cmosis_special_82"/>
+ <register address="89" offset="0" size="8" default="96" rwmask="0" mode="RW" name="cmosis_vlow2"/>
+ <register address="90" offset="0" size="8" default="96" rwmask="0" mode="RW" name="cmosis_vlow3"/>
+ <register address="100" offset="0" size="14" default="16260" rwmask="0" mode="RW" name="cmosis_offset"/>
+ <register address="102" offset="0" size="2" default="0" rwmask="0" mode="RW" name="cmosis_pga"/>
+ <register address="103" offset="0" size="8" default="32" rwmask="0" mode="RW" name="cmosis_adc_gain"/>
+ <register address="111" offset="0" size="1" default="1" rwmask="0" mode="RW" name="cmosis_bit_mode"/>
+ <register address="112" offset="0" size="2" default="0" rwmask="0" mode="RW" name="cmosis_adc_resolution"/>
+ <register address="115" offset="0" size="1" default="1" rwmask="0" mode="RW" name="cmosis_special_115"/>
+ </bank>
+</model>
diff --git a/xml/test/dma.xml b/xml/test/dma.xml
new file mode 100644
index 0000000..1d20725
--- /dev/null
+++ b/xml/test/dma.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<model xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <bank bar="0" size="0x0200" protocol="software_registers" read_address="0x0" write_address="0x0" word_size="32" endianess="little" format="0x%lx" name="dma" description="DMA Registers"/>
+</model>
diff --git a/xml/test/names.xml b/xml/test/names.xml
new file mode 100644
index 0000000..f6ddbcc
--- /dev/null
+++ b/xml/test/names.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<model xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <enum name="enumm1" description="enum towards temperatures register">
+ <name name="high" value="0x100" min="0x2" max="0x300"/>
+ <name name="low" value="0x010"/>
+ </enum>
+ <enum name="enumm2" description="enum towards sensor_temperature register">
+ <name name="high" value="0x120"/>
+ <name name="low" value="0x010" min="0x00" max="0x020"/>
+ </enum>
+ <enum name="enumm3" description="enum towards cmosis_exp_register register">
+ <name name="short" value="0x000"/>
+ <name name="mid" value="0x010"/>
+ <name name="long" value="0x100" min="0x0F0"/>
+ </enum>
+</model>
diff --git a/xml/test/props.xml b/xml/test/props.xml
new file mode 100644
index 0000000..cf163eb
--- /dev/null
+++ b/xml/test/props.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0"?>
+<model xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <transform path="/test/prop1" register="test_prop1" unit="C" read_from_register="(503975./1024000)*${/registers/fpga/sensor_temperature:C} - 27315./100" description="formula to get real fpga temperature from the fpga_temperature register in decimal"/>
+</model>
diff --git a/xml/test/units.xml b/xml/test/units.xml
new file mode 100644
index 0000000..74ab9f7
--- /dev/null
+++ b/xml/test/units.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0"?>
+<model xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <unit name="C">
+ <transform unit="K" transform="$value+273.15"/>
+ <transform unit="F" transform="$value*(9./5)+32"/>
+ </unit>
+ <unit name="K">
+ <transform unit="C" transform="$value-273.15"/>
+ <transform unit="F" transform="($value-273.15)*(9./5)+32"/>
+ </unit>
+ <unit name="F">
+ <transform unit="C" transform="($value-32)*5./9"/>
+ <transform unit="K" transform="($value+273.15-32)*5./9"/>
+ </unit>
+ <unit name="s">
+ <transform unit="ms" transform="$value*1000"/>
+ <transform unit="us" transform="$value*1000000"/>
+ <transform unit="ns" transform="$value*1000000000"/>
+ </unit>
+ <unit name="ms">
+ <transform unit="s" transform="$value/1000"/>
+ <transform unit="us" transform="$value*1000"/>
+ <transform unit="ns" transform="$value*1000000"/>
+ </unit>
+ <unit name="us">
+ <transform unit="s" transform="$value/1000000"/>
+ <transform unit="ms" transform="$value/1000"/>
+ <transform unit="ns" transform="$value*1000"/>
+ </unit>
+ <unit name="ns">
+ <transform unit="s" transform="$value/1000000000"/>
+ <transform unit="ms" transform="$value/1000000"/>
+ <transform unit="us" transform="$value/1000"/>
+ </unit>
+</model>
diff --git a/xml/test/views.xml b/xml/test/views.xml
new file mode 100644
index 0000000..c40cd0f
--- /dev/null
+++ b/xml/test/views.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<model xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <transform name="formuu1" unit="C" read_from_register="(503975./1024000)*$value - 27315./100" write_to_register="($value + 27315./100)*(1024000./503975)" description="formula to get real fpga temperature from the fpga_temperature register in decimal"/>
+ <transform name="formuu2" unit="C1" read_from_register="((1./4)*($value - 1200)) if $freq==0 else ((3./10)*($value - 1000))" write_to_register="4*$value + 1200 if $freq==0 else (10./3)*$value + 1000" description="formula to get real sensor temperature from the sensor_temperature register in decimal"/>
+ <transform name="formuu3" unit="us" read_from_register="($value+(43./100))*129./(40*1000000)if $freq==0 else ($value+(43./100))*129./(48*1000000)" write_to_register="$value/129.*(40*1000000) - 43./100 if $freq==0 else $value/129.*(48*1000000) - 43./100" description="formula to get real exposure time from the cmosis_exp_time register in decimal"/>
+</model>