HiDEOS Interface to EPICS
Introduction
A library has been set up to simplify the writing of HiDEOS device support
modules for EPICS. All HiDEOS devices use the EPICS asynchronous device
support model. By using the library, the programmer will minimize the
amount of code that needs to be written. Most of the details of EPICS
device support and the HiDEOS interface are hidden from the developer.
The library consists of a base class which the user subclasses off of. A
macro is used to generate the EPICS DSET.
Overview
Creating an EPICS/HiDEOS device support module requires knowledge of C++.
The library makes use of virtual base classes, static member function, and
constructors. The base class used to create EPICS/HiDEOS device support
modules is the HideosDevice class. Every device support module must do
the following: create a new class by deriving off HideosDevice (1), define
a constructor (2), define the StartIO() and CompleteIO() routines (3),
define a static member function to be called at record initialization (4),
define a DSET (5). Each record in the EPICS database which specified
HiDEOS devices will have contain it's own HidoesDevice subclass instance.
The pointer to HihideoDevice subclass instance is stored in the record
private field (DPVT).
(1) Creating a New Class
As stated earlier, the HideosDevice class controls most aspects of
initialization and communication with EPICS and HiDEOS. The public
interface of HidoesDevice contains methods for retrieving and freeing
HiDEOS message buffers (see HiDEOS documentation). Also contained in the
class are methods for sending the messages. Two types of send are
supported, blocking and non-blocking. The class has no concept of different
record types, all communication with record is done through the record
base structure dbCommon. All device support derived from the HideosDevice
class is automatically assumed to be asynchronous. The HideosDevice class
constructor creates a communications interface instance (BPD) for HiDEOS and
attempts to bind the record instance to a HiDEOS task. The name of the
HiDEOS task will be the first string in the parm field of the link. A method
called GetUserParm() exists for easily retrieving a pointer to the
remaining data in the parm field. The parm field is viewed as a comma
separated list of strings, the first being the name of the HiDEOS task. The
HiDEOS task name is the only part of the parm field that is parsed by the
HideosDevice class, the rest of the string is left for the user to define.
(2) New Device Constructor
The HideosDevice derived class must define a constructor. The constructor
will take the arguments of the HideosDevice constructor and pass it's
arguments down to the base class. Remember that the derived class
constructor gets called after base class constructor. The first thing
to do in this function is to check the device status using the DeviceStatus()
method. If the base class constructor failed, then the status returned from
DeviceStatus() will indicate the EPICS return code and nothing further needs
to be done. If the status indicates success, then the derived class
constructor can continue. The next step to do here is to initialize the
private data of the derived class and record instance. Almost all device
support modules retain some sort of state, this state should be stored
in the private section of the derived class.
(3) Defining the I/O Functions
The HideosDevice class contains two pure virtual function - functions which
must be written in the subclass. The first, StartIO(dbCommon*), gets called
when to EPICS record gets processed. The job of StartIO() is to cast the
EPICS base structure dbCommon to the correct record type, create
a HiDEOS message with the appropriate data and send it out. The second
function which must be written is the CompleteIO(dbCommon*,Message*) function.
The dbCommon parameter is the record for which I/O is completing, the Message
parameter is the HiDEOS response from the earlier send. The job of
CompleteIO() is to cast the dbCommon structure and Message to the actual
expected types, decode the response, record any required information in the
record, and free the message buffer.
(4) Record Initialization Function
The HideosDevice derived class must define a static member function which
is to be called at EPICS record instance initialization time. The function
will become part of the DSET by using the DSET definition macro described
below. The function takes as an argument the record instance being
initialized. As stated earlier, there is one HideosDevice instance per
EPICS record instance. The job of this function is to actually create the
user's HideosDevice derived object. Remember that each EPICS device support
module for HiDEOS contains a HideosDevice derived class, this function will
create an instance of that class to latch on the record instance (using the
DPVT field of the record). Since this function is called directly from the
DSET, the user knows exactly what class instance to create - this is the
only point in the flow of execution that this information is known. After
creating the instance of the user's class, the function returns using
the DeviceStatus() as a return code. Nothing more needs to be done here
because the constructor of the user's class will take care of the
initialization.
(5) Defining the DSET
DSETs are defined using a special macro. The two parameter needed by the
macro are a name and the above described record initialization function.
The name parameter is the DSET name used by EPICS record suport to find
the device support functions (see EPICS Developer's Guide). See the section
below on the actual use of the macro. Currently all the functions in the
DSET are defined in the HideosDevice base class except for the record
initialization function.
HideosDevice Base Class Public Interface
- HideosDevice(dbCommon* rec,link* l);
- Construct a HideosDevice instance for record rec using link
information l. The instance pointer will be stored in the record's
DPVT field. The record will be bound to the HiDEOS task name
specified in the link's parm field. All subsequence I/O will be
to the HiDEOS task named in the parm field. The card field will
identify where the HiDEOS task is running, card=0 is the
vxWorks/EPICS board.
- virtual long StartIO(dbCommon* rec)=0;
- Start the asynchronous transaction using rec. Typically the user will
send a message to HiDEOS here and return. The user should return
the normal EPICS return codes here or HideosDevice_OK if
everything is to complete normally using asynchronous record completion.
Two return codes, HideosDevice_EndOK and
HideosDevice_EndNC are used to inform the library that
processing is complete and asynchronous completion should not
done. HideosDevice_EndOK indicates complete with conversion
and HideosDevice_EndNC indicates complete without conversion.
- virtual long CompleteIO(dbCommon* rec,Message* msg)=0;
- Complete the asynchronous transaction using rec. Msg is the message
returned from HiDEOS as a result of a StartIO(). The msg can be parsed
here and the record updated. Return the standard EPICS codes for
conversion/no conversion here if transaction is successful.
- long DeviceStatus();
- Return the status of the device. The status can be set by any of the
base class function, usually the constructor. The user should use this
to ensure that the device is functioning. The status stored here is
the EPICS return codes.
- BPD* GetBPD();
- Return the HiDEOS BPD communications descriptor. This is the low level
interface to HiDEOS. Each instance of HidoesDevice uses one BPD.
- TD GetTD();
- This is the HiDEOS task descriptor. Each instance of HideosDevice
communicates with one HiDEOS task. The TD holds all the information
about the location of the HiDEOS task the HideosDevice is communicating
with.
- const char* GetUserParm();
- Return a pointer to the start of the user defined portion of the link's
parm field. The purpose of the function is to easily get access to
the user's parm field.
- Message* GetMessageBuffer(int type);
- int FreeMessageBuffer(Message* msg);
- Routines for getting and freeing message buffers. All message buffer
should be created using these routines. GetMessageBuffer() takes a
integer argument which is a HiDEOS message enumerator (see HiDEOS
documents) and returns a reference to that type of message buffer.
FreeMessageBuffer() returns a message previously allocated with
GetMessageBuffer() to the heap. All HiDEOS message are derived from the
Message class, so GetMessageBuffer() always returns the buffer as the
messaging base class Message.
- int Send(Message* msg);
- Send the message msg to the HiDEOS task which this instance of HideosDevice
is connected. This is the call typically used in StartIO() to begin
a transaction to HiDEOS. This call does not block.
- Message* SendBlock(Message* msg);
- Send the message msg to the HiDEOS task which this instance of
HideosDevice is connected. Additionally, block until a message is
returned from the HiDEOS task. The returned Message* is the message that
is returned from the connected HiDEOS task. It is the responsibility of
the SendBlock() caller to free the returned Message buffer. This is
more of a synchonous transaction. The place where this is typically
used is in a HideosDevice subclass constructor. The subclass
constructor can send and retreive configuration information from HiDEOS
tasks during EPICS record initialization.
DSET Creation Macros
Two macros currently exist for automatically generating the EPICS DSET
structure.
- MAKE_HIDEOS_DSET(name,init_function)
- Create a DSET with global symbol "name" as the device name. The "name"
should be used to create an entry in the devSup.ascii file so the device
is available as a DTYP field choice in DCT. The "init_function" should
be the static member function for initialization described above.
Remember to use the scope operator in the init_function argument.
Since the macro is used outside the context of a class, the init_function
must include the class name (example: myDevice::init_func where myDevice
is the class derived from HideosDevice and init_func is the static
member function for initialization).
- MAKE_HIDEOS_AI_DSET(name,init_function)
- Same as above macro, but used for the ai/ao records. This macro
generates the linear conversion function required by the ai/ao records.
Summary
Argonne National Laboratory
Copyright
Information
Jim Kowalkowski ([email protected]) updated 4/12/95