1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746
|
=================================================
ca: Low-level Channel Access module
=================================================
.. module:: epics.ca
:synopsis: low-level Channel Access module.
The :mod:`ca` module provides a low-level wrapping of the EPICS Channel Access
(CA) library, using ctypes. Most users of the `epics` module will not need to
be concerned with most of the details here, and will instead use the simple
procedural interface (:func:`epics.caget`, :func:`epics.caput` and so on), or
use the :class:`epics.PV` class to create and use epics PV objects.
General description, difference with C library
=================================================
The :mod:`ca` module provides a fairly complete mapping of the C interface to
the CA library while also providing a pleasant Python experience. It is
expected that anyone using this module is somewhat familiar with Channel
Access and knows where to consult the `Channel Access Reference Documentation
<https://epics.anl.gov/base/R3-14/8-docs/CAref.html>`_. Here, we focus on the
differences with the C interface, and assume a general understanding of what
the functions are meant to do.
Name Mangling
~~~~~~~~~~~~~
As a general rule, a CA function named `ca_XXX` in the C library will have the
equivalent function called `XXX` in the `ca` module. This is because the
intention is that one will import the `ca` module with
>>> from epics import ca
so that the Python function :func:`ca.XXX` will corresponds to the C
function `ca_XXX`. That is, the CA library called its functions `ca_XXX`
because C does not have namespaces. Python does have namespaces, and so
they are used.
Similar name *un-mangling* also happens with the DBR prefixes for
constants, held here in the `dbr` module. Thus, the C constant DBR_STRING
becomes dbr.STRING in Python.
Other Changes and Omissions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Several function in the C version of the CA library are not implemented in
the Python module. Most of these unimplemented functions are currently
seen as unnecessary for Python, though some of these could be added without
much trouble if needed. See :ref:`ca-omissions-label` for further details.
In addition, while the CA library supports several `DBR` types in C, not
all of these are supported in Python. Only native types and their DBR_TIME
and DBR_CTRL variants are supported here. The DBR_STS and DBR_GR variants
are not, as they are subsets of the DBR_CTRL type, and space optimization
is not something you'll be striving for with Python. Several `dbr_XXX`
functions are also not supported, as they appear to be needed only to be
able to dynamically allocate memory, which is not necessary in Python.
.. _ca-init-label:
Initialization, Finalization, and Life-cycle
==============================================
The Channel Access library must be initialized before it can be used.
There are 3 main reasons for this need:
1. CA requires a context model (preemptive callbacks or non-preemptive
callbacks) to be specified before any actual calls can be made.
2. the ctypes interface requires that the shared library be loaded
before it is used.
3. ctypes also requires that references to the library and callback
functions be kept for the life-cycle of CA-using part of a program (or
else they will be garbage collected).
As far as is possible, the :mod:`ca` module hides the details of the CA
lifecyle from the user, so that it is not necessary to to worry about
explicitly initializing a Channel Access session. Instead, the library is
initialized as soon as it is needed, and intervention is really only
required to change default settings. The :mod:`ca` module also handles
finalizing the CA session, so that core-dumps and warning messages do not
happen due to CA still being 'alive' as a program ends.
Because some users may wish to customize the initialization and
finalization process, the detailed steps will be described here. These
initialization and finalization tasks are handled in the following way:
* The :data:`libca` variable in the :mod:`ca` module holds a permanent,
global reference to the CA shared object library (DLL).
* the function :func:`initialize_libca` is called to initialize libca.
This function takes no arguments, but does use the global Boolean
:data:`PREEMPTIVE_CALLBACK` (default value of ``True``) to control
whether preemptive callbacks are used.
* the function :func:`finalize_libca` is used to finalize libca.
Normally, this is function is registered to be called when a program
ends with :func:`atexit.register`. Note that this only gets called on
a graceful shutdown. If the program crashes (for a non-CA related
reason, for example), this finalization may not be done, and
connections to Epics Variables may not be closed completely on the
Channel Access server.
.. data:: PREEMPTIVE_CALLBACK
sets whether preemptive callbacks will be used. The default value is
``True``. If you wish to run without preemptive callbacks this variable
*MUST* be set before any other use of the CA library. With preemptive
callbacks enabled, EPICS communication will not require client code to
continually poll for changes. With preemptive callback disables, you
will need to frequently poll epics with :func:`pend_io` and
func:`pend_event`.
.. data:: DEFAULT_CONNECTION_TIMEOUT
sets the default `timeout` value (in seconds) for
:func:`connect_channel`. The default value is `2.0`
.. data:: AUTOMONITOR_MAXLENGTH
sets the default array length (ie, how many elements an array has) above
which automatic conversion to numpy arrays *and* automatic monitoring
for PV variables is suppressed. The default value is 65536. To be
clear: waveforms with fewer elements than this value will be
automatically monitored changes, and will be converted to numpy arrays
(if numpy is installed). Larger waveforms will not be automatically
monitored.
:ref:`arrays-label` and :ref:`arrays-large-label` for more details.
Using the CA module
====================
Many general-purpose CA functions that deal with general communication and
threading contexts are very close to the C library:
.. autofunction:: initialize_libca()
.. autofunction:: finalize_libca()
.. autofunction:: pend_io(timeout=1.0)
.. autofunction:: pend_event(timeout=1.e-5)
.. autofunction:: poll(evt=1.e-5[, iot=1.0])
.. autofunction:: create_context()
.. autofunction:: destroy_context()
.. autofunction:: current_context()
.. autofunction:: attach_context(context)
.. autofunction:: detach_context()
.. autofunction:: use_initial_context()
.. autofunction:: client_status(context, level)
.. autofunction:: version()
.. autofunction:: message(status)
.. autofunction:: flush_io()
.. autofunction:: replace_printf_handler(fcn=None)
.. warning::
`replace_printf_handler()` appears to not actually work.
We think this is due to a real limitation of Python's `ctypes` module
not supporting the mapping of C *va_list* function arguments to Python.
If you are interested in this or have ideas of how to fix it, please
let us know.
Creating and Connecting to Channels
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The basic channel object is the Channel ID or ``chid``. With the CA
library (and ``ca`` module), one creates and acts on the ``chid`` values.
These are simply :data:`ctypes.c_long` (C long integers) that hold the
memory address of the C representation of the channel, but it is probably
a good idea to treat these as object instances.
.. autofunction:: create_channel(pvname, connect=False, callback=None, auto_cb=True)
.. autofunction:: connect_channel(chid, timeout=None, verbose=False)
Many other functions require a valid Channel ID, but not necessarily a
connected Channel. These functions are essentially identical to the CA
library versions, and include:
.. autofunction:: name(chid)
.. autofunction:: host_name(chid)
.. autofunction:: element_count(chid)
.. autofunction:: replace_access_rights_event(chid, callback=None)
.. autofunction:: read_access(chid)
.. autofunction:: write_access(chid)
.. autofunction:: field_type(chid)
See the *ftype* column from :ref:`Table of DBR Types <dbrtype_table>`.
.. autofunction:: clear_channel(chid)
.. autofunction:: state(chid)
A few additional pythonic functions have been added:
.. autofunction:: isConnected(chid)
.. autofunction:: access(chid)
.. autofunction:: promote_type(chid, [use_time=False, [use_ctrl=False]])
See :ref:`Table of DBR Types <dbrtype_table>`.
.. data:: _cache
The ca module keeps a global cache of Channels that holds connection
status and a bit of internal information for all known PVs. This cache
is not intended for general use.
.. autofunction:: show_cache(print_out=True)
.. autofunction:: clear_cache()
Interacting with Connected Channels
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Once a ``chid`` is created and connected there are several ways to
communicating with it. These are primarily encapsulated in the functions
:func:`get`, :func:`put`, and :func:`create_subscription`, with a few
additional functions for retrieving specific information.
These functions are where this python module differs the most from the
underlying CA library, and this is mostly due to the underlying CA function
requiring the user to supply DBR TYPE and count as well as ``chid`` and
allocated space for the data. In python none of these is needed, and
keyword arguments can be used to specify such options.
.. autofunction:: get(chid, ftype=None, count=None, as_string=False, as_numpy=True, wait=True, timeout=None)
See :ref:`Table of DBR Types <dbrtype_table>` for a listing of values of *ftype*,
See :ref:`arrays-large-label` for a discussion of strategies for how to best deal with very large arrays.
See :ref:`advanced-connecting-many-label` for a discussion of when using `wait=False` can give a large performance boost.
See :ref:`advanced-get-timeouts-label` for further discussion of the *wait* and *timeout* options and the associated :func:`get_complete` function.
.. autofunction:: get_with_metadata(chid, ftype=None, count=None, as_string=False, as_numpy=True, wait=True, timeout=None)
.. autofunction:: get_complete(chid, ftype=None, count=None, as_string=False, as_numpy=True, timeout=None)
See :ref:`advanced-get-timeouts-label` for further discussion.
.. autofunction:: get_complete_with_metadata(chid, ftype=None, count=None, as_string=False, as_numpy=True, timeout=None)
.. autofunction:: put(chid, value, wait=False, timeout=30, callback=None, callback_data=None)
See :ref:`ca-callbacks-label` for more on this *put callback*,
.. autofunction:: create_subscription(chid, use_time=False, use_ctrl=False, mask=None, callback=None)
See :ref:`ca-callbacks-label` for more on writing the user-supplied callback,
.. warning::
*event_id* is the id for the event (useful for clearing a subscription).
You **must** keep the returned tuple in active variables, either as a
global variable or as data in an encompassing class.
If you do *not* keep this data, the return value will be garbage
collected, the C-level reference to the callback will disappear, and you
will see coredumps.
On Linux, a message like::
python: Objects/funcobject.c:451: func_dealloc: Assertion 'g->gc.gc_refs != (-2)' failed.
Abort (core dumped)
is a hint that you have *not* kept this data.
.. data:: DEFAULT_SUBSCRIPTION_MASK
This value is the default subscription type used when calling
:func:`create_subscription` with `mask=None`. It is also used by
default when creating a :class:`PV` object with auto_monitor is set
to ``True``.
The initial default value is *dbr.DBE_ALARM|dbr.DBE_VALUE*
(i.e. update on alarm changes or value changes which exceeds the
monitor deadband.) The other possible flag in the bitmask is
*dbr.DBE_LOG* for archive-deadband changes.
If this value is changed, it will change the default for all
subsequent calls to :func:`create_subscription`, but it will not
change any existing subscriptions.
.. autofunction:: clear_subscription(event_id)
Several other functions are provided:
.. autofunction:: get_timestamp(chid)
.. autofunction:: get_severity(chid)
.. autofunction:: get_precision(chid)
.. autofunction:: get_enum_strings(chid)
.. autofunction:: get_ctrlvars(chid)
See :ref:`Table of Control Attributes <ctrlvars_table>`
.. _ctrlvars_table:
Table of Control Attributes
==================== ==============================
*attribute* *data types*
==================== ==============================
status
severity
precision 0 for all but double, float
units
enum_strs enum only
upper_disp_limit
lower_disp_limit
upper_alarm_limit
lower_alarm_limit
upper_warning_limit
lower_warning_limit
upper_ctrl_limit
lower_ctrl_limit
==================== ==============================
Note that *enum_strs* will be a tuple of strings for the names of ENUM
states.
.. autofunction:: get_timevars(chid)
.. _ca-sg-label:
Synchronous Groups
~~~~~~~~~~~~~~~~~~~~~~~
.. warning::
Synchronous groups are simulated in pyepics, but are not recommended,
and probably don't really make sense for usage within pyepics and using
asynchronous i/o anyway.
Synchronous Groups are can be used to ensure that a set of Channel Access
calls all happen together, as if in a *transaction*. Synchronous Groups
should be avoided in pyepics, and are not well tested. They probably make
little sens in the context of asynchronous I/O. The documentation here is
given for historical purposes.
The idea is to first create a synchronous group, then add a series of
:func:`sg_put` and :func:`sg_get` which do not happen immediately, and
finally block while all the channel access communication is done for the
group as a unit. It is important to *not* issue :func:`pend_io` during the
building of a synchronous group, as this will cause pending :func:`sg_put`
and :func:`sg_get` to execute.
.. autofunction:: sg_create()
.. autofunction:: sg_delete(gid)
.. autofunction:: sg_block(gid[, timeout=10.0])
.. autofunction:: sg_get(gid, chid[, ftype=None[, as_string=False[, as_numpy=True]]])
.. autofunction:: sg_put(gid, chid, value)
.. autofunction:: sg_test(gid)
.. autofunction:: sg_reset(gid)
.. _ca-implementation-label:
Implementation details
================================
The details given here should mostly be of interest to those looking at the
implementation of the `ca` module, those interested in the internals, or
those looking to translate lower-level C or Python code to this module.
DBR data types
~~~~~~~~~~~~~~~~~
.. _dbrtype_table:
Table of DBR Types
============== =================== ========================
*CA type* *integer ftype* *Python ctypes type*
============== =================== ========================
string 0 string
int 1 integer
short 1 integer
float 2 double
enum 3 integer
char 4 byte
long 5 integer
double 6 double
time_string 14
time_int 15
time_short 15
time_float 16
time_enum 17
time_char 18
time_long 19
time_double 20
ctrl_string 28
ctrl_int 29
ctrl_short 29
ctrl_float 30
ctrl_enum 31
ctrl_char 32
ctrl_long 33
ctrl_double 34
============== =================== ========================
`PySEVCHK` and ChannelAccessExcepction: checking CA return codes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. exception:: ChannelAccessException
This exception is raised when the :mod:`ca` module experiences
unexpected behavior and must raise an exception
.. autofunction:: PySEVCHK(func_name, status[, expected=dbr.ECA_NORMAL])
.. autofunction:: withSEVCHK(fcn)
Function Decorators
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In addition to :func:`withSEVCHK`, several other decorator functions are
used heavily inside of ca.py or are available for your convenience.
.. autofunction:: withCA(fcn)
.. autofunction:: withCHID(fcn)
.. autofunction:: withConnectedCHID(fcn)
.. autofunction:: withInitialContext(fcn)
See :ref:`advanced-threads-label` for further discussion.
Unpacking Data from Callbacks
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Throughout the implementation, there are several places where data returned
by the underlying CA library needs to be be converted to Python data. This
is encapsulated in the :func:`_unpack` function. In general, you will not
have to run this code, but there is one exception: when using
:func:`sg_get`, the values returned will have to be unpacked with this
function.
.. autofunction:: _unpack(chid, data[, count=None[, ftype=None[, as_numpy=None]]])
.. _ca-callbacks-label:
User-supplied Callback functions
================================
User-supplied callback functions can be provided for :func:`put`,
:func:`replace_access_rights_event`, and :func:`create_subscription`.
Note that callbacks for `PV` objects are slightly different: see
:ref:`pv-callbacks-label` in the :mod:`pv` module for details.
When defining a callback function to be run either when a :func:`put` completes
or on changes to the Channel, as set from :func:`create_subscription`, or when
read/write permissions change from :func:`replace_access_rights_event`, it is
important to know two things:
1) how your function will be called.
2) what is permissible to do inside your callback function.
Callbacks will be called with keyword arguments for :func:`put` and for
:func:`create_subscription`. You should be prepared to have them passed to
your function. Use `**kw` unless you are very sure of what will be sent.
For the case of :func:`replace_access_rights_event`, only positional arguments
will be passed.
For callbacks sent when a :func:`put` completes, your function will be passed these:
* `pvname` : the name of the pv
* `data`: the user-supplied callback_data (defaulting to ``None``).
For subscription callbacks, your function will be called with keyword/value
pairs that will include:
* `pvname`: the name of the pv
* `value`: the latest value
* `count`: the number of data elements
* `ftype`: the numerical CA type indicating the data type
* `status`: the status of the PV (1 for OK)
* `chid`: the integer address for the channel ID.
For access rights event callbacks, your function will be passed:
* `read_access`: boolean indicating read access status
* `write_access`: boolean indicating write access status
Depending on the data type, and whether the CTRL or TIME variant was used,
the callback function may also include some of these as keyword arguments:
* `enum_strs`: the list of enumeration strings
* `precision`: number of decimal places of precision.
* `units`: string for PV units
* `severity`: PV severity
* `timestamp`: timestamp from CA server.
* `posixseconds`: integer seconds since POSIX epoch of timestamp from CA server.
* `nanoseconds`: integer nanoseconds of timestamp from CA server.
Note that a the user-supplied callback will be run *inside* a CA function,
and cannot reliably make any other CA calls. It is helpful to think "this
all happens inside of a :func:`pend_event` call", and in an epics thread
that may or may not be the main thread of your program. It is advisable to
keep the callback functions short and not resource-intensive. Consider
strategies which use the callback only to record that a change has occurred
and then act on that change later -- perhaps in a separate thread, perhaps
after :func:`pend_event` has completed.
.. _ca-omissions-label:
Omissions
=========
Several parts of the CA library are not implemented in the Python module.
These are currently seen as unneeded (with notes where appropriate for
alternatives), though they could be added on request.
.. function:: ca_add_exception_event
*Not implemented*: Python exceptions are raised where appropriate and
can be used in user code.
.. function:: ca_add_fd_registration
*Not implemented*
.. function:: ca_client_status
*Not implemented*
.. function:: ca_set_puser
*Not implemented* : it is easy to pass user-defined data to callbacks as needed.
.. function:: ca_puser
*Not implemented*: it is easy to pass user-defined data to callbacks as needed.
.. function:: ca_SEVCHK
*Not implemented*: the Python function :func:`PySEVCHK` is
approximately the same.
.. function:: ca_signal
*Not implemented*: the Python function :func:`PySEVCHK` is
approximately the same.
.. function:: ca_test_event
*Not implemented*: this appears to be a function for debugging events.
These are easy enough to simulate by directly calling Python callback
functions.
.. function:: ca_dump_dbr
*Not implemented*
In addition, not all `DBR` types in the CA C library are supported.
Only native types and their DBR_TIME and DBR_CTRL variants are supported:
DBR_STS and DBR_GR variants are not. Several `dbr_XXX` functions are also
not supported, as they are needed only to dynamically allocate memory.
:class:`CAThread` class
==========================
.. class:: CAThread(group=None[, target=None[, name=None[, args=()[, kwargs={}]]]])
create a CA-aware subclass of a standard Python :class:`threading.Thread`. See the
standard library documentation for further information on how to use Thread objects.
A `CAThread` simply runs :func:`use_initial_context` prior to running each target
function, so that :func:`use_initial_context` does not have to be explicitly put inside
the target function.
The See :ref:`advanced-threads-label` for further discussion.
Examples
=========
Here are some example sessions using the :mod:`ca` module.
Create, Connect, Get Value of Channel
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Note here that several things have been simplified compare to using CA in C:
initialization and creating a main-thread context are handled, and connection
of channels is handled in the background::
from epics import ca
chid = ca.create_channel('XXX:m1.VAL')
count = ca.element_count(chid)
ftype = ca.field_type(chid)
print "Channel ", chid, count, ftype
value = ca.get()
print value
Put, waiting for completion
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Here we set a PVs value, waiting for it to complete::
from epics import ca
chid = ca.create_channel('XXX:m1.VAL')
ca.put(chid, 1.0, wait=True)
The :func:`put` method will wait to return until the processing is
complete.
Define a callback to Subscribe to Changes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Here, we *subscribe to changes* for a PV, which is to say we define a
callback function to be called whenever the PV value changes. In the case
below, the function to be called will simply write the latest value out to
standard output::
from epics import ca
import time
import sys
# define a callback function. Note that this should
# expect certain keyword arguments, including 'pvname' and 'value'
def onChanges(pvname=None, value=None, **kw):
fmt = 'New Value: %s value=%s, kw=%s\n'
sys.stdout.write(fmt % (pvname, str(value), repr(kw)))
sys.stdout.flush()
# create the channel
mypv = 'XXX.VAL'
chid = ca.create_channel(mypv)
# subscribe to events giving a callback function
eventID = ca.create_subscription(chid, callback=onChanges)
# now we simply wait for changes
t0 = time.time()
while time.time()-t0 < 10.0:
time.sleep(0.001)
It is **vital** that the return value from :func:`create_subscription` is
kept in a variable so that it cannot be garbage collected. Failure to keep
this value will cause trouble, including almost immediate segmentation
faults (on Windows) or seemingly inexplicable crashes later (on linux).
Define a connection callback
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Here, we define a connection callback -- a function to be called when the
connection status of the PV changes. Note that this will be called on
initial connection::
import epics
import time
def onConnectionChange(pvname=None, conn=None, chid=None):
print 'ca connection status changed: ', pvname, conn, chid
# create channel, provide connection callback
motor1 = '13IDC:m1'
chid = epics.ca.create_channel(motor1, callback=onConnectionChange)
print 'Now waiting, watching values and connection changes:'
t0 = time.time()
while time.time()-t0 < 30:
time.sleep(0.001)
This will run the supplied callback soon after the channel has been
created, when a successful connection has been made. Note that the
callback should be prepared to accept keyword arguments of `pvname`,
`chid`, and `conn` for the PV name, channel ID, and connection state
(``True`` or ``False``).
Define an access rights change event callback
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The following example demonstrates the addition of a function to be
called when the access rights of a channel changes. Note this will be
called immediately after successful installation::
import epics
import time
def on_access_rights_change(read_access, write_access):
print 'read access = %s, write access = %s' % (read_access, write_access)
# create a channel and attach the above function for access rights events
chid = epics.ca.create_channel('pv_name')
# a message should be printed immediately following this registration
epics.ca.replace_access_rights_event(chid, callback=on_access_rights_change)
# Affecting the channel's access rights, (for example, by enabling/disabling
# CA Security rules), should produce additional console messages
try:
while True:
time.sleep(0.25)
except KeyboardInterrupt:
pass
|