Privacy and Security Notice

CDEV Documentation



Service Developer's Guide

Techniques for Developing Services using the

Control Device Interface

Chip Watson, Jie Chen, Danjin Wu, Walt Akers

Version 1.5 - December 9, 1996

TJNAF - Thomas Jefferson National Accelerator Facility




Table of Contents

1.
Overview of cdev Services

What is a cdev Service

Service Classes

Request Object Classes

Loader Functions

What the Developer Must Understand
2.
Developing cdev Services

Steps in Developing a cdev Service
3.
The cdevService Class

Overview of the cdevService Class

The flush Method

The poll Method

The pend Method

The getRequestObject Method

Public Member Functions of the cdevService ClassPublic Functions of the cdevService Class

flush

poll

pend

pend

getRequestObject

getNameServer

getCollectionRequest

getFd

registerFd

autoErrorOn

autoErrorOff

reportError

setErrorHandler

setThreshold

name
4.
The cdevRequestObject Class

Overview of the cdevRequest Object Class

Public Member Functions of the cdevRequest Object Class

attachRef

attachRef

attachPtr

attachPtr

detach

detach

message

device

system

service

getState

getAccess

setContext

getContext

getPrivate

setPrivate

send

sendNoBlock

sendCallback
5.
The cdevCollectionRequest Class

Overview of the cdevCollection Request Class

Public Member Functions of the cdevCollection Request Class

constructor

destructor

attachPtr

className

resultCodeTag
6.
The Service Loader Function

Overview

Naming Convention
7.
The cdevTranObj Class

Overview of the cdevTranObj Class

Public Data Properties of the cdevTranObj Class

system_

reqObj_

resultData_

userCallback_

Public Member Functions of the cdevTranObj Class

status

removeFromGrps

enableDeleteCbk

disableDeleteCbk
8.
Default Service Behavior for Standard Messages

Overview

"get" Message

"set" Message

"monitorOn" Message

CDEV_SUCCESS:

CDEV_DISCONNECTED:

CDEV_RECONNECTED:

CDEV_ERROR:

CDEV_INVALIDOBJ:

CDEV_INVALIDARG:

CDEV_INVALIDSVC:

CDEV_NOTCONNECTED:

CDEV_IOFAILED:

CDEV_CONFLICT:

CDEV_NOTFOUND:

CDEV_TIMEOUT:

CDEV_CONVERT:

CDEV_OUTOFRANGE:

CDEV_NOACCESS:

CDEV_ACCESSCHANGED:

"monitorOff" Message

device

attribute

function

userarg
9.
demoService: A Sample cdev Service

Overview of the demoService

The demoDevice Object

The demoService Object

The enqueueTransaction Method

The processTransaction Method

The newDemoService Function

The cdevSelector Object

The VERB Enumeration

The ATTR Enumeration

The demoRequestObject Object

Makefile for the demoService

Device Definition File for the demoService



List of Figures

Figure 1: Return codes generated by the send method.
Figure 2: Naming convention and syntax for the cdevService loader function
Figure 3: Example cdevService loader function
Figure 4: Default behavior of the "get" and "set" messages
Figure 5: Default behavior of the "monitorOn" and "monitorOff" messages
Figure 6: demoDevice.h: Header file for devices used by the demoService
Figure 7: demoDevice.cc: C++ source for the demoDevice class
Figure 8: demoService.h: Header file for the demoService class
Figure 9: demoService.cc: Source code for the demoService class
Figure 10: demoRequestObject.h: Header file for the demoRequestObject class
Figure 11: demoRequestObject.cc: Source for the demoRequestObject class
Figure 12: Makefile for the demoService
Figure 13: Device Definition Language file for the demoService



1.

Overview of cdev Services

What is a cdev Service

The cdev library defines a command set that can be used to provide a homogenous interface to differing control systems. In order to incorporate a control system into the cdev environment, the developer must create linking code that allows the cdev system to communicate with the system. This linking code is called a cdev service. At a minimum, the cdev service developer must develop two interface classes and a simple constructor function in order to create a new service. These classes and functions will be described at length in the sections that follow.

