Commit d50bbadc authored by Federico Vaga's avatar Federico Vaga

doc: update documentation

This re-write the documentation in sphinx. It also adds
an example program that can be used to copy and paste code or
to quote it in the documentation.
Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent c8db46a3
doxy-adclib/
*.log
\ No newline at end of file
doxygen-lib-output/
*.log
_build
\ No newline at end of file
GIT_VERSION = $(shell cd $(src); git describe --dirty --long --tags)
# Minimal makefile for Sphinx documentation
#
O ?= doxy-adclib
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
SPHINXPROJ = FMCADC100M14bit4Channel
SOURCEDIR = .
BUILDDIR = _build
# Build the documentation with or without the internals details
ifdef SHOW_INTERNALS
EXCLUDE_FILES = ""
BRIEF = "API Documentation - With Internals"
else
EXCLUDE_FILES = "../lib/adc-lib-int.h"
BRIEF = "API Documentation"
endif
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
all: doxygen
.PHONY: help Makefile doxygen doxygen-clean
doxygen:
GIT_VERSION=$(GIT_VERSION) EXCLUDE_FILES=$(EXCLUDE_FILES) BRIEF=$(BRIEF) \
OUTPUT=$(O) doxygen ./doxygen-adclib-config
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
$(MAKE) doxygen TARGET=$@
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
clean:
rm -rf $(O)
# Latex stuff
rm -f *.dvi *.aux *.out *.log *.backup *.pdf
GIT_VERSION = $(shell cd $(src); git describe --dirty --long --tags)
doxygen:
ifeq ($(TARGET),clean)
@echo "Remove Doxygen files"
@rm -rf doxygen-lib-output
else
GIT_VERSION=$(GIT_VERSION) EXCLUDE_FILES=$(EXCLUDE_FILES) doxygen ./doxygen-adclib-config
endif
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# FMC ADC 100M 14 bit 4 Channel documentation build configuration file, created by
# sphinx-quickstart on Thu Jan 25 09:54:50 2018.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ['sphinx.ext.autodoc',
'sphinx.ext.todo',
'sphinx.ext.coverage',
'sphinx.ext.graphviz',
'breathe']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = 'ADC Library'
copyright = 'CERN 2018, Federico Vaga <federico.vaga@cern.ch>'
author = 'Federico Vaga <federico.vaga@cern.ch>'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '2.0'
# The full version, including alpha/beta/rc tags.
release = '2.0.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
highlight_language = 'none'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store', 'doxygen-lib-output']
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = True
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
#html_theme = 'alabaster'
html_theme = "sphinx_rtd_theme"
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# This is required for the alabaster theme
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
html_sidebars = {
'**': [
'relations.html', # needs 'show_related': True theme option to display
'searchbox.html',
]
}
# -- Options for HTMLHelp output ------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'adclibdoc'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'adclib.tex', 'ADC Library Documentation',
'Federico Vaga \\textless{}federico.vaga@cern.ch\\textgreater{}', 'manual'),
]
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'adclib', 'ADC Library Documentation',
[author], 1)
]
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'adclib', 'ADC Library Documentation',
author, 'adclib', 'One line description of project.',
'Miscellaneous'),
]
# -- Options for Epub output ----------------------------------------------
# Bibliographic Dublin Core info.
epub_title = project
epub_author = author
epub_publisher = author
epub_copyright = copyright
# The unique identifier of the text. This can be a ISBN number
# or the project homepage.
#
# epub_identifier = ''
# A unique identification for the text.
#
# epub_uid = ''
# A list of files that should not be packed into the epub file.
epub_exclude_files = ['search.html']
smart_quotes = False
breathe_projects = {
"adc-lib":"doxygen-lib-output/xml/",
}
breathe_default_project = "adc-lib"
PROJECT_NAME = "Generic ADC Library - GAL"
PROJECT_NUMBER = $(GIT_VERSION)
PROJECT_BRIEF = $(BRIEF)
PROJECT_BRIEF = "Generic ADC Library API"
PROJECT_LOGO =
OUTPUT_DIRECTORY = $(OUTPUT)
OUTPUT_DIRECTORY = doxygen-lib-output
CREATE_SUBDIRS = YES
TAB_SIZE = 8
OPTIMIZE_OUTPUT_FOR_C = YES
......@@ -16,5 +16,6 @@ INPUT = ../lib
RECURSIVE = YES
EXCLUDE = $(EXCLUDE_FILES)
GENERATE_LATEX = NO
GENERATE_HTML = YES
GENERATE_LATEX = YES
GENERATE_XML = YES
This diff is collapsed.
Welcome to the ADC library documentation!
==============================================
This is the documentation for the programmer's interface (API) that
is expected to accompany most or all of the ADC cards being developed
and used by the Controls group at CERN.
This design is the outcome of email discussion between Michel Arruat,
David Cobas, Federico Vaga and Alessandro Rubini in March 2013. Ideas
have later been refined during real use. Mainly Alessandro wrote this
document.
The aim of this project is to provide a generic API for ADC devices (drivers).
The advantage of sharing the same API among different applications is that we
can concentrate to provide a single stable and robust entry point for a
variety of boards and driver types, and on the application side it allows to
write generic tools that may work with any ADC.
The `ADC library`_ project developed on the `Open Hardware Repository`_.
.. _`Open Hardware Repository`: http://www.ohwr.org/
.. _`ADC library`: http://www.ohwr.org/projects/adc-lib
.. toctree::
:maxdepth: 2
:caption: Contents:
library-user
library-devel
library-api
tools-adc-acq
tools-example
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
graph layers {
user [label="User Programs"];
api [label="ADC API", shape=box];
route [label="Routing", shape=diamond];
lib1 [label="Board\nLibrary 1", shape=box];
lib2 [label="Board\nLibrary 2", shape=box];
lib3 [label="Board\nLibrary 3", shape=box];
drv1 [label="Driver 1"];
drv2 [label="Driver 2"];
drv3 [label="Driver 3"];
edge [color=gray];
user -- api;
subgraph library {
label="ADC Library";
style=filled;
color=red;
node [style=filled, color=lightgray];
edge [color=black, style=bold];
api -- route;
route -- lib1;
route -- lib2;
route -- lib3;
}
edge [color=gray];
lib1 -- drv1;
lib2 -- drv2;
lib3 -- drv3;
}
\ No newline at end of file
The Library API
================
Enumerations And Constants
-----------------------------
.. doxygenenum:: adc_supported_boards
.. doxygenenum:: adc_configuration_type
.. doxygenenum:: adc_configuration_trigger_ext
.. doxygenenum:: adc_configuration_trigger_thr
.. doxygenenum:: adc_configuration_acquisition
.. doxygenenum:: adc_configuration_channel
.. doxygenenum:: adc_configuration_board
Board Specific
''''''''''''''
FMC ADC 100M 14 bit 4 Channel
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. doxygenenum:: adc_configuration_100m14b4cha
Data Structures
---------------
.. doxygenstruct:: adc_conf
:members:
.. doxygenstruct:: adc_buffer
:members:
.. doxygenstruct:: adc_timestamp
:members:
Functions
----------
.. doxygenfunction:: adc_init
.. doxygenfunction:: adc_exit
.. doxygenfunction:: adc_strerror
.. doxygenfunction:: adc_open
.. doxygenfunction:: adc_open_by_lun
.. doxygenfunction:: adc_close
.. doxygenfunction:: adc_apply_config
.. doxygenfunction:: adc_retrieve_config
.. doxygenfunction:: adc_set_conf_mask
.. doxygenfunction:: adc_set_conf_mask_all
.. doxygenfunction:: adc_set_conf
.. doxygenfunction:: adc_get_conf
.. doxygenfunction:: adc_reset_conf
.. doxygenfunction:: adc_get_capabilities
.. doxygenfunction:: adc_set_param
.. doxygenfunction:: adc_get_param
.. doxygenfunction:: adc_acq_start
.. doxygenfunction:: adc_acq_poll
.. doxygenfunction:: adc_acq_stop
.. doxygenfunction:: adc_request_buffer
.. doxygenfunction:: adc_release_buffer
.. doxygenfunction:: adc_fill_buffer
.. doxygenfunction:: adc_tstamp_buffer
.. doxygenfunction:: adc_trigger_fire
The Library For Developers
============================
Sources Organization
---------------------
Mainly the sources are organized in four main directory.
**lib**
It contains the library sources and the relative building output
**tools**
It contains the tools sources and the relative building output
**tests**
It containes the tests sources for automatic tests and the relative
building output
**doc**
It containes the *sphinx* documentation sources and the relative
building output
Library
-------
You can find the library sources in the directory *lib*.
There are two header files: ``adc-lib.h`` and ``adc-lib-int.h``. The first,
it is the one used to export the library symbols to user space: the API.
The latter is used to export symbols among the internal library sources.
.. graphviz:: layers.dot
:align: center
As shown in the graph above, the library has an internal routing mechanism
that redirect the user's requests to the correct board-specific logic.
Almost all the routing mechanism is implemented in the ``route.c`` file.
These functions are then exported to the users by declaring them in the
``adc-lib.h`` file.
The source file ``lib.c`` contains a collection of library's helpers that
the users may find handy to deal with most common procedures.
Finally, the ``init.c`` source file contains all the initialization code.
For the time being this is empty, but we may fill it in the future.
The structure above shows the organization of the generic code. For the
specialized code there are not many rule. The main rule is to have at least
one source file for each board-type where to put the specific code.
The specific code means, in other words, to implement all the operations
in ``struct adc_operations`` and to declare a new ``struct adc_board_type``.
Board-Specific Code (How To)
''''''''''''''''''''''''''''
The first step is to create a new source file in *lib* named as the board
type (or something similar) in order to be able to distinguish it.::
touch newboard-type.c
To add the new file to the building system, you just need to add the object
file to the Makefile variable ``LOBJ``::
LOBJ += newboard-type.o
The minimum implementation requires you to declare a new
``struct adc_board_type`` and the operations in ``struct adc_operations``::
static struct adc_operations newboard_ops = {
/* implement the operations */
};
struct adc_board_type newboard = {
/* fill the attributes */
};
Then, in order to have a compiling system, you have to:
- export the new *adc_board_type* in ``adc-lib-int.h``
- add a new board type in ``enum adc_supported_boards`` in ``adc-lib.h``
- add the board type and the name respectively in ``adc_board_name`` and
``adc_board_types`` in ``route.c``
At this point you should have the new board correctly exported.
If your new board has some custum configuration or dedicated function,
you must not use the ``adc-lib.h`` header file to export them. Instead,
create a new header file.
Tools
------
The aim of this project is not to develop tools, but to develop a generic
library; for this reason device-specific tools are not accepted. The main
purpose of the tools is to show to the user show to use the library, and
to provide a basic testing tool that can be used to handle generic
acquisition.
Each tool shall have a dedicated source file and it shall be compiled using
the static linkage with the library.
In principle, in order to add a new tool you have to:
- create a new source file in the directory *tools*
- add a new entry in the Makefile variable ``DEMO`` with the name of the source
file without the *.c* extension
Tests
-----
In the directory *tests* you can find all the automatic tests used to validate
the different devices supported by the library and to validate the library
itself.
Documentation
---------------
The documentation is based on the `Sphinx`_ documentation framework.
The documents are written in ReStructuredText format with the addition
of some *sphinx* directive.
In order to build the documentation you can run one of the following
commands from the *doc* directory::
make html
make epub
make latexpdf
You will find the generated documentation in the respective sub-directories
in *doc/_build/*.
_`Sphinx`: http://www.sphinx-doc.org/en/master/
_`ReStructuredText`: http://docutils.sourceforge.net/docs/user/rst/quickref.html
This diff is collapsed.
The ``adc-acq`` Tools
========================
The ``adc-acq`` is supposed to be a generic tool to be used to driver
acquisitions. The tool tries to export all the library's features to
its users.
Generally speaking, this is not a tool that you should use operationally.
This tools is supposed to be used as a tesing tool.
Instead of having a dedicated command line argument for each of the
possible ADC configuration options, we decided to use configuration
strings. This has the advantage to simplify the code and the simplify
the usage of the tool, especially when the user wants to configure
many things.
For most of the option the help message from the ``adc-acq`` tools is
self-explanatory. Probably the configuration strings need some clarifications.
Acquisition (``--acquisition <pre-sample>,<post-sample>,<n-shots>,<undersample>``)
The *<pre-sample>* is the number of sample to acquire before the trigger.
The *<post-sample>* is the number of samples to acquire after the trigger
(including the sample that triggered the acquisition).
The *<n-shots>* is the number of consecutive acquisition to perform with
the same configuration.
The *<undersample>* is a factor used to reducing the sampling rate buy
skipping samples (e.g. undersample=3 will get 1 sample every 3).
Channel (``--channel <channel>,<termination>,<range>,<offset>,<saturation>``)
The *<channel>* is the channel index in the range [0, N].
The *<termination>* is 0 to disable or 1 to enable the termination on the
channel.
The *<range>* is the operation voltage range of the ADC. This value
depends on the device in use
The *<offset>* is used to move the signal.
The *<saturation>* is the value at which the channel must saturate.
External Trigger (``--trg-ext <idx>,<enable>,<polarity>,<delay>``)
The *<idx>* is the Nth external trigger channel in the range [0, N].
The *<polarity>* is 0 for positive edge/slope or 1 for negative edge/slope.
The *<delay>* is number of samples to wait before actually starting the
acquisition (without account for undersampling).
Threshold Trigger (``--trg-thr <idx>,<enable>,<polarity>,<threshold>,<hysteresis>,<delay>``)
The index *<idx>* is the Nth threshold trigger channel in the range [0, N].
The polarity *<polarity>* is 0 for positive edge/slope or 1 for
negative edge/slope.
The threshold *<threshold>* is the raw value that makes trigger the ADC on
a given channel.
The hysteresis *<hysteresis>* is the error tollerance for the threshold.
The delay *<delay>* is number of samples to wait before actually starting
the acquisition (without account for undersampling).
Timer Trigger (``--trg-tim``)
Not implemented yet
.. literalinclude:: ../tools/adc-acq.c
:language: c
The Example Tools
====================
You are not supposed to use this tool because its main purpose is to be an
example for the users of this library. You can use this a copy'n'paste code
in your sources.
.. literalinclude:: ../tools/example.c
:language: c
......@@ -27,49 +27,47 @@ struct adc_dev *adc_internal_open(const struct adc_board_type *b,
* The operations structure is the device-specific backend of the library
*/
struct adc_operations {
typeof(adc_internal_open) *open;
typeof(adc_close) *close; /**< @copydoc adc_close */
typeof(adc_internal_open) *open; /**< @related adc_open */
typeof(adc_close) *close; /**< @related adc_close */
typeof(adc_acq_start) *acq_start; /**< @copydoc adc_acq_start */
typeof(adc_acq_poll) *acq_poll; /**< @copydoc adc_acq_poll */
typeof(adc_acq_stop) *acq_stop; /**< @copydoc adc_acq_stop */
typeof(adc_acq_start) *acq_start; /**< @related adc_acq_start */
typeof(adc_acq_poll) *acq_poll; /**< @related adc_acq_poll */
typeof(adc_acq_stop) *acq_stop; /**< @related adc_acq_stop */
typeof(adc_apply_config) *apply_config; /**< @copydoc adc_apply_config */
typeof(adc_retrieve_config) *retrieve_config; /**< @copydoc adc_retrieve_config */
typeof(adc_get_param) *get_param; /**< @copydoc adc_acq_get_param */
typeof(adc_set_param) *set_param; /**< @copydoc adc_acq_set_param */
typeof(adc_apply_config) *apply_config; /**< @related adc_apply_config */
typeof(adc_retrieve_config) *retrieve_config; /**< @related adc_retrieve_config */
typeof(adc_get_param) *get_param; /**< @related adc_acq_get_param */
typeof(adc_set_param) *set_param; /**< @related adc_acq_set_param */
typeof(adc_request_buffer) *request_buffer; /**< @copydoc adc_request_buffer */
typeof(adc_fill_buffer) *fill_buffer; /**< @copydoc adc_fill_buffer */
typeof(adc_tstamp_buffer) *tstamp_buffer; /**< @copydoc adc_tstamp_buffer */
typeof(adc_release_buffer) *release_buffer; /**< @copydoc adc_release_buffer */
typeof(adc_request_buffer) *request_buffer; /**< @related adc_request_buffer */
typeof(adc_fill_buffer) *fill_buffer; /**< @related adc_fill_buffer */
typeof(adc_tstamp_buffer) *tstamp_buffer; /**< @related adc_tstamp_buffer */
typeof(adc_release_buffer) *release_buffer; /**< @related adc_release_buffer */
typeof(adc_trigger_fire) *trigger_fire; /**< @copydoc adc_trigger_fire */
typeof(adc_trigger_fire) *trigger_fire; /**< @related adc_trigger_fire */
};
/**
* This structure describes the board supported by the library
* @name name of the board type, for example "fmc-adc-100MS"
* @devname name of the device in Linux
* @driver_type: the kind of driver that hanlde this kind of board (e.g. ZIO)
* @capabilities bitmask of device capabilities for trigger, channel
* acquisition
* @adc_op pointer to a set of operations
*/
struct adc_board_type {
char *name;
char *devname;
char *driver_type;
uint32_t capabilities[__ADC_CONF_TYPE_LAST_INDEX];
struct adc_operations *adc_op;
char *name; /**< name of the board type, for example "fmc-adc-100MS" */
char *devname; /**< name of the device in Linux */
char *driver_type; /**< the kind of driver that hanlde this kind of
board (e.g. ZIO) */
uint32_t capabilities[__ADC_CONF_TYPE_LAST_INDEX]; /**< bitmask of
device
capabilities */
struct adc_operations *adc_op; /**< pointer to a set of operations */
};
/*
/**
* Generic Instance Descriptor
*/
struct adc_gid {
const struct adc_board_type *board;
const struct adc_board_type *board; /**< board */
};
/* Definition of board types */
......@@ -77,41 +75,47 @@ extern struct adc_board_type fmcadc_100ms_4ch_14bit;
extern struct adc_board_type adc_ziofake;
extern struct adc_board_type adc_genericfake;
/* Internal structure (ZIO specific, for ZIO drivers only) */
/**
* Internal structure for ZIO drivers only
*/
struct __adc_dev_zio {
unsigned int cset;
int fdc;
int fdd;
uint32_t dev_id;
unsigned long flags;
char *devbase;
char *sysbase;
unsigned long samplesize;
unsigned long pagesize;
unsigned int cset; /**< channel-set index */
int fdc; /**< control file descriptor */
int fdd; /**< data file descriptor */
uint32_t dev_id; /**< ZIO device ID */
unsigned long flags; /**< internal flags */
char *devbase; /**< base path to char-device */
char *sysbase; /**< base path to device sysfs */
unsigned long samplesize; /**< size of 1 sample */
unsigned long pagesize; /**< size of 1 page */
/* Mandatory field */
struct adc_gid gid;
struct adc_gid gid; /**< general ADC descriptor */
};
/**
* Configuration options for the generic-fake board
*/
struct __adc_genfake_conf {
int nshots;
int presamples;
int postsamples;
int nshots; /**< number of shots */
int presamples; /**< number of pre-samples */
int postsamples; /**< number of post-samples */
};
/* Internal structure for generic (not ZIO) fake board type*/
/**
* Internal structure for generic-fake board type
*/
struct __adc_dev_genfake {
int acq;
unsigned int conf_index;
unsigned int conf_type;
unsigned long samplesize;
struct __adc_genfake_conf *cf;
struct adc_gid gid;
int acq; /**< acquisition status */
unsigned int conf_index; /**< conf_index */
unsigned int conf_type; /**< conf_type */
unsigned long samplesize; /**< size of 1 sample */
struct __adc_genfake_conf *cf; /**< local configuration */
struct adc_gid gid; /**< general ADC descriptor */
};
/* Note: bit 16 and up are passed by users, see fmcadc-lib.h */
#define ADC_FLAG_VERBOSE 0x00000001
#define ADC_FLAG_MALLOC 0x00000002 /* allocate data */
#define ADC_FLAG_MMAP 0x00000004 /* mmap data */
#define ADC_FLAG_VERBOSE 0x00000001 /**< Internal verbose mode */
#define ADC_FLAG_MALLOC 0x00000002 /**< allocate data with malloc */
#define ADC_FLAG_MMAP 0x00000004 /**< use mmap to get data */
/* The board-specific functions are defined in fmc-adc-100m14b4cha.c */
......
......@@ -37,54 +37,43 @@ extern const char *adc_board_name[];
/**
* Enumerate all supported boards
* @enum ADC_GENERICFAKE It identifies a generic board for testing purpose
* @enum ADC_ZIOFAKE It identifies a generic board that supports the ZIO framework
* @enum FMCADC_100MS_4CH_14BIT It identifies the FMC ADC 100M 14Bit 4Channel
* @enum __ADC_SUPPORTED_BOARDS_LAST_INDEX It represents the the last index of
* this enum. It can be useful for some sort of automation
*/
enum adc_supported_boards {
FMCADC_100MS_4CH_14BIT = 0,
ADC_ZIOFAKE,
ADC_GENERICFAKE,
__ADC_SUPPORTED_BOARDS_LAST_INDEX,
FMCADC_100MS_4CH_14BIT = 0, /**< It identifies the FMC ADC 100M 14Bit
4Channel */
ADC_ZIOFAKE, /**< It identifies a generic board that supports the ZIO
framework */
ADC_GENERICFAKE, /**< It identifies a generic board for testing
purpose */
__ADC_SUPPORTED_BOARDS_LAST_INDEX, /**< It represents the the last
index of enum. It can be useful
for some sort of automation */
};
/**
* The buffer hosts data and metadata, plus informative fields
* @var data container for all the samples
* @var metadata description of the acquisition
* @var samplesize size of a single sample in Byte
* @var nsamples number of samples in the buffer
* @var dev the device used for the acquisition
* @var mapaddr mmap address
* @var maplen mmap length
* @var flags internal to the library
*/
struct adc_buffer {
void *data;
void *metadata;
int samplesize;
int nsamples;
struct adc_dev *dev;
void *mapaddr;
unsigned long maplen;
unsigned long flags;
void *data; /**< container for all the samples */
void *metadata; /**< description of the acquisition */
int samplesize; /**< size of a single sample in Byte */
int nsamples; /**< number of samples in the buffer */
struct adc_dev *dev; /**< the device used for the acquisition */
void *mapaddr; /**< mmap address */
unsigned long maplen; /**< mmap length */
unsigned long flags; /**< internal to the library */
};
/**
* Timestamp descriptor. This is should be big enough to store *any*
* time stamp.
* @var secs number of seconds
* @var ticks number of coarse sub-seconds unit
* @var bins high resolution sub-seconds unit
*/
struct adc_timestamp {
uint64_t secs;
uint64_t ticks;
uint64_t bins;
uint64_t secs; /**< number of seconds */
uint64_t ticks; /**< number of coarse sub-seconds unit */
uint64_t bins; /**< high resolution sub-seconds unit */
};
......@@ -98,49 +87,57 @@ enum adc_trigger_polarity {
/**
* It describes the possible configuration option for an external trigger
* @enum ADC_CONF_TRG_EXT_ENABLE It enable/disable the trigger
* @enum ADC_CONF_TRG_EXT_POLARITY It is used to apply the polarity to the
* external triggers
* @enum ADC_CONF_TRG_EXT_DELAY acquisition delay after trigger.
* @enum __ADC_CONF_TRG_EXT_LAST_INDEX It represents the the last index of this
* enum. It can be useful for some sort of automation
* If not specified, the meaning of a configuration option depends on
* the board in use
*
* @todo we should have a generic definition and then the device-specific
* code dealing with the conversion
*/
enum adc_configuration_trigger_ext {
ADC_CONF_TRG_EXT_ENABLE,
ADC_CONF_TRG_EXT_POLARITY,
ADC_CONF_TRG_EXT_DELAY,
__ADC_CONF_TRG_EXT_LAST_INDEX,
ADC_CONF_TRG_EXT_ENABLE, /**< It enable/disable the trigger */
ADC_CONF_TRG_EXT_POLARITY, /**< It is used to apply the polarity to the
external triggers */
ADC_CONF_TRG_EXT_DELAY, /**< acquisition delay after trigger */
__ADC_CONF_TRG_EXT_LAST_INDEX, /**< It represents the the last index of
this enum. It can be useful for some
sort of automation */
};
/**
* It describes the possible configuration option for a threshold trigger
* @enum ADC_CONF_TRG_THR_ENABLE It enable/disable the trigger
* @enum ADC_CONF_TRG_THR_POLARITY It is used to apply the polarity to the
* threshold triggers
* @enum ADC_CONF_TRG_THR_DELAY It defines the acquisition delay after trigger
* @enum ADC_CONF_TRG_THR_THRESHOLD The threshold value that triggers
* the acquisition
* @enum ADC_CONF_TRG_THR_HYSTERESIS If defines the hysteresis associated to
* the threshold value
* @enum __ADC_CONF_TRG_THR_LAST_INDEX It represents the the last index of this
* enum. It can be useful for some sort of automation
* If not specified, the meaning of a configuration option depends on
* the board in use
*
* @todo we should have a generic definition and then the device-specific
* code dealing with the conversion
*/
enum adc_configuration_trigger_thr {
ADC_CONF_TRG_THR_ENABLE,
ADC_CONF_TRG_THR_POLARITY,
ADC_CONF_TRG_THR_DELAY,
ADC_CONF_TRG_THR_THRESHOLD,
ADC_CONF_TRG_THR_HYSTERESIS,
__ADC_CONF_TRG_THR_LAST_INDEX,
ADC_CONF_TRG_THR_ENABLE, /**< It enable (1) or disable (0) the trigger */
ADC_CONF_TRG_THR_POLARITY, /**< It is used to apply the polarity to the
threshold triggers */
ADC_CONF_TRG_THR_DELAY, /**< It defines the acquisition delay after
trigger */
ADC_CONF_TRG_THR_THRESHOLD, /**< The threshold value that triggers
the acquisition */
ADC_CONF_TRG_THR_HYSTERESIS, /**< If defines the hysteresis associated
to the threshold value */
__ADC_CONF_TRG_THR_LAST_INDEX, /**< It represents the the last index
of this enum. It can be useful for
some sort of automation */
};
/**
* It describes the possible configuration option for a time trigger
* If not specified, the meaning of a configuration option depends on
* the board in use
*
* @todo we should have a generic definition and then the device-specific
* code dealing with the conversion
*/
enum adc_configuration_trigger_tim {
ADC_CONF_TRG_TIM_ENABLE, /**< It enable/disable the trigger */
ADC_CONF_TRG_TIM_ENABLE, /**< It enable (1) or disable (0) the trigger */
__ADC_CONF_TRG_TIM_LAST_INDEX, /**< It represents the the last index
of this enum. It can be useful for
some sort of automation */
......@@ -168,6 +165,11 @@ enum adc_configuration_acquisition {
/**
* This represents the list of configuration options for the channels
* when using ``conf->type = ADC_CONF_TYPE_CHN``
* If not specified, the meaning of a configuration option depends on
* the board in use
*
* @todo we should have a generic definition and then the device-specific
* code dealing with the conversion
*/
enum adc_configuration_channel {
ADC_CONF_CHN_RANGE = 0, /**< Volt range */
......@@ -185,6 +187,11 @@ enum adc_configuration_channel {
/**
* This represents the list of configuration options for the board status
* when using ``conf->type = ADC_CONF_TYPE_BRD``
* If not specified, the meaning of a configuration option depends on
* the board in use
*
* @todo we should have a generic definition and then the device-specific
* code dealing with the conversion
*/
enum adc_configuration_board {
ADC_CONF_BRD_STATUS = 0, /**< Board status */
......@@ -210,6 +217,11 @@ enum adc_configuration_board {
/**
* It describes the possible configuration types
* If not specified, the meaning of a configuration option depends on
* the board in use
*
* @todo we should have a generic definition and then the device-specific
* code dealing with the conversion
*/
enum adc_configuration_type {
ADC_CONF_TYPE_BRD = 0, /**< Configuration for the board */
......@@ -231,22 +243,18 @@ enum adc_configuration_type {
/**
* ADC configuration descriptor.
* @var type configuration type
* @var dev_type device type
* @var route_to internal route to a particular sub-device (e.g. a channel)
* @var flags FIXME how to identify invalid?
* @var mask capabilities mask, 1 when the correspondent value in ``value[]``
* is valid
* @var value array of configuration value. The position in the array
* correspond to a specific capability
*/
struct adc_conf {
enum adc_configuration_type type;
uint32_t dev_type;
uint32_t route_to;
uint32_t flags;
uint64_t mask;
uint32_t value[__ADC_CONF_LEN];
enum adc_configuration_type type; /**< configuration type */
uint32_t dev_type; /**< device type */
uint32_t route_to; /**< internal route to a particular sub-device
(e.g. a channel) */
uint32_t flags; /**< FIXME how to identify invalid? */
uint64_t mask; /**< capabilities mask, 1 when the correspondent
value in ``value[]`` is valid */
uint32_t value[__ADC_CONF_LEN]; /**< array of configuration value.
The position in the array correspond
to a specific capability */
};
......@@ -342,6 +350,7 @@ static inline int adc_get_conf(struct adc_conf *conf,
return -1;
}
}
extern int adc_reset_conf(struct adc_dev *dev, unsigned int flags,
struct adc_conf *conf);
extern int adc_apply_config(struct adc_dev *dev, unsigned int flags,
......
......@@ -257,15 +257,18 @@ struct adc_dev *adc_open(char *name, unsigned int dev_id,
* at the same time by the application.
* @param[in] flags currently it supports: ADC_F_FLUSH, ADC_F_VERBOSE
*
* @return It returns an opaque object describing the device.
* It should be passed around but not be looked into.
*
* @todo make it generic, now it works only for the CERN environment
* with the adc-100m14b. Actually I (Federico) believe that this
* is impossible to make it generic enough
* @todo some udev rule should create symlink to map lun->devid
*/
struct adc_dev *adc_open_by_lun(char *name, int lun,
unsigned long buffersize,
unsigned int nbuffer,
unsigned long flags)
unsigned long buffersize,
unsigned int nbuffer,
unsigned long flags)
{
ssize_t ret;
char dev_id_str[8];
......@@ -288,6 +291,12 @@ struct adc_dev *adc_open_by_lun(char *name, int lun,
}
/**
* It closes the link with the ADC devices previously opened with adc_open()
* @param[in] dev the device token from adc_open()
* @return It returns 0 on success, otherwise -1 and errno is appropriately set
*/
int adc_close(struct adc_dev *dev)
{
struct adc_gid *b = (struct adc_gid *)dev;
......
......@@ -9,12 +9,20 @@ const char * const libadc_version_s = "libadc version: " GIT_VERSION;
const char * const libadc_zio_version_s = "libadc is using zio version: " ZIO_GIT_VERSION;
const char * const libadc_fmcadc100m14b4cha_version_s = "libadc is using fmc-adc-100m14b4cha version: " FMCADC_100MS_4CH_14BIT_GIT_VERSION;
/* We currently do nothing in init/exit. We might check /proc/meminfo... */
/**
* It initializes the library
* @return 0 on success, otherwise -1 and errno is set appropriately
*/
int adc_init(void)
{
return 0;
}
/**
* It releases the resources holded by the library
*/
void adc_exit(void)
{
return;
......
......@@ -15,9 +15,12 @@
/* * * * * * * * * * * * * * * * Utilities * * * * * * * * * * * * * * * * */
/**
* This the table of the error messages
*/
static struct adc_errors {
int num;
char *str;
int num; /**< the errno that linked to the message */
char *str; /**< the message associated to the errno */
} adc_errors[] = {
{ ADC_ENOP, "Operation not supported"},
{ ADC_ENOCAP, "Capabilities not supported"},
......@@ -31,6 +34,16 @@ static struct adc_errors {
{ 0, }
};
/**
* It returns a string describing an error number
* @param[in] errnum the error number to describe
* @return a string representing a message error. The function returns static
* storage, so you can keep around the pointer it returns, if needed.
* Similarly, there is no concurrency between getting the string and
* using it, not even in multithreaded environments (``errno`` itself
* is already protected, in this respect).
*/
char *adc_strerror(int errnum)
{
struct adc_errors *p;
......
......@@ -23,13 +23,22 @@
/**
* It starts an acquisition on the given device
* It tells hardware to start the acquisition on the given device according
* to the current configuration (but starting in itself is usually a fast
* operation, because it doesn't rewrite configuration to the hardware,
* at least with currently supported boards).
* It can return immediately or wait for completion, with a timeout.
* @param[in] dev ADC device token
* @param[in] flags flags to control the acquisition options
* @param[in] timeout time to wait to conclude the acquisition. When 0,
* the acquisition will run in backgroun and you can
* use adc_acq_poll() to check for data.
* ADC_F_FLUSH - discard prevoius leftover data before activating
* the acquisition (if any is there)
* @param[in] timeout The timeout is used like the argument for ``select(2)``:
* if NULL, the functions wait forever, otherwise they specify the
* maximum allowed waiting time -- and passing zero values asks to not wait
* at all (you can use adc_acq_poll() later).
*
* @return 0 on success, -1 on error and errno is set appropriately
* ADC_EDISABLED - acquisition disabled or aborted
*/
int adc_acq_start(struct adc_dev *dev,
unsigned int flags,
......@@ -43,13 +52,22 @@ int adc_acq_start(struct adc_dev *dev,
/**
* It waits for acquisition to complete.
* It polls the given device to check if data is available
* @param[in] dev ADC device token
* @param[in] flags flags to specify how to poll
* @param[in] timeout The timeout is used like the argument for ``select(2)``:
* if NULL, the functions wait forever, otherwise they specify the
* maximum allowed waiting time -- and passing zero values asks to not wait
* at all.
* @return 0 on success, -1 on error and errno is set appropriately
* ADC_EDISABLED - acquisition disabled or aborted
*
* @todo For multi-shot we would like to return the number of
* still-missing shots, but this is not yet supported.
*/
int adc_acq_poll(struct adc_dev *dev, unsigned int flags,
struct timeval *timeout)
struct timeval *timeout)
{
struct adc_gid *g = (struct adc_gid *)dev;
const struct adc_board_type *b = g->board;
......@@ -59,7 +77,8 @@ int adc_acq_poll(struct adc_dev *dev, unsigned int flags,
/**
* It stops the acquisition on the given device
* It stops an already-begun acquisition. It is not expected to be of
* frequent use.
* @param[in] dev ADC device token
* @param[in] flags flags to specify how to stop
* @return 0 on success, -1 on error and errno is set appropriately
......@@ -175,13 +194,14 @@ int adc_set_param(struct adc_dev *dev, char *name,
/**
* It requests a buffer where store data from the acquisition
* It allocates an empty buffer where store data from the acquisition
* @param[in] dev ADC device token
* @param[in] nsamples size of the buffer in number of samples
* @param[in] alloc when set it will use the given function to allocate
* the buffer
* @param[in] flags flags to control the buffer request
* @return 0 on success, -1 on error and errno is set appropriately
* @return It returns a valid pointer on success, otherwise NULL and errno
* is set appropriately
*/
struct adc_buffer *adc_request_buffer(struct adc_dev *dev,
int nsamples,
......@@ -201,8 +221,15 @@ struct adc_buffer *adc_request_buffer(struct adc_dev *dev,
* @param[in] dev ADC device token
* @param[in] buf the buffer to fill
* @param[in] flags used to control how to fill the buffer
* @param[in] timeout maximum time to fill the buffer
* @param[in] timeout maximum time to fill the buffer. The behavior
* is similar to *select(1)*. If NULL, there is no timeout and
* the function will wait until the data is ready.
* @return 0 on success, -1 on error and errno is set appropriately
* ADC_EDISABLED - when the acquisition is disabled or aborted
* ETIMEDOUT - timeout
*
* The size of the buffer must be at least equal to the size of the shot
* that library should copy into; otherwise, the result is undefined.
*/
int adc_fill_buffer(struct adc_dev *dev,
struct adc_buffer *buf,
......@@ -217,13 +244,19 @@ int adc_fill_buffer(struct adc_dev *dev,
/**
* It gets the timestamp of a given buffer
* @param[in] dev ADC device token
* It gets the timestamp of a given buffer, in a driver-specific way
* (most likely looking in the metadata structure).
* @param[in] buf the buffer of interest
* @param[out] ts the buffer timestamp
* @return the buffer timestamp
*
* If the caller passes a ``ts`` pointer, the timestamp is copied into
* that pointer and the same pointer is returned. If ``ts`` is NULL,
* the function returns a pointer of its own choice, that is only valid
* until the buffer is released.
*/
struct adc_timestamp *adc_tstamp_buffer(struct adc_buffer *buf,
struct adc_timestamp *ts)
struct adc_timestamp *ts)
{
struct adc_gid *g = (struct adc_gid *)buf->dev;
const struct adc_board_type *b = g->board;
......@@ -233,8 +266,11 @@ struct adc_timestamp *adc_tstamp_buffer(struct adc_buffer *buf,
/**
* It frees a given buffer
* It releases any resources associated with the buffer.
* @param[in] dev ADC device token
* @param[in] buf the buffer to fill
* @param free when set it will use the given function to release
* the buffer
* @return 0 on success, -1 on error and errno is set appropriately
*/
int adc_release_buffer(struct adc_dev *dev, struct adc_buffer *buf,
......
......@@ -3,4 +3,5 @@ fald-test
fald-simple-get-conf
fald-acq
fald-trg-cfg
fald-bad-clock
\ No newline at end of file
fald-bad-clock
example
......@@ -23,6 +23,7 @@ LDLIBS += -Wl,-Bstatic -ladc
LDLIBS += -Wl,-Bdynamic -lrt
DEMOS := adc-acq
DEMOS += example
all: demo
......
......@@ -254,7 +254,6 @@ static void fald_acq_print_config(struct adc_dev *adc)
memset(&cfg, 0, sizeof(struct adc_conf));
cfg.type = ADC_CONF_TYPE_TRG_EXT;
adc_set_conf_mask_all(&cfg, adc);
adc_set_conf_mask_all(&cfg, adc);
err = adc_get_conf(&cfg_brd, ADC_CONF_BRD_N_TRG_EXT, &n);
if (err)
n = 0;
......
/* Copyright 2013 CERN
* Author: Federico Vaga <federico.vaga@cern.ch>
* License: GPLv2
*
* This is an example program that shows the different part of the library
* in action.
*
*
* This is part of the documentation, so when you change it **REMEMBER** to
* update the references in documents in `doc/`.
*
* The reason to have the example here as a true program is that we can always
* compile it and run it, so that we can validate the example.
* This way, at least for this aspect, the documentation in always aligned.
*
* Do not try to optimize this code, the purpose is to show code, highlight
* snippet and being able to refer to it from the documentation
*/
#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <adc-lib.h>
#define NSHOT 3
#define PRESAMPLES 5
#define POSTSAMPLES 5
static char *prog_name;
static int current_config_acquisition(struct adc_dev *adc);
static void process_buffer(struct adc_buffer *buf);
static int config_acquisition(struct adc_dev *adc);
static int config_and_acquire(struct adc_dev *adc, struct adc_buffer *buf);
static int alloc_config_and_acquire(struct adc_dev *adc);
static int use_adc_library();
int main(int argc, char *argv[])
{
int err;
prog_name = argv[0];
err = adc_init();
if (err)
exit(EXIT_FAILURE);
err = use_adc_library();
if (err)
exit(EXIT_FAILURE);
adc_exit(); /* optional, indeed in the error condition
we do not do it */
exit(EXIT_SUCCESS);
}
static int use_adc_library()
{
struct adc_dev *adc;
int err;
/* Open the ADC */
adc = adc_open("adc-genericfake", 0x0000, 0, 0, ADC_F_FLUSH);
if (!adc) {
fprintf(stderr, "%s: Cannot open device: %s\n",
prog_name, adc_strerror(errno));
return -1;
}
err = alloc_config_and_acquire(adc);
adc_close(adc);
return err;
}
static int alloc_config_and_acquire(struct adc_dev *adc)
{
struct adc_buffer *buf;
int err;
buf = adc_request_buffer(adc, NSHOT * (PRESAMPLES + POSTSAMPLES),
NULL, 0);
if (!buf) {
fprintf(stderr, "%s: Cannot allocate buffer: (%d) %s\n",
prog_name, errno, adc_strerror(errno));
return -1;
}
err = config_and_acquire(adc, buf);
adc_release_buffer(adc, buf, NULL);
return err;
}
static int config_and_acquire(struct adc_dev *adc, struct adc_buffer *buf)
{
struct timeval tv = {0, 0};
int err, k;
err = config_acquisition(adc);
if (err)
return err;
/* stop any pending acquisition on the device */
err = adc_acq_stop(adc, 0);
if (err) {
fprintf(stderr,
"%s: cannot stop pending acquisition: (%d) %s\n",
prog_name, errno, adc_strerror(errno));
return err;
}
/* Start the acquisition without wait */
err = adc_acq_start(adc, ADC_F_FLUSH, &tv);
if (err) {
fprintf(stderr,
"%s: Cannot start acquisition: (%d) %s\n",
prog_name, errno, adc_strerror(errno));
return err;
}
for (k = 0; k < NSHOT; ++k) {
fprintf(stdout, "Shot %d/%d\n", k + 1, NSHOT);
/* Wait until the data is available */
err = adc_acq_poll(adc, 0 , NULL);
if (err) {
fprintf(stderr, "Failed to wait for data: (%d) %s\n",
errno, adc_strerror(errno));
break;
}
/* Fill the buffer with the data */
err = adc_fill_buffer(adc, buf, 0, NULL);
if (err) {
fprintf(stderr, "Failed to retrieve for data: (%d) %s\n",
errno, adc_strerror(errno));
break;
}
process_buffer(buf);
}
/* stop the acquisition on the device */
err = adc_acq_stop(adc, 0);
if (err) {
fprintf(stderr,
"%s: cannot stop the acquisition: (%d) %s\n",
prog_name, errno, adc_strerror(errno));
return err;
}
return 0;
}
static int config_acquisition(struct adc_dev *adc)
{
struct adc_conf cfg;
int err;
memset(&cfg, 0, sizeof(struct adc_conf));
cfg.type = ADC_CONF_TYPE_ACQ;
adc_set_conf(&cfg, ADC_CONF_ACQ_N_SHOTS, NSHOT);
adc_set_conf(&cfg, ADC_CONF_ACQ_POST_SAMP, POSTSAMPLES);
adc_set_conf(&cfg, ADC_CONF_ACQ_PRE_SAMP, PRESAMPLES);
err = adc_apply_config(adc, 0 , &cfg);
if (err) {
fprintf(stderr, "%s: Cannot configure acquisition: (%d) %s\n",
prog_name, errno, adc_strerror(errno));
return err;
}
/* read back the configuration */
current_config_acquisition(adc);
return 0;
}
static int current_config_acquisition(struct adc_dev *adc)
{
struct adc_conf cfg;
uint32_t sh, pr, po;
int err;
memset(&cfg, 0, sizeof(struct adc_conf));
cfg.type = ADC_CONF_TYPE_ACQ;
adc_set_conf_mask(&cfg, ADC_CONF_ACQ_N_SHOTS);
adc_set_conf_mask(&cfg, ADC_CONF_ACQ_POST_SAMP);
adc_set_conf_mask(&cfg, ADC_CONF_ACQ_PRE_SAMP);
err = adc_retrieve_config(adc, &cfg);
if (err) {
fprintf(stderr, "%s: Cannot configure acquisition: (%d) %s\n",
prog_name, errno, adc_strerror(errno));
return err;
}
adc_get_conf(&cfg, ADC_CONF_ACQ_N_SHOTS, &sh);
fprintf(stdout, "Number of shots: %d\n", sh);
adc_get_conf(&cfg, ADC_CONF_ACQ_POST_SAMP, &po);
fprintf(stdout, "Number of post-samples: %d\n", po);
adc_get_conf(&cfg, ADC_CONF_ACQ_PRE_SAMP, &pr);
fprintf(stdout, "Number of pre-samples: %d\n", pr);
return 0;
}
static void process_buffer(struct adc_buffer *buf)
{
struct adc_timestamp ts;
uint8_t *data;
int i;
adc_tstamp_buffer(buf, &ts);
fprintf(stdout,
"time: {secs:%"PRIu64" ticks:%"PRIu64" bins:%"PRIu64"}\n",
ts.secs, ts.ticks, ts.bins);
data = buf->data;
for (i = -PRESAMPLES; i < POSTSAMPLES; ++i, ++data)
fprintf(stdout, "sample: %d, value: 0x%02"PRIx8"\n",
i, *data);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment