Difference between revisions of "V4 CA Client User Interface"

From EPICSWIKI
(Ideas for the event & Filter. Separate "SyncChannel")
Line 19: Line 19:
that a CA client API should provide.
that a CA client API should provide.


=== Directory Server ===
=== Directory ===
* setServer(string URL-type-server-address)<BR>Optional; otherwise some site-specific default name server is used. That 'URL' might contain a user & password, which decides if this name server connection is read-only (for OPI clients) or if writes are allowed (for IOCs that add PVs to the name server).
The directory is used to discover available channels and map them to the CA Server address and port.
* Directory(string URL-type-server-address = "")<BR>Constructor; uses site-specific default server or specific one. The 'URL' might contain a user & password, which decides if this name server connection is read-only (for OPI clients) or if writes are allowed (for IOCs that add PVs to the name server).
* getChannelInfo(string PV_or_pattern)<BR>Returns list of
* getChannelInfo(string PV_or_pattern)<BR>Returns list of
** CA server - IP & port of server that has the PV
** CA server - IP & port of server that has the PV
Line 37: Line 38:
* string getAsString(string property)
* string getAsString(string property)


=== Channel, General Methods ===
=== Channel ===
* Channel(string name)<br>Constructor. Channel has to have a name.
* Channel(string name, Directory dir = default)<br>Constructor. Channel has to have a name. Uses the 'best' channel from the default directory or from a given directory.
* Channel(string name, CASInfo)<br>... in case you want a specific server after querying the directory yourself or not using a directory at all.
* getName()<br>Returns the name of the channel.
* getName()<br>Returns the name of the channel.
* addListener(Listener l), removeListener(Listener l)<br>Register for notifications, see below.


=== Channel, Connection Related Methods ===
=== Channel: Listener ===
One idea is that - in contrast to the V3 API - the user shouldn't have to connect at all.
The Channel::Listener interface is invoked in response to the many asynchronous methods of the Channel.
The first 'get' or 'put' will try to connect.
* writeComplete(Channel ch)
A disconnect is a special type of data notification, not a separate
** Channel that send this notification
connection callback.
* newData(Channel ch, DataAccess data, Event why)
** DataAccess interface to the data
** Reason for the update: Value deadband exceeded, minimum period expired, event 'blue beam', ...
* disconnected(Channel ch)
* accessRightChange(Channel ch)
 
Alternatively, these could be separate interfaces for a writeListener, dataListener, stateListener.
 
=== Channel: State ===
In contrast to the V3 API, the user doesn't 'connect'.
The first data notification implies that we're connected.


* setDirectory(string directory_URL)<br>Use specific directory server, otherwise the default one is used.
* setServer(CA server info)<BR>Attempts to connect & maintain the connection with specific server. Otherwise, the directory is queried.
* bool isConnected()<BR> .. for those who want to poll
* bool isConnected()<BR> .. for those who want to poll
* xxx getServerInfo(), xxx getType()<BR>  .. only valid when isConnected().
* xxx getServerInfo(), xxx getType()<BR>  .. only valid when isConnected().
* setUser(), ...<BR>Sets/changes the 'user' that determines the access rights, allowing OPI tools to adjust this per-channel at runtime.
* setUser(), ...<BR>Sets/changes the 'user' that determines the access rights, allowing OPI tools to adjust this per-channel at runtime.


=== Channel, 'Put' Related Methods ===
=== Channel: Writing ===
* put(new value)<BR>Sends data to the server.<BR>Returns error if currently disconnected or other local problem, no other feedback wether the value actually reached the server.
* write(new value)<BR>Sends the value to the server.
* putNotify(new value), putCompletionNotify(new value)<BR>Sends the value to the server, invokes putNotification when receiving record has received the value respectively all the processing triggered by the new value has completed.
* createWriteRequest(new value, receipt {delivery, completion})<BR>Sends the value to the server, invokes Listener when CA server has received the value respectively all the processing triggered by the new value has completed.
* addPutListener(pnl), removePutListener(pnl)<BR>Need to register listener to actually receive the put*Notify info.
 
=== Channel, 'Get' Related Methods ===
* DataAccess = getData(property_list)<BR> Waits for the data.
* getDataNotify(property_list)<BR>  Will invoke DataListener once data arrives.
* addDataListener(dn), removeDataListener(dl)
 
=== Data Listener Interface===
The data listener is invoked in response to an async. 'get' as well as a subscription update and contains the following:
* Channel that send this notification
* DataAccess interface to the data
* Reason for the update
** event 'x'
** channel is disconnected
** access rights changed
** channel moved to different IOC


=== Channel, Subscription Related Methods ===
=== Channel: Reading ===
* addSubscription(event, filter)
* createSubscription(list<property> what, Event e, Filter f)<BR>Will invoke Listener once data arrives.
** event: alarm condition change, some hardware event (like blue beam).<br>Is this still simply a bit mask, and one needs detailed info from the IOC to know that 'blue beam' == bit 14?
** event is a set of any of the following:
** filters: min/max period, range, rate of change, absolute change
*** exceeded absolute value deadband, exceeded percentage change, exceeded logarithmic change
* cancelSubscription(event, filter)
*** minimum update period expired
*** alarm condition change
*** some hardware event (like blue beam)
** filters
*** override server-side idea of the value deadband, percentage change, log. change, minumum update rate, maximum update rate
*** specify value count<br>setting this to '1' turns the subscription into a single-value 'get'
* cancelSubscription(Event, Filter)