Service Classes

Each service must define a service class that provides the mechanisms for communicating with the underlying control system. This class is inherited from the cdevService class, from which it gains most of its functionality. The main effort for the developer in creating this class is in the flush, poll and pend methods. These methods are functionally identical to those defined in the cdevSystem object, however, the developer must provide concrete mechanisms for communicating with the intended control system, as well as managing and reporting errors that might occur during normal operation.

Request Object Classes

The service developer must also create a request object class that provides the mechanisms for a cdevDevice object to communicate with the developer's service class. This class is inherited from the cdevRequestObject class, from which it gains most of its functionality. The primary effort for the developer in creating this class is in the send, sendNoBlock and sendCallback functions. The service creator must also develop his strategy for efficiently communicating with the underlying system. The source code in the following chapters will illustrate a queueing scheme that provides a very simple and efficient linkage between the service and the request object. The request object is also responsible for detecting and reporting errors that occur within its domain.

Loader Functions

The loader function is an extern "C" function that is called by the cdevSystem object to dynamically construct a copy of the service class.

What the Developer Must Understand

In order to create cdev services, the developer must have an extensive understanding of the complete cdev system. A potential service developer should first develop applications using existing cdev services in order to understand the expected behavior of a service. The developer should then familiarize himself completely with all of the classes within the cdev library, paying special attention to the cdevService class and the cdevRequestObject class.

The following chapters describe the structure and syntax of the most important of these classes and an overview of how certain messages are expected to behave. This manual finishes with the complete annotated source code for a demonstration service that operates on a virtual control system.

2.

Developing cdev Services

Steps in Developing a cdev Service

1.

Install and build the cdev distribution. Obtain a copy of the most recent cdev distribution and install it on your system.

2.

Define the devices in your control system. Define the names, attributes and messages associated with each device in your control system. This information will be critical in the construction of the Device Definition Language file that cdev will use to determine which service will process messages for a device.

3.

Design and document specific device/message behavior. Determine the specific inputs and outputs required for each device to process a message. Design and document how the service will route messages to the underlying control system. Ensure that the disposition of standard messages within your service is consistent with the behavior of standard cdev services.

4.

Develop your cdevService object. This object is a sub-class of the cdevService class and will be responsible for responding to flush, poll, and pend requests from the cdevSystem object. The service object should be able to perform all interface tasks necessary to link the service specific cdevRequestObjects to the underlying control system.

5.

Develop your cdevRequestObject object. This object is a sub-class of the cdevRequestObject class and will be responsible for responding to send, sendNoBlock and sendCallback requests from the cdev application.

6.

Develop your cdevCollectionRequest object (optional). If your service will provide specialized support for collections of devices, it wil be necessary to develop a cdevCollectionRequest object that processes these requests.

7.

Create a service loader function. This function is described earlier in this document and is used by the cdevSystem object to an instantiate a new service object for this service.

8.

Compile and link the shared object. Compile a position-independent shared object file that cdev can load on request. The service's shared object file should contain all of the object code necessary to directly load and utilize the service. This file should be copied to the directory where the other cdev services are stored.

3.

The cdevService Class

Overview of the cdevService Class

The cdevService C++ class is an abstract base class for all cdev services. This class defines the mechanisms that cdev will utilize to communicate with your underlying control system. It is the responsibility of the service developer to 'flesh out' the virtual functions that are defined within this class and to develop the code necessary to communicate with the underlying control system.

The primary methods that developers must concern themselves with are flush, poll pend, and getRequestObject. These methods represent the majority of the work that must be performed in developing a cdev service.

The flush Method

The flush method is responsible for submitting any unsent messages to the device. This may entail submission of a message using a network protocol or simply calling a statically linked C function. The cdevSystem object will call this method prior to each pend or poll operation, or whenever the flush method of the system object is called directly by the user.

The poll Method

The poll method is responsible for directly polling each of the physical devices that are managed by the service to detect if they require attention (typically by checking a single socket). This method is typically utilized to allow the physical device an opportunity to return a response to a previously sent message. The cdevSystem object will call this method whenever the application calls the poll method of the system object. Most services can route this call directly to their associated pend method.

