CAMAC++
CAMAC++
CAMAC++
Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
04 July 2000<br />
<strong>CAMAC++</strong><br />
Steve Wotton
1 Introduction<br />
This document describes a primitive C++ CAMAC library for systems which utilise the CES CBD8211 CAMAC<br />
branch driver. No attempt has been made to preserve the familiar calling sequences of standard CAMAC libraries.<br />
The motivation for providing this library is to ease the integration of CAMAC systems into modern data acquisition<br />
environments where portability between different operating systems and different hardware environments may be<br />
important. The library is incomplete and under development.<br />
The library has so far been used on the following systems:<br />
• HP742 VME SBC running HPUX<br />
• PC running Windows NT using the National Instruments PCI-to-VME interface.<br />
• SBCs running OS9<br />
• CES RIO running LynxOs<br />
The g++ v2.7.2 compiler has been used except on WNT where Borland C++ v5 was used. It should be<br />
straightforward to modify the library for use in other similar systems. The main requirement is that the host system<br />
should support transparent addressing of the VMEbus. On virtual memory systems (like the HP) this is done by<br />
mapping the physical address space of the CBD into the user's virtual address space. On non-virtual addressing<br />
systems (eg OS-9) the corresponding address mapping function would simply return the "physical" address of the<br />
module. All this architecture dependent stuff is hidden in a vme class for easy portability.<br />
2 About the CAMAC branch driver<br />
The CBD can drive a single CAMAC branch containing up to 7 crates. The physical VME base address of the CBD<br />
depends on the branch number selected with the front panel switch. The base address is then given by the expression<br />
(0x800000 | (N
3.1.1 Member functions<br />
Member function Operation Returns<br />
cbranch(vme *VME, const char brname[], const char config[]) Constructor(1) -<br />
cbranch(vme *VME, CAMACD *address, unsigned brnumber,<br />
Constructor(2) -<br />
const char config[])<br />
3.1.2 Description of arguments<br />
Name<br />
Notes<br />
VME Pointer to VME++ object<br />
brname Name of branch as identified in VME++ configuration file<br />
config Configuration file name or environment variable name<br />
address Physical base address of CBD<br />
brnumber Physical branch number<br />
The following example configuration file describes a system having two camac crates on branch 0 with two<br />
CAMAC modules in each crate:<br />
branch: 0 0x800000<br />
crate: 1 crate1<br />
module: 16 tdc lrs2228<br />
module: 21 scalar1 lrs2551<br />
crate: 2 crate2<br />
module: 7 scalar2 lrs2551<br />
module: 8 scalar3 lrs2551<br />
Each line has one of the following forms:<br />
branch: number CBD_addr<br />
crate: number name<br />
module: slot_number name type<br />
The "name" parameters are arbitrary and are used to locate the named object in the internal lists. The "number"<br />
parameters must be consistent with the hardware configuration. The module "type" parameter is used to determine<br />
which concrete class of module to instantiate.<br />
Refer to the example program for more details.<br />
The alternative form of the constructor cbranch(vme,addr,i,file) allows the creation of a branch to which<br />
crates and modules may be added later by explicit calls to ccrate and cmodule constructors in the user program.<br />
Note that the name of an existing file is still required as this is identified with a semaphore created by the library.<br />
However, in this case, the file may be empty - the branch number and physical address of the CAMAC branch driver<br />
are passed explicitly as constructor arguments.<br />
3.2 The class ccrate<br />
This class represents a CAMAC crate and implements the functions used for crate initialisation and control:<br />
Member function Operation Returns<br />
ccrate(cbranch *branch, int id, char *name ) Constructor -<br />
void reset(void) Crate reset (CCCZ) -<br />
void clear(void) Crate clear (CCCC) -<br />
int clrInhibit(void) Clear inhibit (CCCI) Inhibit state<br />
int setInhibit(void) Set inhibit (CCCI) Inhibit state<br />
int testInhibit(void) Test inhibit (CTCI) Inhibit state<br />
int clrDemand(void)<br />
Clear demand (CCCD) Demand state<br />
int setDemand(void) Set demand (CCCD) Demand state<br />
int testDemand(void) Test demand (CTCD) Demand state<br />
3.3 The class cmodule<br />
This class is an abstraction of a CAMAC module and is used to define the interface functions which all derived<br />
classes must provide. Currently the following functions must exist: read, test, clear, execute. See camac.h for<br />
implementation details.<br />
3
CAMAC defines a set of function codes which perform more or less standard operations on all CAMAC modules<br />
(although not all functions are implemented on all modules). The following is a suggested convention for the<br />
cmodule member function names corresponding to the CAMAC function codes F0-31:<br />
CAMAC read member function CAMAC control member function CAMAC write member function<br />
F0 read F8 testLam F16 write<br />
F1 read2 F9 clear F17 write2<br />
F2 readClear F10 clearLam F18 setSelective<br />
F3 readComplement F11 clear2 F19 setSelective2<br />
F4 - F12 - F20 -<br />
F5 - F13 - F21 clearSelective<br />
F6 - F14 - F22 -<br />
F7 - F15 - F23 clearSelective2<br />
- - F24 disable - -<br />
- - F25 execute - -<br />
- - F26 enable - -<br />
- - F27 test - -<br />
- - F28-F31 - - -<br />
CAMAC Q, X and timeout responses are placed into cmodule::errno which should be checked after every<br />
CAMAC operation which may affect these flags. If 0, no error occurred otherwise bit 0 set indicates CAMAC<br />
timeout, bit 1 set indicates no X response and bit 2 set indicates no Q response.<br />
4 Locating modules<br />
The class library constructors build internal data structures which are lists of which crates belong to a branch and<br />
which modules belong to a crate. Modules may be located by name, the module and crate names being defined in<br />
the branch configuration file. The example program illustrates how to locate the module called "scalar" in the crate<br />
named "crate2". Note the type cast to the actual type of the located module. This expression should be used as a<br />
model for locating other modules.<br />
5 Extending the library<br />
Every CAMAC module in a system is represented by a concrete class derived from class cmodule. Adding support<br />
for new modules means deriving a new class from cmodule which must implement at least the read, test,<br />
clear and execute member functions (although they may be dummy). The simple classes lrs2228 (a D16<br />
module) and lrs2551 (a D24 module) in camac.h serve as simple examples. One should not forget to set<br />
cmodule::errors depending on the CAMAC response.<br />
6 Error handling<br />
For maximum portability C++ exception handling has not been used in this library. Instead, each class contains a<br />
public data member, errors, which behaves as a trace buffer into which arbitrary text can be placed for later<br />
display. This strategy has the advantage of allowing constructors (which cannot return values) to report errors in the<br />
same way as other member functions and also allows messages to be reported from deeply nested function calls and<br />
still allow the error to be precisely located. The trace buffer continues to accumulate error messages until flushed to<br />
cout or cerr using the
8 Multitasking<br />
The hardware must be protected against concurrent access which may arise in a multitasking environment where<br />
more than one process may try to access a CAMAC branch. One possibility would be to confine all CAMAC<br />
operations within a single process. Another possibility would be to protect all CAMAC operations with a<br />
semaphore. In order to avoid incurring any unnecessary software penalties the responsibility of protecting the<br />
CAMAC operations has been left to the user. The example program illustrates the use of the branch semaphore. This<br />
approach has the disadvantage that users can cheat by not protecting CAMAC access with the semaphore either<br />
deliberately or inadvertently (e.g. by using an alternative CAMAC library with different or no protection<br />
mechanism). Note that the semaphore is used in the library to protect the branch initialisation.<br />
Another potential problem in a multi-tasking environment is that of initialisation. Typically the hardware<br />
initialisation should be done only once. Since an initialisation function is called from the class constructors and only<br />
the first use of a constructor by any process in the system should perform initialisation, a second semaphore is used<br />
by the library to guarantee this behaviour. The initialisation routines can always be called from the users program at<br />
any time in order to reinitialise part or all of the CAMAC branch. Again, it is possible to cheat the concurrent access<br />
protection scheme.<br />
8.1 Interrupts<br />
Interrupt handling (generated in response to LAMs) is not implemented. On the HP this would require the<br />
implementation of a device driver. On OS9 a device driver already exists but needs to be integrated with this library.<br />
The Nat. Inst. PCI-VME interface has user-callable software to install interrupt handlers so implementation of LAM<br />
interrupt handlers should be easy here. The main problem is to make the library behave the same on all platforms<br />
given the constraints of using the already existing software.<br />
8.2 C-binding<br />
These functions are implemented as jacket routines to the C++ API. The CBRANCHID and CMODULEID type<br />
arguments are actually pointers to the underlying C++ objects and should never be directly manipulated by a C-<br />
coded application. They serve as context arguments used by the library. Since these are jacket routines, this code is<br />
hardware independent and is split off into a separate file, ccamac.cpp<br />
Function Operation Returns<br />
int opencbranch(CBRANCHID *cid, VMEID vid,<br />
const char *file)<br />
Setup CAMAC branch using<br />
configuration file<br />
error<br />
code<br />
int closecbranch(CBRANCHID cid)<br />
Close CAMAC branch<br />
error<br />
code<br />
int getcbranch(CBRANCHID cid)<br />
Get exclusive access to (lock) branch error<br />
code<br />
int releasecbranch(CBRANCHID cid)<br />
Release lock on branch<br />
error<br />
code<br />
int getcmodule(CBRANCHID cid, CMODULEID *mid,<br />
error<br />
Get pointer to named module<br />
const char *crate, const char *module)<br />
code<br />
int cfnr(CMODULEID mid, int A, int *D, int fn) Perform read operation<br />
QXT<br />
int cfnw(CMODULEID mid, int A, int D, int fn) Perform write operation<br />
QXT<br />
int cfnc(CMODULEID mid, int fn) Perform control operation QXT<br />
Where the return code is indicated as QXT this means a bitmask indicating the status of the CAMAC Q, X and T<br />
response in the least significant 3 bits or some other error code in higher order bits.<br />
In addition to these routines it is also necessary to initialise the VME interface using the openvme() and<br />
closevme() from the VME library as in the example program.<br />
9 Built in support for CAMAC modules<br />
Support for a number of specific common CAMAC modules is included in the library. The following modules are<br />
known in addition to generic 16bit and 24bit data modules:<br />
Module Description<br />
LRS2228 TDC<br />
LRS2229 TDC<br />
5
LRS2249 ADC<br />
LRS2551 Scaler, 12ch.<br />
LRS4416 Discriminator<br />
LRS4418 Programmable delay, 16ch<br />
LRS4516 Programmable Logic Unit<br />
LRS4432 Scaler, 32ch.<br />
or2027 Output register, 16ch.<br />
LRS2341 Input register, 16ch.<br />
c85 CAEN Programmable logic unit<br />
10 Example C++ program<br />
11 Example C program<br />
6