The idea is that the end result of a subscription is just like a getDataNotify,
=== SyncChannel ===
invoking the dataListener, except that a subscription will
A wrapper class around the async. Channel.
typically return data more than once.
Uses a configurable timeout and provides synchronous 'read', 'write'.
One can add more then one subscription to the same channel.


=== Container ===
=== Container ===
The Channel does not store any data from a 'put', 'get' or subscription.
The Channel does not store any data.
When attaching a container to a channel, the container will subscribe
When attaching a container to a channel, the container will subscribe
to the channel and keep a copy of all data, so one can always ask
to the channel and keep a copy of all data, so one can always ask
Line 96: Line 96:
This is how a simple 'caget' could be written:
This is how a simple 'caget' could be written:


  Channel channel("fred");  
  SyncChannel channel("fred");  
  DataAccess da = channel.get("value");
  DataAccess da = channel.read("value");
  cout << "Value of " << channel.getName() << " : " << da.getAsString("value") << "\n";
  cout << "Value of " << channel.getName() << " : " << da.getAsString("value") << "\n";
  channel.disconnect();
  channel.disconnect();

Revision as of 16:07, 24 June 2005

Channel Access Client User Interface

Under V4, a ProcessVariable would no longer be limited to the current properties 'value', 'units', ... but allow the users to create CA servers and clients that understand new properties.

The low-level V4 CA client API is likely to be rather complex because it now needs to handle arbitrary property catalogs.

  • There still needs to be an easy to use high-level API, not much more complex than the existing one.
  • There needs to be access to CA from languages like Matlab in a way that's as easy as
pv = caopen('fred');
value = caget(pv);

Food for thought

Is there anything we can learn from other communication libraries?

Skeleton API

What follows is in the form of pseudo classes and associated methods that a CA client API should provide.

Directory

The directory is used to discover available channels and map them to the CA Server address and port.

  • Directory(string URL-type-server-address = "")
    Constructor; uses site-specific default server or specific one. The 'URL' might contain a user & password, which decides if this name server connection is read-only (for OPI clients) or if writes are allowed (for IOCs that add PVs to the name server).
  • getChannelInfo(string PV_or_pattern)
    Returns list of
    • CA server - IP & port of server that has the PV
    • quality - is this the IOC, a gateway, backup/primary
  • addChannelInfo(string PV, CASInfo addr_and_port, CASType primary_or_backup_or...)
    Used by CA servers to register their PV in directory
  • deleteChannelInfo(string PV, CASInfo addr_and_port, CASType primary_or_backup_or...)
    Used by CA servers to remove their PV from directory

Data Access

All the data is accessed via DataAccess, which handles the introspection of arbitrary data types. It should provide the following convenience routines in addition to whatever more efficient methods it might have (using hash IDs instead property name string etc.):

  • list<string> getProperties()
    Get a list of all the properties
  • type_info getType(string property)
  • bool hasWriteAccess(string property)
  • string getAsString(string property)

Channel

  • Channel(string name, Directory dir = default)
    Constructor. Channel has to have a name. Uses the 'best' channel from the default directory or from a given directory.
  • Channel(string name, CASInfo)
    ... in case you want a specific server after querying the directory yourself or not using a directory at all.
  • getName()
    Returns the name of the channel.
  • addListener(Listener l), removeListener(Listener l)
    Register for notifications, see below.

Channel: Listener

The Channel::Listener interface is invoked in response to the many asynchronous methods of the Channel.

  • writeComplete(Channel ch)
    • Channel that send this notification
  • newData(Channel ch, DataAccess data, Event why)
    • DataAccess interface to the data
    • Reason for the update: Value deadband exceeded, minimum period expired, event 'blue beam', ...
  • disconnected(Channel ch)
  • accessRightChange(Channel ch)

Alternatively, these could be separate interfaces for a writeListener, dataListener, stateListener.

Channel: State

In contrast to the V3 API, the user doesn't 'connect'. The first data notification implies that we're connected.

  • bool isConnected()
    .. for those who want to poll
  • xxx getServerInfo(), xxx getType()
    .. only valid when isConnected().
  • setUser(), ...
    Sets/changes the 'user' that determines the access rights, allowing OPI tools to adjust this per-channel at runtime.

Channel: Writing

  • write(new value)
    Sends the value to the server.
  • createWriteRequest(new value, receipt {delivery, completion})
    Sends the value to the server, invokes Listener when CA server has received the value respectively all the processing triggered by the new value has completed.

Channel: Reading

  • createSubscription(list<property> what, Event e, Filter f)
    Will invoke Listener once data arrives.
    • event is a set of any of the following:
      • exceeded absolute value deadband, exceeded percentage change, exceeded logarithmic change
      • minimum update period expired
      • alarm condition change
      • some hardware event (like blue beam)
    • filters
      • override server-side idea of the value deadband, percentage change, log. change, minumum update rate, maximum update rate
      • specify value count
        setting this to '1' turns the subscription into a single-value 'get'
  • cancelSubscription(Event, Filter)

SyncChannel

A wrapper class around the async. Channel. Uses a configurable timeout and provides synchronous 'read', 'write'.

Container

The Channel does not store any data. When attaching a container to a channel, the container will subscribe to the channel and keep a copy of all data, so one can always ask the container for the current values.

  • attach(channel)
  • detach()
  • implements the DataAccess interface to allow access to the data.

caget 101

This is how a simple 'caget' could be written:

SyncChannel channel("fred"); 
DataAccess da = channel.read("value");
cout << "Value of " << channel.getName() << " : " << da.getAsString("value") << "\n";
channel.disconnect();