The pend Method

The pend method allows the service to wait for a period of time for one of its underlying devices to require attention. After waiting for a specified period of time, this method will return CDEV_SUCCESS if it successfully serviced any of its underlying devices, or CDEV_TIMEOUT if no device became active during that period. This method is typically called by the cdevSystem object in response to a change in state of one or more of the service's file descriptors.

The getRequestObject Method

The getRequestObject method is used by the cdevSystem object to obtain a new instance of one of the service's request objects in response to a request made by the application. The service may internally define many request object types for use by applications, therefore, it is the responsibility of this function to return the correct request object for the specified device / message combination. Typically a service will only define one type of request object and will use it for all requests.

Public Member Functions of the cdevService Class

Public Functions of the cdevService Class

flush

int flush (void);

Flushes any pending outbound requests to the appropriate servers. This is a pure virtual function that must be provided by the service developer.

poll

int poll (void);

Directly polls each of the cdevService's underlying file descriptors for activity, and delivers any asynchronous callbacks that are ready. This is a pure virtual function that must be provided by the service developer.

pend

int pend (int fd);

Waits for a default period of time for the specified file descriptor to have an I/O event. If the fd parameter is not provided, the cdevService object will wait for an I/O event on any of its contained file descriptors. When an event occurs on one of the file descriptors, the cdevService object will call the appropriate function to process the event and dispatch any asynchronous callbacks that are ready. This is a pure virtual function that must be provided by the service developer.

pend

int pend (double seconds, int fd);

Processes all I/O events that occur on the file descriptor during the specified period of time. If the fd parameter is not provided, the cdevService object will wait for I/O events on all of its contained file descriptors. When an event occurs on one of the file descriptors, the cdevService object will call the appropriate functions to process the event and dispatch any asynchronous callbacks that are ready. This is a pure virtual function that must be provided by the service developer.

getRequestObject

int getRequestObject ( char *dev, char *msg,

cdevRequestObject* &req);

Obtains a pointer to a cdevRequestObject that is specific to this service and the specified device/message combination. This method should only be called by the cdevSystem object. This is a pure virtual function that must be provided by the service developer.

getNameServer

int getNameServer (cdevDevice* &server);

Obtains a cdevDevice object identifying the name server for this service. A service is not required to provide its own name server and may simply set the server parameter to NULL. This is a pure virtual function an must be provided by the service developer.

getCollectionRequest

int getCollectionRequest ( char ** devices,

int nDevices, char * msg,

cdevCollectionRequest * &req);

This method allows the caller to obtain a cdevCollectionRequest object that will contain only devices that are associated with the service. A default mechanism is provided to support this functionality, however, the developer may create a special request object to optimize these operations.

getFd

int getFd (int* &fd, int &numFd);

Retrieves a list of file descriptors that are contained within the cdevService object. The fd pointer will be given the pointer to the internal array of file descriptors, and the numFD parameter will be set to the number of file descriptors in the list. A service that does not use file descriptors should set the fd and numFD parameters to NULL and 0, respectively. This is a pure virtual function that must be provided by the service developer.

registerFd

int registerFd (int fd, int opened);

The service developer may implement this method to allow external file descriptors to be added to the list of file descriptors in the service. The fd parameter should contain the file descriptor, and the opened parameter should contain 1 to add it to the list or 0 to remove it from the list.

autoErrorOn

int autoErrorOn (void);

Informs the cdevService object that it should use its internal default error handler to process any error messages that are generated by objects within its control. This is the default operating condition for the cdevService object.

autoErrorOff

int autoErrorOff (void);

Informs the cdevService object that it should use its internal default error handler to process any error messages that are generated by objects within its control. This is the default operating condition for the cdevService object.

reportError

int reportError ( int severity, char *name,

cdevRequestObject *obj,

char *formatString,...);

Emits an error message. The severity field indicates the severity of the error, the name string identifies the object that generated the error, the obj parameter is the cdevRequestObject that was in use when the error occurred, and the formatString and additional parameters (...) should be formatted in the same manner as the parameters used by printf.

