V4 CA Interfaces

From EPICSWIKI

CA Preliminary 2nd Generation Interfaces

C++ Namespace

All of the following will be in namespace ??????

Exceptions

The following base class will be used for all exceptions thrown by the library and or passed to exception callbacks to communicate asynchronous failure. The c++ dynamic_castwill be used to test for a particular, concrete condition.

class diagnostic : public std::exception {
public: 
    enum severity_t { 
        sevWarning, sevError, sevFatal };
    virtual severity_t severity () const = 0;
    virtual context ( stringSegment & ) const = 0;
};

Event Specifications

This interface will be used to specify a set of events.

class eventSpec {
public:
    virtual bool operator == ( 
        epicsGuard &, const eventSpec & ) const = 0;    
    virtual bool compare ( 
        epicsGuard &, 
        const eventSpec & comparand, 
        const eventSpec & select ) const = 0;    
    virtual bool isEmpty ( 
        epicsGuard & ) const = 0;
    virtual void show (        
        epicsGuard &, unsigned level ) const = 0;    
    virtual void include (
        epicsGuard &, const eventSpec & ) = 0;    
    virtual void exclude ( 
        epicsGuard &, const eventSpec & ) = 0;    
    virtual void excludeAll (      
        epicsGuard & ) = 0;
};

Subscription Event Specification

This interface is used to specify what events will and will not be present if a subscription update is triggered.

It is hoped that one subscription specification might be shared by several subscriptions in the server.

class subscrEventSpec {
public:  
    // subscrSpec is by default is a dont care w.r.t
    // the eventSpec space
    virtual void require ( 
        epicsGuard &, const eventSpec & ) = 0;
    virtual void prohibit ( 
        epicsGuard &, const eventSpec & ) = 0;
    virtual bool isMatch ( 
        epicsGuard &, const eventSpec & ) const = 0;
    virtual void show ( 
        epicsGuard &, unsigned level ) const = 0;
};

Subscription Filter Specification

It is hoped that one subscription filter might be shared by several subscriptions installed into a service.

Should (can) a subscription spec be a property catalog?

class subscrFilterSpec {
public:
    // updates no less frequently than specified
    virtual void setPeriodMinimum (
        epicsGuard &, double periodInSeconds ) = 0;
    // updates no more frequently than specified
    virtual void setPeriodMaximum (
        epicsGuard &, double periodInSeconds ) = 0;
    // delta between updates no less than specified
    virtual void setPercentChangeMinimum ( 
        epicsGuard &, double percentChange ) = 0;
    // delta between updates no more than specified    
    virtual void setPercentChangeMaximum ( 
        epicsGuard &, double percentChange ) = 0;
    // when data acquisition system can pluck data at an offset
    virtual void setTriggerTimeOffset ( 
        epicsGuard &, double delayInSeconds ) = 0;
    // number of intermediate values saved when busy
    // before replacing last entry on queue
    virtual void setEventQueueLength ( 
        epicsGuard &, unsigned length ) = 0;
    // when supported by data store, specify
    // retrieval of values from the past
    virtual void setTimeWindow ( 
        epicsGuard &, epicsTime & begin, epicsTime & end ) = 0;
};

Write Request

class writeCompletionNotify { 
public:
    virtual void success ( 
        epicsGuard & ) = 0;    
    virtual void exception (      
        epicsGuard &, const diagnostic & ) = 0;
};
class writeRequest {
public:
    virtual void write ( 
        epicsGuard &, const propertyCatalog & ) = 0;
    virtual void write ( 
        epicsGuard &, const propertyCatalog &, 
        writeCompletionNotify & ) = 0;
    virtual void cancel ( 
        epicsGuard & ) = 0;
    virtual void show ( 
        epicsGuard &, unsigned level ) const = 0;
};

Read Request

class readCompletionNotify {
public:
    virtual void success (       
        epicsGuard &, const propertyCatalog & ) = 0;
    virtual void exception (
        epicsGuard &, const diagnostic & ) = 0;
};
class readRequest {
public:
    virtual void read (
        epicsGuard &, readCompletionNotify & ) = 0;
    virtual void cancel (
        epicsGuard & ) = 0;
    virtual void show (
        epicsGuard &, unsigned level ) const = 0;
};

Subscription Request

class subscriptionUpdateNotify {
public:
    virtual void update (
        epicsGuard &, const eventSpec &, 
        const propertyCatalog & ) = 0;    
    virtual void exception (
        epicsGuard &, const diagnostic & ) = 0;
};
class subscriptionRequest {
    virtual void subscribe ( 
        epicsGuard &, subscriptionUpdateNotify & ) = 0;
    virtual void cancel ( 
        epicsGuard & ) = 0;
    virtual void show ( 
        epicsGuard &, unsigned level ) const = 0;
};

Channel

