The purpose of this document is to define rules and methods for level-1 software development.
The strategy to build the test tools for the KLOE readout system is based on the integration of different libraries, each of them written to access a given module. In order to allow an easy integration, each developer has to follow some simple rules regarding software portability, use of common tools and libraries, general programming criteria, naming conventions, and documentation.
As for the general rules of the KLOE online software,
the rules and methods described here should be
regarded as a starting point for discussion.
So, if some rule will be added or modified, according to
developers' experience, this document will be updated
accordingly.
The updated topics will be marked with
.
While in a second step all the software will be included in a single package, each developer has to create his own package in order to develop the software related to a board, following the naming conventions described in the following.
All the rules contained in the general document about the online software development hold if not otherwise specified.
It is mandatory to use packman to configure and maintain the software. Once a version of a package will be released, it will be freezed and integrated in the level-1 general package and a new version will be created as developing area.
Each version of a package must be certified both by the responsible of the related board and by the responsible of software integration.
The KLOE DAQ and online environment is a distributed heterogeneous UNIX environment. Various UNIX operating systems, mainly HP-UX, OSF/1, LynxOS, are in use on different hardware platforms including VME processor boards. All the level-1 software must support almost these three OS.
Some general criteria have to be followed to build multi-platform code with only one set of source files:
Some naming conventions have to be adopted to avoid entry point duplication and to build easy-to-read software. These conventions applies to:
use short, simple names, possibly referred to the module you are working on (for instance: adc, tcd, rock...).
provide one source file containing library functions, calling it consequently (for instance: adclib.c, tcdlib.c, ...).
use the "unix default" name (like libadc.a, libtdc.a, ...).
use long and self-explaining names, beginning with package name in one of the following forms:adc_load_pedestals (preferred) AdcLoadPedestalsChoose one or the other, anyway, please be coherent!
Almost one include files must be provided, named package.h or package_public.h, containing:
#define TDC_MAX_TDC_NUMBER 256
#define ADC_REGNAME_OFFSET 0x24
or the equivalent:#define ADC_FIELDNAME 4 /* begins at the 4th bit */ #define ADC_FIELDNAME_LEN 2
#define ADC_FIELDNAME 4 /* begins at the 4th bit */ #define ADC_FIELDNAME_MASK 3
#define adc_set_fieldname(id,value) definition
#define ROCK_ERR_SYNCFAIL errcode
Please name the variables in function prototypes; it is not needed by the compiler but helps to make the code readable.void adc_load_pedestal (adc_id id, int ped);
Another include file can be provided if encapsulated type definitions are needed. This file will be called package_private.h.
Simple operations on registers (such as read, write or modify operations) should be implemented using macros and an easy-to-learn naming scheme:
For instance, to read the register called pippo in the adc, in the public include file you will have:#define package_operation_register-name
#define ADC_PIPPO_OFFSET 0x32 #define adc_get_pippo (id, val_pippo) \ VmeRead(id.cid, ADC_PIPPO,\ (char *) &val_pippo,\ sizeof (val_pippo))
In general, working with macros helps to have compact and efficient code,
avoiding overload. A macro can easily implement low-level operations.
Furthermore, writing a macro for each register allows the user to work
easily, calling the appropriate procedures for each operation on the hardware.
To implement operations on bits or bit fields similar criteria should be used. A basic macro should be provided to implement each operation for each bit field; bit and field manipulation can be performed by using the utility bits, included in the common package. For instance, to set the flag called MYFLG in the ADC register PIPPO:
#include "bits.h" #define ADC_PIPPO_OFFSET 0x20 #define ADC_MYFLG 4 #define adc_set_myflg (id, value) \ {char rval;\ VmeRead (id.cid, ADC_PIPPO,\ &rval, sizeof (char));\ bits_set_bit (rval, ADC_MYFLG,\ value);\ VmeWrite (id.cid, ADC_PIPPO,\ &rval, sizeof (char));}
It is possible to manage bit fields (see
bits documentation).
Use macros to manage single fields; use functions
to perform complex operation,
such as modifying two fields in the same register.
This will avoid overload due to unuseful VME accesses when
calling two `set' macros.
Updated documentation in standard HTML form, possibly using source2html or c2html.
Comments inside the code.
Simple example applications.
If possible, build graphic tools using the TL compiler and tcl/tk.