The integer used by severity should have one of the following values indicating the severity of the error that has occurred.

CDEV_SEVERITY_INFO:

No error.

CDEV_SEVERITY_WARN:

An error occurred that should not impact continued processing.

CDEV_SEVERITY_ERROR:

An error occurred and should be corrected before continuing.

CDEV_SEVERITY_SEVERE:

A severe or fatal error has occurred and cdev cannot continue normal execution.

setErrorHandler

void setErrorHandler (cdevErrorHandler handler);

Used to install a user specified error handler. This error handler will be called when an error occurs if the autoErrorOff method has been used to disable the default error handler. The user provided error handler should have the following prototype:

void handler (int severity, char *text, cdevRequestObject *obj);

The severity parameter will contain one of the integers specified in the reportError documentation, the text parameter will contain the text of the error, and the obj parameter will contain the cdevRequestObject that was in use when the error occurred.

setThreshold

void setThreshold (int errorThreshold);

Used to specify the level of severity at which errors should be submitted to the error handler. The value of errorThreshold should be one of the severity levels specified in the reportError method.

name

char *name (void) const;

Retrieves the name of the service. This method is used extensively to determine the service that underlies a specific cdevRequestObject object. If not over-ridden by the service developer, this method will return the string "cdevService".

4.

The cdevRequestObject Class

Overview of the cdevRequest Object Class

The cdevRequestObject C++ class is the application's interface to the underlying service. Each service must provide a service specific request object that applications may use to send messages to the service.

The message associated with a cdevRequestObject may be sent to a device using one of the three send member functions, these are: send, sendNoBlock, and sendCallback. The syntax and functionality of these methods is described in the section below. The majority of work in the development of a service specific request object is in the development of these three methods.

Public Member Functions of the cdevRequest Object Class

attachRef

static cdevRequestObject& attachRef (char *device, char * msg);

Obtains a reference to a cdevRequestObject object by specifying the name of the device and the message string. By default, the new object will be managed by the default cdevSystem.

attachRef

static cdevRequestObject& attachRef (cdevDevice &dev, char * msg);

Obtains a reference to a cdevRequestObject object by providing a reference to the associated cdevDevice object and the message string. By default, the new object will be managed by the default cdevSystem.

attachPtr

static cdevRequestObject* attachPtr (char *device, char * msg);

Obtains a pointer to a cdevRequestObject by specifying the name of the device and the message string. By default, the new object will be managed by the default cdevSystem.

attachPtr

static cdevRequestObject* attachPtr (cdevDevice &dev, char * msg);

Obtains a pointer to a cdevRequestObject by providing a reference to the associated cdevDevice object and the message string. By default, the new object will be managed by the default cdevSystem.

detach

static void detach (cdevRequestObject& dev);

Removes a referenced cdevRequestObject object from its associated cdevSystem object. Ordinary applications should never use this command.

detach

static void detach (cdevRequestObject* dev);

Detaches the cdevRequestObject object specified by dev from its associated cdevSystem object. Ordinary applications should never use this command.

message

char *message (void) const;

Retrieves the message string that is associated with this cdevRequestObject.

device

cdevDevice &device (void) const;

Retrieves a reference to the cdevDevice object that is associated with this cdevRequestObject.

system

cdevSystem& system (void) const;

Retrieves a reference to the underlying cdevSystem object that manages this cdevRequestObject.

service

cdevService& service (void) const;

Retrieves a reference to the underlying cdevService object that this cdevRequestObject is attached to.

getState

int getState (void);

Obtains the state of the underlying device. This function returns one of the following values as defined in cdevErrCode.h.

CDEV_STATE_CONNECTED:

Object is connected.

CDEV_STATE_NOTCONNECTED:

Object is not connected.

CDEV_STATE_INVALID:

Object is invalid.

The service developer is responsible for implementing this function correctly in the service related cdevRequestObject.

getAccess

int getAccess (void);

Obtains access control information about the underlying device. This function returns one of the following values as defined in cdevErrCode.h.

