560 likes | 763 Views
Channel Access Client Programming in C. Advanced EPICS Training (This is going to be hard!). Contents. What is Channel Access? About channels Channel Access data types Connecting Reading Monitoring Writing Channel Access Security Channel Access details. What is Channel Access?.
E N D
Channel Access Client Programming in C Advanced EPICS Training (This is going to be hard!)
Contents • What is Channel Access? • About channels • Channel Access data types • Connecting • Reading • Monitoring • Writing • Channel Access Security • Channel Access details Advanced EPICS Training, Dirk Zimoch 2007
What is Channel Access? • The EPICS network protocol • Based on UDP and TCP, default ports 5064 and 5065 • Provides reading, writing and monitoring values • Typical Channel Access servers are • EPICS IOCs • Channel Access Gateways • Typical Channel Access clients are • EPICS IOCs • medm • caget Advanced EPICS Training, Dirk Zimoch 2007
Vocabulary • Record: The building blocks of EPICS IOCs holding data. • Field: Part of a record, e.g. VAL=value, EGU=units • A field is one atomic piece of data, e.g. a number or a string • A record consists of many fields, VAL is only the "default" field. • PV (Process Variable): A piece of data with attributes • It usually gets the value from a record field, often the VAL field. • The attributes may come from other fields. • You always work with local copies of remote PVs. • Channel: The connection to a remote PV on a server Often "record", "PV", and "channel" are mixed up. Advanced EPICS Training, Dirk Zimoch 2007
The CA view to the world • CA connects to remote PVs, not to records or fields. • CA does not know about records or record types. • CA only knows about data types. Example: • caget ARIDI-PCT:CURRENT tries to read a PV • The IOC ARIDI-VME-PCT has an ai record with that name • The IOC returns the VAL field of that record to the client • The client gets a copy of a DOUBLE PV • caget ARIDI-PCT:CURRENT.VAL gets the same value Advanced EPICS Training, Dirk Zimoch 2007
About channels • A channel connects to a remote PV by name. • PV names must be unique within the network. • ca_create_channel() assigns a channel ID to a PV name and allocates necessary resources (memory). • Channel IDs are unique within the program • A channel starts disconnected. • Only after connection, data can be transferred. • Reading: ca_get() • Writing: ca_put() • Monitoring: ca_create_subscription() Advanced EPICS Training, Dirk Zimoch 2007
Channel status • Get the connection status • ca_state(channel) returns: • cs_never_conn before 1st connection or when PV is not found • cs_conn after connection, when channel can be used • cs_prev_conn after disconnect, e.g. server shut down • cs_closed after ca_clear_channel() • Close a channel and free resources • ca_clear_channel(channel) • also uninstalls all handlers (callbacks) for channel • can be called before client exits for clean shutdown Advanced EPICS Training, Dirk Zimoch 2007
Other channel information • Read back the PV name which is connected to the channel • ca_name(channel) • Get the native data type of the channel (the remote PV) • ca_field_type(channel) • available after connection • returns TYPENOTCONN if the channel is not connected • Get number of elements or array PVs • ca_element_count(channel) • available after connection • returns 1 for scalar PVs Advanced EPICS Training, Dirk Zimoch 2007
Channel Access data types • 7 basic fundamental data base field types: • DBF_STRING: a string of max 40 characters (incl null-byte) • DBF_CHAR: one unsigned byte • DBF_SHORT: signed 16 bit integer, alias DBF_INT • DBF_LONG: signed 32 bit integer • DBF_ENUM: one of up to 16 predefined strings • DBF_FLOAT: 32 bit floating point • DBF_DOUBLE: 64 bit floating point • 1 dimensional arrays of fundamental types • "annotated" types with meta-data for local PVs Advanced EPICS Training, Dirk Zimoch 2007
Annotated CA data types (with meta-data) • 5 flavours (detail levels) of data base request types • DBR_*: The naked DBF_* value • DBR_STS_*: value + status + severity • DBR_TIME_*: value + status + severity + (time-) stamp • DBR_GR_*: value + status + severity + display infos • DBR_CTRL_*: value + status + severity + control infos • The local copy of a PV always uses one of the DBR types Note: • Control infos supersede display infos • DBR_GR_* and DBR_CTRL_* don't inclue timestamps Advanced EPICS Training, Dirk Zimoch 2007
Display and control infos for integers Note: • If the PV is the VAL field of a record, the info maps to other fields. • Numeric infos have the same data type as the value. • Display info • units (string max 8 chars incl null-byte) (EGU) • upper_disp_limit and lower_disp_limit (HOPR and LOPR) • upper_warning_limit and lower_warning_limit (HIGH and LOW) • upper_alarm_limit and lower_alarm_limit (HIHI and LOLO) • Control info (in addition to display info) • upper_ctrl_limit and lower_ctrl_limit (DRVH and DRVL) Advanced EPICS Training, Dirk Zimoch 2007
Display and control info for floating point • Display info • Everything integer display info has but with floating point data type • precision (short integer) • It is not really defined, what e.g. precision=3 means. • digits after decimal point like in %.3f (e.g. 12345.678) • total valid digits like in %.3g (e.g. 1.23e+04) • digits after decimal point in exponential notation like in %.3e (e.g. 1.235e+04) • It is not defined what precision<0 means. • Control info (in addition to display info) • Like integer control info but with floating point format Advanced EPICS Training, Dirk Zimoch 2007
Display and control info for enums Note: • Value is an index (unsigned short integer) to a string list. • Display info • no_str (short integer) number of defined strings • strs (16 strings of max 26 chars incl null-byte) • Control info • Same as display info Note: • Enums have no units and no limit infos. • Be careful with string conversion when value >= no_str. Advanced EPICS Training, Dirk Zimoch 2007
When to use which detail level • To read static information once after the channel connected • Use DBR_CTRL_* if you plan to write to the channel. • You may use DBR_GR_* if you only want to read the channel. • If in doubt, use DBR_CTRL_* always. • To read or monitor dynamic (changing) values • Use DBR_TIME_*. • The naked value might be invalid or old without notice! • To write values • use the naked DBR_*. • I know no use for DBR_STS_* (and DBR_GR_*) Advanced EPICS Training, Dirk Zimoch 2007
Caveats • There is no signed char type. • There are no unsigned short or long types. PVs of those types will be converted to a sufficiently large type on the server: • unsigned short → DBF_LONG • unsigned long → DBF_DOUBLE • There are no 64 bit integers. • Strings are limited to 40 bytes, but arrays of char can be used. • There are no user-defined structures. • There are no multi-dimensional arrays. • Arrays have constant length (while connected) Advanced EPICS Training, Dirk Zimoch 2007
Converting DBF types to DBR types • A channel has a native DBF type. • This is the data type of the value of the remote PV. • ca_field_type(channel) returns the native DBF_* type • Reading and writing requires a DBR type. • This is the type and detail level of the local copy of the PV. • It is possible to do automatic conversion (on the server), e.g. read a DBF_SHORT PV as DBR_STRING or DBR_DOUBLE. • It is more efficient to use use a matching DBR type. • CA provides conversion macros to find matching DBR types: • dbf_type_to_DBR_CTRL(field_type) and similar Advanced EPICS Training, Dirk Zimoch 2007
Mapping of CA types to C types • DBR_* and DBF_* are macros for code numbers used in channel access functions. • Each DBR_<XXX>_<TYPE> code has a corresponding C data type: struct dbr_<xxx>_<type> (all lowercase letters) • These structures should be used for the local copies of PVs. • There are no dbr_gr_string or dbr_ctrl_string types. • Codes and structures are defined in db_access.h • Channel Access provides a macro to calculate the required amount of memory for a PV (also for arrays). • dbr_size_n(DBR_type, element_count) Advanced EPICS Training, Dirk Zimoch 2007
Creating a channel • A channel starts disconnected and without network traffic • ca_create_channel(name, connhandler, user, prio, pchannel) • name PV name (const char*) to conenct to • connhandler handler function to be called on connection change can be NULL • user arbitrary user data (void*) associated with channel • prio priority on server, 0 lowest, 99 highest CA_PRIORITY_DEFAULT=0 CA_PRIORITY_ARCHIVE=20 • pchannel pointer to channel ID to be filled in (chid*) • First create all needed channels before connecting them. • Connecting is an expensive operation. Advanced EPICS Training, Dirk Zimoch 2007
Connecting channels • Channels without connection handler • ca_pend_io(timeoutSec) sends pending requests and waits. • Returns early with ECA_NORMAL after all channels connected. • Returns after timeoutSec with ECA_TIMEOUT. • Check all channels with ca_state(channel) to find not connected channels. • Channels with connection handler • ca_flush_io() sends pending requests and returns immediately. • ca_pend_io(timeoutSec) would also return immediately. • Whenever a channel (dis-/re-)connects, its handler is called. • All connect requests are processed in parallel. Advanced EPICS Training, Dirk Zimoch 2007
Wait or call back? • When to wait for connections • Command line tools • Simple linear programs • Short lived programs • When to use connection handlers • Graphical user interfaces • Servers • Event driven programs • Long lived programs • Always Advanced EPICS Training, Dirk Zimoch 2007
Connection handling • Disconnecting and reconnecting are normal. • In a distributed system, remote IOCs may be rebooted at any time. • This should never put the client in an undefined state. • Late connecting is normal. • The IOC may be started after the client. • This is handled automatically by Channel Access. • Write a connection handler to perform action on (dis-)connection. • void handler(struct connection_handler_args args) • args.chid channel id • args.opCA_OP_CONN_UP or CA_OP_CONN_DOWN Advanced EPICS Training, Dirk Zimoch 2007
What to avoid • Do not call ca_pend_io() or ca_flush_io() separately for each channel. • When writing PV wrappers, do not connect in the constructor! • When building a GUI, do not connect each widget separately! • When processing a list of PVs, do not connect each PV separately! • First create all PVs, widgets, etc. then connect in parallel. • Do not call ca_create_channel() twice for the same PV. • When a channel disconnects, do not call ca_create_channel() again! • When a connect times out, do not call ca_create_channel() again! • Use connection handlers instead of timeouts. Advanced EPICS Training, Dirk Zimoch 2007
Providing buffer space • Use ca_field_type(channel) for native field type. • Use dbf_type_to_DBR_*(field_type) for matching DBR type. • Choose the appropriate DBR_* type for your application. • Use ca_element_count(channel) for array length. • Use dbr_size_n(dbr_type, elements) for required size. • Allocate buffer memory. malloc(dbr_size_n(dbf_type_to_DBR_TIME(ca_field_type(channel))), ca_element_count(channel)) • Or choose a DBR type manually and let the server convert • This increases the load on the server. Advanced EPICS Training, Dirk Zimoch 2007
Reading channels • Prepare a read request • ca_array_get(dbr_type, elements, channel, buffer) • dbr_type requested data type (should match buffer size) • elements maximum array size to read (may be smaller than native size) • channel channel ID • buffer pointer to buffer (min dbr_size_n(dbr_type, elements) bytes long) • ca_get(dbr_type, channel, buffer) • Same as above with elements=1 • Send request and wait for reply • ca_pend_io(timeoutSec) Advanced EPICS Training, Dirk Zimoch 2007
Increasing read performance • If possible, do many ca_get() with one ca_pend_io() • Requests are sent in parallel. • Timeout for replies runs in parallel. • Problem: Error detection • ca_pend_io() returns ECA_TIMEOUT when any get fails. • No way to find out which get failed. • Caution: ca_pend_io() delays the program. • GUIs, servers and other event driven programs should block. • Better use callbacks. Advanced EPICS Training, Dirk Zimoch 2007
Reading with callbacks • Prepeare read request • ca_array_get_callback(dbr_type, elements, channel, callback, usr) • dbr_type, elements, channel as in ca_array_get() • callback function to be called when data arrives • usr arbitrary user argument to callback function • No need to provide buffer! • ca_get_callback(dbr_type, channel, callback, arg) • Send read requests and continue • ca_flush_io() • If possible, do many ca_get_callback() with one ca_flush_io() Advanced EPICS Training, Dirk Zimoch 2007
Receiving read callbacks • Write a callback function • void readCallback(struct event_handler_args args) • args.usr user data from ca_get_callback() call • args.chid channel ID • args.type DBR type of data • args.count number of elements in array (1 for scalars) • args.dbr pointer to data buffer (void*) • args.status a ECA_* status code for the operation, e.g. ECA_SUCCESS • Copy the data from *dbr to your private buffer. • You have to implement timeouts yourself, if required. • ca_pend_io(timeoutSec) does not wait for get with callback! Advanced EPICS Training, Dirk Zimoch 2007
What can go wrong while reading • The channel is disconnected • ca_get then returns ECA_DISCONN • This can happen at any time, even if a previous call to ca_state(channel) returned cs_connected. • IOCs may be rebooted. • Network may be overloaded. • The server does not reply in time • ca_pend_io(timeoutSec) times out. • The server may be too busy. • The network latency may be too high. Advanced EPICS Training, Dirk Zimoch 2007
What else can go wrong • PV is not readable • CA security on the server forbits reading. • The PV has no readable data type (DBF_NOACCESS). • The PV cannot be converted to the requested DBR type. • Invalid parameters • invalid (e.g. closed) channel ID • invalid DBR type code • requested elements larger than PV array size • Out of memory • Check return value of all ca_* functions! Advanced EPICS Training, Dirk Zimoch 2007
Exercise 1 (2 hours) • Write a simple program that connects to a remote PV (e.g. a record on an IOC), reads the value and prints it. • CA functions: #include <cadef.h> • CA datatypes: see db_access.h • status and severity: see alarm.h • Format the value nicely (precision, units, alarms). • Read more than one value efficiently. • Read the values repeatedly. • What if a PV does not exit or disconnects (when IOC reboots)? • What if you request a “wrong” DBR type? Advanced EPICS Training, Dirk Zimoch 2007
Contexts, threads and callbacks • Multi-threaded context • ca_context_create(ca_enable_preemtive_callbacks) • Callbacks may be called at any time except during other callbacks. • You need to know how to use mutex semaphores. • Single-threaded context • ca_context_create(ca_disable_preemtive_callbacks) • Is created automatically when ca_* functions are used without context. • Callbacks are only called from within a ca_* function. • The program must call ca_pend_io(), ca_flush_io(), ca_pend_event() or ca_poll() regularly to receive any data (e.g. in event/idle loop). Advanced EPICS Training, Dirk Zimoch 2007
Doing network traffic in single-theaded context • Four functions send pending output and wait for input • ca_pend_io(timeoutSec) send, wait until get and connect requests without callback complete • ca_pend_event(waitSec) send, wait for input, does not return before waitSec are over • ca_poll() send, handle only pending input, does not wait for more input • ca_flush_io() send, don’t process input • Output is also sent when output buffers are full. • For efficiency send as much output as possible together. Advanced EPICS Training, Dirk Zimoch 2007
Doing network traffic in multi-threaded context • The single-threaded networking functions can be used to force sending output and to wait. • Output may also be sent at any other time. • Most probably when all threads are idle (waiting for something) • Input may be received at any time. • There is no need to call ca_pend_io() and friends. • Don't forget to protect your data with mutex semaphores! • A callback may modify your local PV copy while you are accessing it! Advanced EPICS Training, Dirk Zimoch 2007
Monitoring cannels • Subscribe for monitor events • ca_create_subscription(dbr_type, elements, channel, eventmask, callback, usr, pmonid) • dbr_type, elements, channel, callback and usr are the same as in ca_array_get_callback() • eventmask combination of bits DBE_VALUE, DBE_LOG, DBE_ALARM Normally use DBE_VALUE| DBE_ALARM. • pmonid pointer to monitor ID, needed to delete monitor (evid*) • The same callback as for ca_array_get_callack() may be used. • Send monitor requests, e.g with ca_flush_io(). • Monitors will come whenever value or alarm status changes. Advanced EPICS Training, Dirk Zimoch 2007
Using monitors efficiently • First create all subscriptions before sending them • Do not call ca_flush_io() after every single ca_create_subscription() • Especially when writing wrappers, classes, GUIs, make sure that not every single monitor request is sent individually. • Separate static and dynamic data • Read large DBR_CTRL_* only once after connection with ca_get(). • Can be done in connection handler. • Don’t read arrays here. • Subscribe for small DBR_TIME_* types. • Prefer monitors to ca_get() polling. Advanced EPICS Training, Dirk Zimoch 2007
Monitor or get? • When to use get • When a value is read only once. • When a value must be read at a specific time. • To take a snapshot (e.g. save a setup). • In short lived programs (command line tools). • When to use monitors • Whenever a PV changes frequently. • When short pulses (off-on-off) should not be missed. • In GUIs, servers, other long lived programs. • Always. Advanced EPICS Training, Dirk Zimoch 2007
Waiting for PV changes ("done"-flags, etc) • Use monitors instead of repeated gets (polling) • Polling can miss short pulses (e.g. off-on-off) • Polling wastes network bandwidth and server (IOC) resources. • Simple single-threaded solution • Monitor callback updates value • Loop over ca_pend_even(0.1) and check value. • Sophisticated multi-threaded solution • Monitor callback updates and checks value and triggers event semaphore. • Wait for event semaphore. Advanced EPICS Training, Dirk Zimoch 2007
Caveats • Monitors trigger only at significant value changes. • The server decides what is significant. • Some servers don’t support monitors on all PVs. • You will not be informed when they change. • No monitor is sent when meta-data change (e.g. limits change) • This usually happen only on restart of the server. • Update meta-data in connection handler. • A monitor may miss intermediate values during rapid changes. • Happens when client or network are too slow. • But: It always gets the first and the last change. Advanced EPICS Training, Dirk Zimoch 2007
What is forbidden in a monitor callback • You must not call ca_pend_io() or similar in callbacks. • Re-entrancy problem: callbacks are called from ca_pend_io(). • That means you can’t read via ca_get() from within a callback. • Workaround: Trigger (non-EPICS) event handler from callback that performs the ca_get(). • Or use monitors for everything. • You must not block inside a callback. • Only one callback runs at a time. • Blocking delays all other callbacks (get, monitor, connect, …) Advanced EPICS Training, Dirk Zimoch 2007
Writing channels • Prepare write request • ca_array_put(type, elements, channel, pvalue) • type use a naked DBR_* type, if type does not match native DBF type, the value is converted on the server. • elements number of array elements to write, 1 for scalar values • channel the channel id • pvalue a pointer to the data to send • ca_put(type, channel, pvalue) • Same as above with elements=1 • Send write request, e.g. with ca_flush_io() • Send as many PVs as possible together. Advanced EPICS Training, Dirk Zimoch 2007
Caveats • ca_put()/ca_flush_io() only sends data to the network layer. • It does not wait until … • actions on the server have been performed. • actions on the server have even been started. • the value has actually been written on the network cable. • It just promises that the current value will be sent in the near future unless the channel disconnects. • Intermediate values may be lost when values change rapidly. • When server or network is slow. • But: First and last value are always written Advanced EPICS Training, Dirk Zimoch 2007
Synchronous put • Create a synchonous group • ca_sg_create(pgroup) • pgroup pointer to a group ID to be filled in (CA_SYNC_GID*) • Perform one or more puts inside synchonous group • ca_sg_array_put(group, type, elements, channel, pvalue) • group group ID • Wait until all puts in the same group have completed • ca_sg_block(group, timeoutSec) • Delete group • ca_sg_delete(group) Advanced EPICS Training, Dirk Zimoch 2007
Synchronous put remarks • Creating and deleting synchronous groups is cheap. • Create and delete them on demand. • No need to store them somewhere globally. • The execution order inside a group is undefined. • Use separate groups and ca_sg_block() when oder matters. • If one put inside a group fails and ca_sg_block() times out, there is no way to find out which one failed. • The program is delayed while blocking • This may be inappropriate for (single-threaded) GUIs and servers • This is what you probably need for scripts. Advanced EPICS Training, Dirk Zimoch 2007
Synchronous put versus asynchronous put • When to use synchronous puts • When time order matters. • First write parameters then write "start". • First write "start", then check "done". • When successful execution must be checked. • First write then read back and check severity. • When intermediate values must not be lost (sequence) • When to use asynchronous puts • When blocking is not allowed (e.g. GUI, server). • When many intermediate values are written (e.g. slider). Advanced EPICS Training, Dirk Zimoch 2007
Put with callback • Prepare write request • ca_array_put_callback(type, elements, channel, pvalue, callback, usr) • type, elements, channel, pvalue are the same as for ca_array_put() • callback a function that is called when the put has completed on the server • usr arbitrary user data to be passed to callback function (void*) • Send write request(s) • ca_flush_io() • Receive callback • Callback function has the same form as a get callback. • In single-threaded model call ca_pend_event() or similar regularly. Advanced EPICS Training, Dirk Zimoch 2007
Put with callback versus synchronous put • Put with callback does not delay the program. • You can still use event semaphores to wait for callbacks. • Response is channel specific. • You can wait for feedback in parallel but still on individual channels. • Synchronous groups only work on a per group basis and only one group after the other. • Programming effort is higher. • Callbacks, semaphores, timeouts must be implemented. • Use put with callback for GUIs and servers. • Use synchronous put for command line tools and scripts. Advanced EPICS Training, Dirk Zimoch 2007
Exiting the program • Destroy the Channel Access context • ca_context_destroy() • This should be the first thing to do before any resources are freed. • All pending output is sent on the network. • All handlers / callbacks are disabled. • For multi-threaded clients it is important to clean up. • Avoids crash on exit, e.g when callbacks access buffers which are already deleted by another thread. Advanced EPICS Training, Dirk Zimoch 2007
Exercise 2 • Modify the polling program from Exercise 1 to use monitors. • Wait without polling until a PV fulfills a condition. • Write 2 other programs that set 1000 different values with asynchonous put and with synchonous put. Verify with your monitoring program what happens to the PV. • Write a program that sets a value from user input and checks the written value for consistency and alarms. • Try PVs with different data types (floating point, string) Advanced EPICS Training, Dirk Zimoch 2007
Channel Access Security • Remote PVs can be readonly or even unreadable. • CA provides functions to check access • ca_read_access(channel) returns 1 if readable • ca_write_access(channel) returns 1 if writable • CA provides a handler when access rights change • ca_replace_access_rights_event(channel, handler) • handler user supplied callback function • void accessHandler (struct access_rights_handler_args args) • args.chid channel ID • args.caar.read_access 1 if readable, 0 if not • args.caar.write_access 1 if writable, 0 if not Advanced EPICS Training, Dirk Zimoch 2007
Channel Access details: Searching PVs • A client sends UDP packages to find PVs • Requests are repeated with decreasing rate until all PVs are found or 100 requests have been sent (after approx. 8 minutes) • Unresolved requests are re-issued when a new server starts. • E.g. when an IOC boots. • Default is to broadcast on all local network interfaces. • This is an expensive action. • All servers on the network have to check their list of PVs. • Many requests can be put into one package for efficiency. Advanced EPICS Training, Dirk Zimoch 2007