The old interface assumed that when a channel is deleted then all related IO is also deleted. This requires an IO list in every channelwith attendent potential for redundant overhead. As a baseline, I intend to eliminate this practice, and therefore, a channel reference is not passed to the IO completion callback.

Users can subscribe for many different types of properties and events and therefore there might no longer be any need for native type/count returning functions in channel ( they can subscribe for "dimension", "bounds", "valueBehavior", "readAccess", "writeAccess", "confirmationRequested" properties ). This is also related to connect / disconnect notify callbacks specified when creating channel(they can subscribe for "state" property).

// I am actively considering abandoning this in favor of allowing 
// them to subscribe when the channel is created.
class channelStateNotify {
public:
    virtual void connectNotify () = 0;
    virtual void responsiveNotify () = 0;
    virtual void unresponsiveNotify () = 0;
    virtual void disconnectNotify () = 0;
};
class channel {
public:
    typedef unsigned priLevel_t;
    static const priLevel_t priorityMax;
    static const priLevel_t priorityMin;
    virtual writeRequest & createWriteRequest (
        epicsGuard &, 
        const propertyCatalogRegistration & ) = 0;
    virtual void destroyWriteRequest (
        epicsGuard &, writeRequest & ) = 0;
    virtual readRequest & createReadRequest (
        epicsGuard &, const propertyCatalogRegistration & ) = 0;
    // receive property description list, but not all
    // property values (avoid large arrays)? Does this identify a
    // interface defect in data access
// does an array of property id's need to be passed here so that 
// they can specify a starting point in the hierarchy?
    virtual readRequest & createAllPropertiesReadRequest (
        epicsGuard & ) = 0;
    virtual void destroyReadRequest 
        epicsGuard &, readRequest & ) = 0;
    virtual subscriptionRequest & createSubscriptionRequest (
        epicsGuard &, const propertyCatalogRegistration & ) = 0;
    virtual void destroySubscriptionRequest (
        epicsGuard &, subscriptionRequest & ) = 0;
    virtual void name (
        epicsGuard &, stringSegment & ) const = 0;
    virtual void show (
        epicsGuard &, unsigned level ) const = 0;
    virtual bool isConnected (
        epicsGuard & ) const = 0;
    virtual unsigned serviceName (
        epicsGuard &, stringSegment & ) const () = 0;
    virtual void flush (
        epicsGuard & ) = 0;
    // exceptions
    class badType : public diagnostic {};
    class propertyValueOutOfBounds {} : public diagnostic {};
    class invalidEventSelection {} : public diagnostic {};
    class noWriteAccess {} : public diagnostic {}; 
    class noReadAccess {} : public diagnostic {};
    class unsupportedByService {} : public diagnostic {};
    class requestTimedOut {} : public diagnostic {};
    class unresponsive {} : public diagnostic {};
    class disconnect {} : public diagnostic {};
}

Channel Factory

class channelFactory {
    virtual cacChannel & createChannel (
        epicsGuard &, const stringSegment & name, channelStateNotify &,
        cacChannel::priLevel_t = cacChannel::priorityMin ) = 0;
    virtual cacChannel & destroyChannel (
        epicsGuard &, cacChannel & ) = 0;
    // exceptions
    class priorityOutOfBounds {} : public diagnostic {};
};

Event Specification Factory

class eventSpecFactory {
    virtual eventSpec & createEventSpec (
        epicsGuard &, const stringSegment & eventName ) = 0;
    virtual eventSpec & createChannelTriggeredEventSpec (
        epicsGuard &, const stringSegment & triggerExpression ) = 0;
    virtual void destroyEventSpec (
        epicsGuard &, eventSpec & ) = 0;
};
class subscrSpecFactory {    
    virtual subscrFilterSpec & createSubscrFilterSpec (        
        epicsGuard & ) = 0;
    virtual void destroySubscrFilterSpec (
        epicsGuard &, subscrFilterSpec & ) = 0;
    virtual subscrEventSpec & createSubscrEventSpec (        
        epicsGuard & ) = 0;
    virtual void destroySubscrEventSpec (
        epicsGuard &, subscrEventSpec & ) = 0;
};

Property Catalog Registration

class propertyCatalogRegistration;

Perhaps its a defect that to register a data structure with a large array we must present a propertyCatalog which has reserved that much space, and therefore should a propertyCatalog have a "traverseStructure()" interface ?

class propertyCatalogRegistry {
    virtual class propertyCatalogRegistration & createRegistration (
        epicsGuard &, const propertyCatalog & ) = 0;
    virtual void destroyRegistration ( 
        epicsGuard &, propertyCatalogRegistration & ) = 0; 
};

Name Service Interface

A name service might also have subscription capabilities?

How does a name service differ from an ordinary service where each channel has an address property, and subordinate properties conveying the various different address formats? How do we accomodate a failover service address. Is this a subordinate property?