CDEV_ACCESS_NONE:

No access to attribute.

CDEV_ACCESS_READONLY:

Read-only access.

CDEV_ACCESS_WRITE:

Read-write access.

The service developer is responsible for implementing this function correctly in the service related cdevRequestObject.

setContext

int setContext (cdevData& cxt);

Used to insert a cdevData object containing tagged values that control optional behavior of the underlying device. The context is often used to specify which properties (value, status, severity) a device returns in response to a "get" message. The service developer may override the default behavior of this method to better accommodate the requirements of the service.

getContext

cdevData & getContext (void);

Retrieves a reference to the cdevData object that contains the context for a specific cdevRequestObject. The service developer may override the default behavior of this method to better accommodate the requirements of the service.

getPrivate

void * getPrivate (void);

Retrieves a pointer to a data object that was placed in this object using the setPrivate function.

setPrivate

void setPrivate (void * data);

Associates a user specified data object with this cdevRequestObject. The pointer can be retrieved later using the getPrivate method.

send

int send (cdevData &out, cdevData& result);

int send (cdevData *out, cdevData& result);

int send (cdevData &out, cdevData* result);

int send (cdevData *out, cdevData* result);

The send function is the standard method for synchronously communicating with a device. The out cdevData object contains any property values that the device will need to perform the task. The result cdevData object will contain the output properties that resulted from the call. The service developer is responsible for implementing this method in the service specified cdevRequestObject. This function will return one of the error code defined in cdevErrCode.h.

Figure 1: Return codes generated by the send method.

CDEV_WARNING:       The failure was non-critical.
CDEV_SUCCESS:       The message was processed successfully.
CDEV_ERROR:         Failed to process message.
CDEV_INVALIDOBJ:    Invalid cdev request object used.
CDEV_INVALIDARG:    Invalid argument passed to cdev call.
CDEV_INVALIDSVC:    Wrong service during dynamic loading.
CDEV_INVALIDOP:     The operation is not supported.
CDEV_NOTCONNECTED:  Not connected to low level network 
                    service.
CDEV_IOFAILED:      Low level network service IO failed.
CDEV_CONFLICT:      Conflicts of data types or tags.
CDEV_NOTFOUND:      Cannot find specified data in cdevData.
CDEV_TIMEOUT:       Time out.
CDEV_CONVERT:       cdevData conversion error.
CDEV_OUTOFRANGE:    Value out of range for device attribute.
CDEV_NOACCESS:      Insufficient access to perform request.
CDEV_ACCESSCHANGED: Change in access permission of device.
CDEV_DISCONNECTED:  The service has lost contact with the 
                    device.
CDEV_RECONNECTED:   The service has regained contact with 
                    the device.
			

sendNoBlock

int sendNoBlock (cdevData &out, cdevData &result);

int sendNoBlock (cdevData *out, cdevData &result);

int sendNoBlock (cdevData &out, cdevData *result);

int sendNoBlock (cdevData *out, cdevData *result);

The sendNoBlock method uses the same parameters and syntax as the send method. However, rather than waiting for the underlying service to respond to the request, this function will return immediately.The caller must use a cdevGroup object in order to detect when the transaction has been completed. The service developer is responsible for implementing this method in the service specified cdevRequestObject.

sendCallback

int sendCallback (cdevData &out, cdevCallback &callback);

int sendCallback (cdevData *out, cdevCallback &callback);

The sendCallback function is the standard method for asynchronously communicating with a device. Rather than providing a result cdevData object, this method requires the user to provide the address of a cdevCallback object. This object contains a user supplied pointer and the address of a function to call when the message has been successfully processed. The service developer is responsible for implementing this method in the service specified cdevRequestObject.

5.

The cdevCollectionRequest Class

Overview of the cdevCollection Request Class

The cdevCollectionRequest class is an abstract base class from which other cdevCollectionRequest objects are derived. It provides a protected constructor and destructor that are used to initialize its internals, however, the primary mechanism that is used to obtain a cdevCollectionRequest object is the attachPtr method.

