.. _API: aioca API ========= .. module:: aioca .. _Common: Common Notes ------------ All four functions take an argument ``pv`` which can specify the name of a single PV or can be a list of PVs. In all cases the returned result has the same "shape" as the ``pv`` argument, in other words, if ``pv`` is a single string then a single value (error code, value, or subscription) is returned, and if ``pv`` is a list then a list of exactly the same length is returned. In general there are advantages to calling `caput`, `caget` or `connect` on a list of PVs, as in this case the channel connection and access delays will occur in parallel. Several arguments are common through this API: ``throw`` determines how errors are handled, ``timeout`` determines timeouts, and finally ``datatype``, ``format`` and ``count`` determine data formats and are documented in `Augmented`. ``timeout`` The ``timeout`` argument specified how long `caput` or `caget` will wait for the entire operation to complete. This timeout is in seconds, and can be one of several formats: a timeout interval in seconds, an absolute deadline (in `time.time` format) as a single element tuple, or None to specify that no timeout will occur. Note that a timeout of 0 will timeout immediately if any waiting is required. If a timeout occurs then a `CANothing` will be raised unless ``throw=False`` has been set. ``throw`` This parameter determines the behaviour of `caget`, `caput`, and `connect` when an error occurs. If ``throw=True`` (the default) is set then an exception is raised, otherwise if ``False`` is specified an error code value is returned for each failing PV. Functions --------- .. autofunction:: caput The return value from `caput` is either a list or a single value, depending on the shape of ``pv``. For each PV a `CANothing` success code is returned on success, otherwise either an exception is raised or an appropriate error code is returned for each failing PV if ``throw=True`` is set. The return code can be tested for boolean success, so for example it is possible to write:: if not caput(pv, value, throw=False): # process caput error If all the PVs listed in ``pv`` have already been connected, through a successful call to any `aioca` method, then the library guarantees that the puts for each PV will occur strictly in sequence. For any PVs which need a connection to be established the order of execution of puts is completely undefined. .. autofunction:: caget The various arguments control the behaviour of `caget` as follows: ``datatype``, ``format``, ``count`` See documentation for :ref:`Augmented` below. ``timeout``, ``throw`` Documented in :ref:`Common` above. If a value cannot be retrieved and ``throw=False`` is set then for each failing PV an empty value with ``.ok==False`` is returned. The format of values returned depends on the number of values requested for each PV. If only one value is requested then the value is returned as a scalar, otherwise as a numpy array. .. autofunction:: camonitor For a single pv callbacks will be called as:: callback(value) for each update where value is an `AugmentedValue`. For a list of pvs then each update is called as:: callback(value, index) where index is the position in the original array of pvs of the name generating this update. If an async function as passed as a callback, then it will be awaited and no further callbacks will be run for this particular Subscription until this completes. This can be useful in conjunction with the default ``all_updates=False`` for running periodic updating code like:: async def about_once_a_second(value): do_something_with(value) await asyncio.sleep(1) camonitor(pv, callback=about_once_a_second) .. note:: If you have the choice between sync and async functions (like `asyncio.Queue.put_nowait` vs `asyncio.Queue.put` on an unbounded Queue) then choose the sync option for better performance Subscriptions will remain active until the :meth:`~Subscription.close()` method is called on the returned subscription object: .. autoclass:: Subscription() :members: .. autofunction:: connect .. autofunction:: cainfo .. autoclass:: CAInfo() :members: The `str` representation of this structure can be printed to produce output similar to that produced by the ``cainfo`` command line tool. It is possible to test whether a channel has successfully connected without provoking suspension by calling ``cainfo(pv, wait=False)`` and testing the ``.state`` attribute of the result. All of the above functions will make a connection to a channel which is cached for future calls. If you need to clear this cache (e.g. in tests) you can call: .. autofunction:: purge_channel_caches All the async functions in the `aioca` interface can be run under the asyncio event loop. A convenience function is provided to do this: .. autofunction:: run .. autoclass:: ChannelInfo() :members: .. autofunction:: get_channel_infos .. _Values: Working with Values ------------------- There are two types of values returned by `aioca` functions: `Augmented` and `Error`. The `caput` function only returns an error code value (which may indicate success), while `caget` and `camonitor` will normally return (or deliver) augmented values, but will return (or deliver) an error code on failure. The following fields are common to both types of value. This means that is is always safe to test ``value.ok`` for a value returned by `caget` or `caput` or delivered by `camonitor`. ``ok`` Set to ``True`` if the data is good, ``False`` if there was an error. For augmented values ``ok`` is always set to ``True``. ``name`` Name of the pv. Values and their Types ~~~~~~~~~~~~~~~~~~~~~~ The type of values returned by `caget` or delivered by `camonitor` callbacks is determined by the requested datatype in the original `caget` or `camonitor` call together with the underlying length of the requested EPICS field. If the underlying length (`element_count`) of the EPICS value is 1 then the value will be returned as a Python scalar, and will be one of the three basic scalar types (string, integer or floating point number), but wrapped as an augmented type. If on the other hand `element_count` is not 1 then the value is treated as an array and is always returned as a numpy array, again wrapped as an augmented type. Note that this means that even if ``caget(pv, count=1)`` is used to fetch a value with one element, if the underlying PV is an array then the result returned will be an array. The table below enumerates the possibilities: =========== =============== ======================================== aioca type Derived from For these values =========== =============== ======================================== `ca_str` `str` String value `ca_int` `int` Integral value `ca_float` `float` Floating point value `ca_array` `ndarray` Any array value =========== =============== ======================================== .. class:: ca_str .. class:: ca_int .. class:: ca_float Scalar types derived from basic Python types. .. class:: ca_array Array type derived from `numpy.ndarray`. The associated :attr:`~numpy.ndarray.dtype` will be as close a fit to the underlying data as possible. .. _Error: Error Code Values ~~~~~~~~~~~~~~~~~ .. autoclass:: CANothing :members: The following ECA error codes from ``epicscorelibs.ca.cadef`` are worth noting: ``ECA_SUCCESS`` Success error code. In this case ``.ok`` is ``True``. Returned by successful `caput` and `connect` calls. ``ECA_DISCONN`` Channel disconnected. This is used by `camonitor` to report channel disconnect events. ``ECA_TIMEOUT`` Channel timed out. Reported if user specified timeout ocurred before completion and if ``throw=False`` specified. .. _Augmented: Augmented Values ~~~~~~~~~~~~~~~~ Augmented values are normally Python or `numpy` values with extra fields: the `!.ok` and `!.name` fields are already mentioned above, and further extra fields will be present depending on format requested for the data. As pointed out above, `!.ok` is always `True` for valid data. Four different types of augmented value are returned: strings, integers, floating point numbers or arrays, depending on the length of the data requested -- an array is only used when the data length is >1. In almost all circumstances an augmented value will behave exactly like a normal value, but there are a few rare cases where differences in behaviour are observed (these are mostly bugs). If this occurs the augumentation can be stripped from an augmented value ``value`` by writing ``+value`` -- this returns the underlying value. The type of augmented values is determined both by parameters passed to `caget` and `camonitor` and by the underlying datatype. Both of these functions share parameters ``datatype``, ``format`` and ``count`` which can be used to control the type of the data returned: ``datatype`` For `caget` and `camonitor` this controls the format of the data that will be requested, while for `caput` the data will be coerced into the requested format. ``datatype`` can be any of the following: 1. ``None`` (the default). In this case the "native" datatype provided by the channel will be returned. 2. A `Dbr` value. See items 5 onwards for details of the special values. 3. A python type compatible with any of the above values, such as `int`, `float` or `str`. These correspond to ``DBR_LONG``, ``DBR_DOUBLE`` and ``DBR_STRING`` respectively. 4. Any `numpy.dtype` compatible with any of the above values. 5. One of the special values ``DBR_CHAR_STR``, ``DBR_CHAR_UNICODE``, or ``DBR_CHAR_BYTES``. This is used to request a char array which is then converted to a Python `str` or `bytes` string on receipt. It is not sensible to specify `count` with this option. The options ``DBR_CHAR_BYTES`` and ``DBR_CHAR_UNICODE`` are meaningless and not supported for `caput`. Note that if the PV name ends in ``$`` and ``datatype`` is not specified then ``DBR_CHAR_STR`` will be used. 6. The special value ``DBR_ENUM_STR``, only for `caget` and `camonitor`. In this case the "native" channel datatype is used unless the channel is an enumeration, in which case the corresponding string is returned. 7. For `caget` and `camonitor` two further special values are supported. In both of these cases `format` is ignored: .. data:: DBR_STSACK_STRING Returns the current value as a string together with extra fields `status`, `severity`, `ackt`, `acks`. .. data:: DBR_CLASS_NAME Returns the name of the "enclosing interface", typically the record type, and typically the same as the EPICS ``.RTYP`` field. For `caput` also two further values are supported: .. data:: DBR_PUT_ACKT DBR_PUT_ACKS These are used for global alarm acknowledgement, where `DBR_PUT_ACKT` configures whether alarms need to be acknowleged and `DBR_PUT_ACKS` acknowledges alarms of a particular severity. ``format`` The `Format` controls how much auxilliary information will be returned with the retrieved data. ``count`` The `Count` determines how many elements to fetch for arrays .. automodule:: aioca.types :members: :member-order: alphabetical