class nameLookupNotify {
    virtual void success (
        epicsGuard &, const propertyCatalog & address,
        const stringSegment & match, bool last ) = 0;
    virtual void exception (
        epicsGuard &, const diagnostic & ) = 0;
};
class nameLookupRequest {
    virtual void lookup (
        epicsGuard &, const stringSegment & name,
        const nameLookupNotify & ) = 0;
    virtual void cancel (
        epicsGuard & ) = 0;
    virtual void show (
        epicsGuard &, unsigned level ) const;
};
class nameService {
    virtual nameLookupRequest & createNameLookupRequest (
        epicsGuard & ) = 0;
    // not supported by all name services?
    virtual nameLookupRequest & 
        createRegularExpressionNameLookupRequest (  
            epicsGuard & ) = 0;
    virtual void destroyNameLookupRequest (
        epicsGuard &, nameRequest & ) = 0;
};

Client Context

The name "clientContext" should possibly be changed.

class clientContext :
    public eventSpecFactory,
    public subscrSpecFactory,
    public propertyCatalogRegistry {
};

Service

A service might failover to a backup service, but currently there appears to be no need to reveal this in public interfaces?

The relation between a name service, channelFactory, service, and genericService to each other are areas which are under active consideration.

class service : 
    public channelFactory, 
    public nameService { 
    virtual void flush ( 
        epicsGuard & ) = 0; 
    virtual void show ( 
        epicsGuard &, unsigned level ) const = 0; 
    // exceptions
    class disconnect {} : public diagnostic {}; 
};

Server

This interface is passed to the service factory.

class server : 
    public eventSpecFactory {
public:
    virtual void serviceExceptionNotify (
        epicsGuard &, diagnostic & ) = 0;
    // for attaching thread private variables
    // in preparation for asynchronous callback
    // from a service thread
    virtual void serviceThreadInitiateNotify (
        epicsGuard & ) = 0;
    virtual void serviceThreadExitNotify (
        epicsGuard & ) = 0;
    // for implementing non-preemptive callback
    // **** probably not needed if guard is based on a pure virtual mutex interface
    // **** and given that they can use thread private variables
    //virtual void serviceCallbackProcessingInitiateNotify (
    // epicsGuard & ) = 0;
    //virtual void serviceCallbackProcessingCompleteNotify (
    // epicsGuard & ) = 0;
};

Generic Service

A genericService is a special service granting homogenous access to multiple underlying services of different types. When an application creates a channel they might not need to know what service is the factory for the channel. Likewise, when they delete a channel they would not need to remember that the channel is recycled with the same service that created it. A genericService will attempt to initially locate the appropriate service, and should a connected service disconnect, attempt to transparently find a new one. A genericService might hide the need to recreate a channel or an IO request when a service disconnects from client applications. This would be accomplished by creating a channel that is a handle to a service specific channel, and an IO request that is a handle to a service specific IO request.

class genericServiceFactory {
public:
    virtual service & createGenericService (
        epicsGuard &, epicsMutex &,
        serviceStateChangeNotify &,
        serviceLocator & ) = 0;
    virtual void destroyGenericService (
        epicsGuard &, service & ) = 0;
};

Network Server/Service Interfaces

These interfaces may be accessed with the dynamic_cast operator

class beaconGenerator {
public:
    virtual void generateBeaconAnomaly (
        epicsGuard & ) = 0;
};
class beaconAnomalyDetectorStateChangeNotify {
public:
    virtual unsigned beaconAnomalyDetectNotify (
        epicsGuard &, const propertyCatalog & ) const = 0;
};
// only access to this will be using dynamic_cast
class networkChannelDiagnostics {
    virtual unsigned searchAttempts (
        epicsGuard & ) const = 0;
};
// only access to this will be using dynamic_cast
class networkCircuitDiagnostics {
    virtual double estimatedBeaconPeriod (
        epicsGuard & ) const; 
    // negative DBL_MAX if UKN
    virtual double receiveWatchdogDelayToExperation (
        epicsGuard & ) const; 
    // negative DBL_MAX if UKN
    virtual unsigned protocolRevision (
        epicsGuard & ) const;
};
// only access to this will be using dynamic_cast
class serviceDiagnostics {
public:
    epicsShareFunc unsigned subscriptionEventsPosted () const;
    epicsShareFunc unsigned subscriptionEventsProcessed () const;
};
// only access to this will be using dynamic_cast
class beaconAnomalyDetectorDiagnostics {
public:
    virtual unsigned beaconAnomaliesDetected (
        epicsGuard & ) const = 0;
};

Oustanding Issues

Locking issues. To what degree are we forcing everything to use the same lock? What will be the minimal locking granularity?

How much of the class name should be in the pure virtual function name for uniqueness?

Unification with the PCAS interface requires more work. In particulant posting and event registration.

What type of string interface will be used, and how will this be unified with the database?