Because the cdevCollectionRequest is inherited from the cdevRequestObject, all of the methods of that class must be fulfilled in addition to those specific to the cdevCollectionRequest class.

Public Member Functions of the cdevCollection Request Class

constructor

cdevCollectionRequest( char **devices, int nDevices,

char * msg, cdevSystem & system);

This is the constructor for the cdevCollectionRequest class. It has the following properties.

This method is protected to prevent the direct instantiation of new cdevCollectionRequests. New instances of the cdevCollectionRequest objects are created by using the attachPtr or attachRef method of the cdevRequestObject class which will call the local attachPtr method to create a new object if necessary.

The constructor is called by the cdevCollection object and is provided with a list and count of devices that will be included in the collection and the message that will be sent to them.

The cdevSystem reference that is provided is the cdevSystem instance that will be used to poll, pend and flush the cdevCollectionRequest object.

destructor

virtual ~cdevCollectionRequest (void);

This is the destructor for a cdevCollectionRequest object. It has the following properties.

This method is protected to prevent the cdevCollectionRequest object from being destroyed by the application. This method should only be called by the cdevSystem object when the application is terminating.

Because the cdevCollectionRequest object will normally be referred to as a cdevRequestObject object, this destructor is virtual to ensure that the 'most senior' destructor is called first.

attachPtr

cdevCollectionRequest * attachPtr

( cdevCollection &col, char *msg, cdevSystem &sys);

This method is used by the cdevCollection object to obtain a new cdevCollectionRequest object.

This method will obtain a copy of the device names from the cdevCollection object and will poll the cdevDirectory object to determine which service each of them is associated with.

If the devices are all from a single service, this method will return a service specific collection request object.

If the devices are from a variety of services, this method will return a cdevGrpCollectionRequest that contains the service specific collection request objects.

Device/message combinations that are not associated with a service will be ignored.

If none of the device/message combinations can be associated with a service, then an error message will be generated and NULL will be returned.

className

char * className (void);

This method returns the name of the class; "cdevCollectionRequest". If the developer inherits a service specific cdevCollectionRequest, then this method should not be altered or overridden.

resultCodeTag

int resultCodetag (void);

This method returns the integer tag that should be used to insert the result code that was geneterated when the message was sent to the actual device.

6.

The Service Loader Function

Overview

The service loader function is used to create an initial instance of the service after the its associated shared object file has been dynamically loaded.

Naming Convention

The naming convention for this class is very specific. The following syntax is required:

Figure 2: Naming convention and syntax for the cdevService loader function

cdevService *newXxxxxService (char * name, cdevSystem * system);
			

In the function name above the Xxxxx should be replaced by the name of the service with the first character capitalized. A service named demo would have a loader function named newDemoService. The loader function is only required to allocate a new service class for the service and return a pointer to it. The following example illustrates how the loader function for the demo service would be written.

Figure 3: Example cdevService loader function

#include <cdevService.h>
 
// ****************************************************************
// * Include file with definition of the service class
// ****************************************************************
#include "demoService.h"
 
// ****************************************************************
// * Loader function for the demoService class 
// ****************************************************************
cdevService *newDemoService (char * name, cdevSystem * system)
   {
   return new demoService(name, *system);   
   }
			

7.

The cdevTranObj Class

Overview of the cdevTranObj Class

The cdevTranObj (cdev transaction object) C++ class is a container class that is used to maintain information that is required for individual operations within a service. This class stores a copy of the cdevRequestObject that was used to submit a request, the cdevSystem object in which the request object was created, the cdevCallback object provided by the user, and the cdevData object that the returned data should be placed in. Because this object is intended for usage only by cdev internals, all of its data elements are public.

The cdevTranObj is used to submit a request from the cdevRequestObject to the cdevService. It is also used to place a transaction into a group of requests using the cdevGroup object. The service notifies the cdevSystem object and the cdevGroup objects that this transaction has been processed by calling its removeFromGrps method. This will effectively remove the cdevTranObj from all groups that it is associated with.

Public Data Properties of the cdevTranObj Class

system_

cdevSystem *system_;

