Difference between revisions of "V4 CA Client User Interface"
KayKasemir (talk | contribs) m (→Data Access) |
KayKasemir (talk | contribs) (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 | === 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 = "")<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 | === 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 | === Channel: Listener === | ||
The Channel::Listener interface is invoked in response to the many asynchronous methods of the Channel. | |||
The first | * 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()<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 | === Channel: Writing === | ||
* | * write(new value)<BR>Sends the value to the server. | ||
* | * 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. | ||
=== Channel | === Channel: Reading === | ||
* | * createSubscription(list<property> what, Event e, Filter f)<BR>Will invoke Listener once data arrives. | ||
** event: alarm condition change | ** event is a set of any of the following: | ||
*** exceeded absolute value deadband, exceeded percentage change, exceeded logarithmic change | |||
* cancelSubscription( | *** 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) | |||
=== SyncChannel === | |||
A wrapper class around the async. Channel. | |||
Uses a configurable timeout and provides synchronous 'read', 'write'. | |||
=== Container === | === Container === | ||
The Channel does not store any data | 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: | ||
SyncChannel channel("fred"); | |||
DataAccess da = channel. | 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?
- A brief look at ZeroC ICE
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'
- event is a set of any of the following:
- 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();