This is a pointer to the cdevSystem that contains this transaction object. The transaction will be processed whenever the poll or pend methods of this cdevSystem object are executed.

reqObj_

cdevRequestObject *reqObj_;

This is a pointer to the cdevRequestObject that was called to submit this transaction. This cdevRequestObject will be submitted to the user specified callback function when the transaction has been completed.

resultData_

cdevData *resultData_;

This is the cdevData object that will be populated with the results of the transaction. This object will also be submitted to the user specified callback function when the transaction has been completed.

userCallback_

cdevCallback *userCallback_;

This class contains a pointer to the caller specified callback function as well as any user argument. The callback function will be executed when the transaction has been completed. Note that it is the responsibility of the service to execute this callback function when it has finished processing the transaction.

Public Member Functions of the cdevTranObj Class

status

int status (void);

Returns the status of the cdevTranObj object. The value returned will be 1 if this object is a member of any cdevGroup object, or -1 if this object is not a member of any cdevGroup object.

removeFromGrps

int removeFromGrps (void);

Removes this transaction object from any cdevGroup object that it may be in.

enableDeleteCbk

void enableDeleteCbk (void);

Sets the internal flag telling the transaction object to delete its internal callback object while executing its destructor. This is the default behavior for the cdevTranObj.

disableDeleteCbk

void disableDeleteCbk (void);

Sets the internal flag telling the transaction object not to delete its internal callback object while executing its destructor. This mode should be used when the user specified callback object is shared by numerous transaction objects.

8.

Default Service Behavior for Standard Messages

Overview

The cdev library is designed to provide a standard calling interface to dissimilar devices within a control system. This interface is accommodated through the use of the cdevDevice methods send, sendNoBlock and sendCallback. However, because each service can define the names and behaviors of the messages that it supports, the user must be increasingly aware of which service may process its messages.

In order to reduce the required knowledge of the user, and to improve the consistency of all services, all cdev services should provide well-defined support for a minimum list of verbs.

The following verbs should be implemented to provide a standard behavior in all cdev services: get, set, monitorOn, and monitorOff.

"get" Message

The "get" verb can be joined with any attribute of a device to form a "get" message. This message is then sent to the device in order to obtain the value of specified properties of the attribute. The following steps should be executed in order to utilize a "get" message.

1.

Obtain a pointer to the cdevDevice object for the device that you wish to address.

2.

Create a message string by concatenating the attribute that you wish to address to the "get" verb. For instance, to get the VAL attribute of a device, the message strings should be: "get VAL".

3.

Optionally, use the cdevDevice object created in step 1 and the message string created in step 2 to obtain a pointer to a cdevRequestObject object.

4.

Set the context of the cdevDevice or cdevRequestObject to indicate which properties you wish to obtain. A non-zero value in any property indicates that its value should be returned. If no context has been specified, the service should return the value property by default. A complete description of the context data object is provided in the cdevDevice documentation.

5.

Use the send, sendNoBlock, or sendCallback message to submit the message to the device.

6.

Evaluate the return value from the send command to determine if the operation completed successful. Any value other than CDEV_SUCCESS indicates that an error occurred in handling the message.

7.

If the call was completed successfully, extract the desired properties from the resultant cdevData object.

"set" Message

The "set" verb can be joined with any attribute of a device to form a "set" message. This message is then sent to the device in order to set the value property of the attribute. The following steps should be executed in order to utilize a "set" message.

1.

Obtain a pointer to the cdevDevice object for the device that you wish to address.

2.

Create a message string by concatenating the attribute that you wish to address to the "set" verb. For instance, to set the bdl attribute of a device, the message string should be: "set bdl".

3.

Optionally, use the cdevDevice object created in step 1 and the message string created in step 2 to obtain a pointer to a cdevRequestObject object.

4.

Set the value property of the outbound cdevData object to the new value.

5.

Use the send, sendNoBlock, or sendCallback message to submit the message to the device.

6.

Evaluate the return value from the specific send command to determine if the message was transmitted successful. Any value other than CDEV_SUCCESS indicates that the message was not transmitted successfully.

In the following example, the "get" message will be used to obtain the properties value, status and severity from the bdl attribute of device MQB1S01, the "set" message will then be used to copy the value property to the bdl attribute of device MQB1S02.

Figure 4: Default behavior of the "get" and "set" messages

#include <cdevSystem.h>
#include <cdevDevice.h>
#include <cdevRequestObject.h>
#include <cdevData.h>
 
// ****************************************************************
// * The printError function will be used to output any error that
// * that occurs during the processing of the "get" or "set"
// * messages.
// ****************************************************************
int printError (int errCode)
   {
   switch(errCode) 
      {   
      // ******* Unknown device or device/message mismatch ******
      case CDEV_INVALIDOBJ:
         printf("Unknown device or device/message mismatch\\n");
         break;
 
      // * Communications error between application and service *
      case CDEV_NOTCONNECTED:
      case CDEV_IOFAILED:
      case CDEV_TIMEOUT:
         printf("Communications error while sending\\n");
         break;
 
			

Figure 4: Default behavior of the "get" and "set" messages (continued)

      // ******* No data or bad data passed with message ********
      case CDEV_INVALIDARG:
      case CDEV_OUTOFRANGE:
      case CDEV_NOTFOUND:
      case CDEV_CONVERT:
         printf("Bad or missing value passed in message\\n");
         break;
 
      // ******************** Generic Error *********************
      case CDEV_ERROR:
      case default:
         printf("Unable to send message\\n");
         break;
      }
   }
 
void main()
   {
   cdevRequestObject * req1, *req2;
   cdevData            ctx;
   cdevData            output, input;
   double              val;
   int                 errorCode = CDEV_SUCCESS;
 
   // ***********************************************************
   // * Obtain a pointer to the cdevRequestObject for the
   // * "get bdl" message on device "MQB1S01".
   // ***********************************************************
   req1 = cdevRequestObject::attachPtr("MQB1S01", "get bdl");
 
   // ***********************************************************
   // * Place a non-zero value in the properties value, status,
   // * severity.
   // ***********************************************************
   ctx.set("value", 1);
   ctx.set("status", 1);
   ctx.set("severity", 1);
   
   // ***********************************************************
   // * Set the context of the cdevRequestObject.
   // ***********************************************************
   req1->setContext(ctx);
 
   // ***********************************************************
   // * Submit the message to the device and test the return 
   // * value to ensure that the message was processed correctly
   // ***********************************************************
   if((errorCode=req1->send(NULL, &output))==CDEV_SUCCESS) 
      {
      // ********************************************************
      // * Message was transmitted and processed successfuly.
      // ********************************************************
      char   stat[50], sev[255];
      output.get("value", &val);
      output.get("status", stat, 50);
			

Figure 4: Default behavior of the "get" and "set" messages

      output.get("severity", sev, 50);
      printf("Val:%f, status:%s, severity:%s", val, stat, sev);
      }   
   else printError(errorCode);
 
   // ***********************************************************
   // * Obtain a pointer to the cdevRequestObject for the
   // * "set bdl" message on device "MQB1S02".
   // ***********************************************************
   req2 = cdevRequestObject::attachPtr("MQB1S02", "set bdl");
 
   // ***********************************************************
   // * Insert the new value into the input cdevData object.
   // ***********************************************************
   input.insert("value", value);
 
   // ***********************************************************
   // * Submit the message "set bdl" to the device and test 
   // * the return value to ensure that the message was 
   // * processed successfully. Note that, by default, the set
   // * message does not generate any output.
   // ***********************************************************
   if((errorCode==req2->send(&input, NULL))==CDEV_SUCCESS) 
      {
      // ********************************************************
      // * Message was transmitted and processed successfuly.
      // ********************************************************
      printf("Message was transmitted successfully\\n");
      }
   else printError(errorCode);
   }
			

"monitorOn" Message

The "monitorOn" verb can be joined with any attribute of a device to form a "monitorOn" message. This message is tells the cdevDevice that each time one of the monitored properties changes, it should call the user specified callback function with the updated value. This message should always be submitted using the sendCallback