diff --git a/documentation/Makefile b/documentation/Makefile index 8f509757c..ee7ff29a4 100644 --- a/documentation/Makefile +++ b/documentation/Makefile @@ -65,6 +65,11 @@ libcom_HEADERS += yajl_common libcom_HEADERS += yajl_gen libcom_HEADERS += yajl_parse +ca_HEADERS += cadef +ca_HEADERS += caerr +ca_HEADERS += caeventmask +ca_HEADERS += db_access + database_HEADERS += chfPlugin database_HEADERS += dbChannel database_HEADERS += dbCommon @@ -128,7 +133,7 @@ menu_HEADERS += menuScan menu_HEADERS += menuSimm menu_HEADERS += menuYesNo -HEADER_TYPES = libcom database record menu +HEADER_TYPES = libcom ca database record menu HEADER_MD_FILES = $(foreach t, $(HEADER_TYPES), \ $(addsuffix _h.md, $($t_HEADERS))) diff --git a/documentation/ca-API.rst b/documentation/ca-API.rst new file mode 100644 index 000000000..0f24288d3 --- /dev/null +++ b/documentation/ca-API.rst @@ -0,0 +1,7 @@ +Channel Access C/C++ APIs +========================= + +.. toctree:: + :maxdepth: 1 + :caption: CA Header Files + diff --git a/documentation/index.rst b/documentation/index.rst index 9f7ebfa35..0bed60cc3 100644 --- a/documentation/index.rst +++ b/documentation/index.rst @@ -25,6 +25,7 @@ EPICS Base Documentation :caption: C/C++ Headers libcom-api + ca-api database-api record-api menu-api diff --git a/modules/ca/src/client/cadef.h b/modules/ca/src/client/cadef.h index 12861c384..32de6a8fe 100644 --- a/modules/ca/src/client/cadef.h +++ b/modules/ca/src/client/cadef.h @@ -7,6 +7,7 @@ * EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. \*************************************************************************/ + /* * * L O S A L A M O S @@ -21,6 +22,11 @@ * */ +/** \file cadef.h + * + * \brief Channel Access library. + */ + #ifndef INC_cadef_H #define INC_cadef_H @@ -43,29 +49,34 @@ extern "C" { #endif +/** \brief Channel identifier. */ typedef struct oldChannelNotify *chid; +/** \brief Channel identifier. */ typedef chid chanId; /* for when the structures field name is "chid" */ typedef long chtype; typedef struct oldSubscription *evid; typedef double ca_real; -/* arguments passed to user connection handlers */ +/** \brief Arguments passed to user connection handlers. */ struct connection_handler_args { - chanId chid; /* channel id */ - long op; /* one of CA_OP_CONN_UP or CA_OP_CONN_DOWN */ + chanId chid; /**< channel id */ + long op; /**< one of ::CA_OP_CONN_UP or ::CA_OP_CONN_DOWN */ }; typedef void caCh (struct connection_handler_args args); +/** \brief Access rights. + */ typedef struct ca_access_rights { - unsigned read_access:1; - unsigned write_access:1; + unsigned read_access:1; /**< Read access. */ + unsigned write_access:1; /**< Write access. */ } caar; -/* arguments passed to user access rights handlers */ +/** \brief Arguments passed to user access rights handlers + */ struct access_rights_handler_args { - chanId chid; /* channel id */ - caar ar; /* new access rights state */ + chanId chid; /**< Channel id. */ + caar ar; /**< New access rights state. */ }; typedef void caArh (struct access_rights_handler_args args); @@ -73,8 +84,7 @@ typedef void caArh (struct access_rights_handler_args args); /* The conversion routine to call for each type */ #define VALID_TYPE(TYPE) (((unsigned short)TYPE)<=LAST_BUFFER_TYPE) -/* - * Arguments passed to event handlers and get/put call back handlers. +/** \brief Arguments passed to event handlers and get/put call back handlers. * * The status field below is the CA ECA_XXX status of the requested * operation which is saved from when the operation was attempted in the @@ -83,32 +93,46 @@ typedef void caArh (struct access_rights_handler_args args); * and the requested operation can not be assumed to be successful. */ typedef struct event_handler_args { - void *usr; /* user argument supplied with request */ - chanId chid; /* channel id */ - long type; /* the type of the item returned */ - long count; /* the element count of the item returned */ - const void *dbr; /* a pointer to the item returned */ - int status; /* ECA_XXX status of the requested op from the server */ + void *usr; /**< User argument supplied with request. */ + chanId chid; /**< Channel id. */ + long type; /**< The type of the item returned. */ + long count; /**< The element count of the item returned. */ + const void *dbr; /**< A pointer to the item returned. */ + int status; /**< `ECA_XXXX` status of the requested op from the server. */ } evargs; typedef void caEventCallBackFunc (struct event_handler_args); +/** \brief A built-in subscription update callback handler + * for debugging purposes that prints diagnostics to standard out. + * + * # Examples + * + * ```c + * void ca_test_event (); + * status = ca_create_subscription ( type, chid, ca_test_event, NULL, NULL ); + * SEVCHK ( status, .... ); + * ``` + * + * \sa ca_create_subscription() + */ LIBCA_API void epicsStdCall ca_test_event ( struct event_handler_args ); -/* arguments passed to user exception handlers */ +/** \brief Arguments passed to user exception handlers. + */ struct exception_handler_args { - void *usr; /* user argument supplied when installed */ - chanId chid; /* channel id (may be nill) */ - long type; /* type requested */ - long count; /* count requested */ - void *addr; /* user's address to write results of CA_OP_GET */ - long stat; /* channel access ECA_XXXX status code */ - long op; /* CA_OP_GET, CA_OP_PUT, ..., CA_OP_OTHER */ - const char *ctx; /* a character string containing context info */ - const char *pFile; /* source file name (may be NULL) */ - unsigned lineNo; /* source file line number (may be zero) */ + void *usr; /**< User argument supplied when installed */ + chanId chid; /**< Channel id (may be null) */ + long type; /**< Type requested */ + long count; /**< Count requested */ + void *addr; /**< User's address to write results of ::CA_OP_GET */ + long stat; /**< Channel access ECA_XXXX status code */ + long op; /**< ::CA_OP_GET, ::CA_OP_PUT, ..., ::CA_OP_OTHER */ + const char *ctx; /**< A character string containing context info */ + const char *pFile; /**< Source file name (may be NULL) */ + unsigned lineNo; /**< Source file line number (may be zero) */ }; typedef unsigned CA_SYNC_GID; @@ -116,24 +140,54 @@ typedef unsigned CA_SYNC_GID; /* * External OP codes for CA operations */ + +/** \brief GET Channel Access operation. */ #define CA_OP_GET 0 +/** \brief PUT Channel Access operation. */ #define CA_OP_PUT 1 +/** \brief CREATE_CHANNEL Channel Access operation. */ #define CA_OP_CREATE_CHANNEL 2 +/** \brief ADD_EVENT Channel Access operation. */ #define CA_OP_ADD_EVENT 3 +/** \brief CLEAR_EVENT Channel Access operation. */ #define CA_OP_CLEAR_EVENT 4 +/** \brief Other Channel Access operation. */ #define CA_OP_OTHER 5 -/* - * used with connection_handler_args +/** \brief Connection up Channel Access operation. + * + * Used with connection_handler_args */ #define CA_OP_CONN_UP 6 + +/** \brief Connection down Channel Access operation. + * + * Used with connection_handler_args + */ #define CA_OP_CONN_DOWN 7 -/* deprecated */ +/** \brief SEARCH Channel Access operation. + * + * \deprecated + */ #define CA_OP_SEARCH 2 -/* - * provides efficient test and display of channel access errors +/** \brief Provides efficient test and display of channel access errors. + * + * SEVCHK() is a macro envelope around ca_signal() which only calls + * ca_signal() if the supplied error code indicates an unsuccessful + * operation. SEVCHK() is the recommended error handler for simple applications + * which do not wish to write code testing the status returned from each + * channel access call. + * + * # Examples + * + * ```c + * status = ca_context_create (...); + * SEVCHK ( status, "Unable to create a CA client context" ); + * ``` + * + * \sa ca_signal(). */ #define SEVCHK(CA_ERROR_CODE, MESSAGE_STRING) \ { \ @@ -146,25 +200,85 @@ typedef unsigned CA_SYNC_GID; __LINE__); \ } +/** \brief The channel's native type when disconnected. */ +#define TYPENOTCONN (-1) -#define TYPENOTCONN (-1) /* the channel's native type when disconnected */ +/** \brief Return the native type in the server of the process variable. + * + * \param[in] chan Channel identifier. + * \returns The data type code will be a member of the set of `DBF_XXXX` in `db_access.h`. + * The constant TYPENOTCONN is returned if the channel is disconnected. + */ LIBCA_API short epicsStdCall ca_field_type (chid chan); + +/** \brief Return the maximum array element count in the server for the specified IO channel. + * + * \param[in] chan Channel identifier. + * \returns The maximum array element count in the server. + * An element count of zero is returned if the channel is disconnected. + */ LIBCA_API unsigned long epicsStdCall ca_element_count (chid chan); + +/** \brief Return the name provided when the supplied channel id was created. + * + * \param[in] chan Channel identifier. + * \returns The channel name. + * The string returned is valid as long as the channel specified exists. + */ LIBCA_API const char * epicsStdCall ca_name (chid chan); + +/** \brief Set a user private void pointer variable retained + * with each channel for use at the users discretion. + * + * \param[in] chan Channel identifier. + * \param[in] puser user private void pointer + */ LIBCA_API void epicsStdCall ca_set_puser (chid chan, void *puser); + +/** \brief Return a user private void pointer variable + * retained with each channel for use at the users discretion. + * + * \param[in] chan Channel identifier. + * \returns User private pointer + */ LIBCA_API void * epicsStdCall ca_puser (chid chan); + +/** \brief Returns whether the client currently has read access + * to the specified channel. + * + * \param[in] chan Channel identifier. + * \returns Boolean true if the client currently has read access to the specified channel + * and boolean false otherwise. + */ LIBCA_API unsigned epicsStdCall ca_read_access (chid chan); + +/** \brief Returns whether the client currently has write access + * to the specified channel. + * + * \param[in] chan Channel identifier. + * \returns Boolean true if the client currently has write access to the specified channel + * and boolean false otherwise + */ LIBCA_API unsigned epicsStdCall ca_write_access (chid chan); -/* - * cs_ - `channel state' - * - * cs_never_conn valid chid, IOC not found - * cs_prev_conn valid chid, IOC was found, but unavailable - * cs_conn valid chid, IOC was found, still available - * cs_closed channel deleted by user +/** \brief Channel state + */ +enum channel_state { + /// valid chid, IOC not found or unavailable + cs_never_conn, + /// valid chid, IOC was found, but unavailable (previously connected to server) + cs_prev_conn, + /// valid chid, IOC was found, still available + cs_conn, + /// channel deleted by user + cs_closed +}; + +/** \brief Returns an enumerated type indicating the current state of the specified IO channel. + * + * \param[in] chan Channel identifier. + * \returns the connection state. */ -enum channel_state {cs_never_conn, cs_prev_conn, cs_conn, cs_closed}; LIBCA_API enum channel_state epicsStdCall ca_state (chid chan); /************************************************************************/ @@ -172,19 +286,121 @@ LIBCA_API enum channel_state epicsStdCall ca_state (chid chan); /* */ /* Must be called once before calling any of the other routines */ /************************************************************************/ + +/** \brief Initialize a Channel Access task. + * + * \deprecated Use ca_context_create() instead. + */ LIBCA_API int epicsStdCall ca_task_initialize (void); + enum ca_preemptive_callback_select { ca_disable_preemptive_callback, ca_enable_preemptive_callback }; + +/** \brief Create a Channel Access context. + * + * This function, or ca_attach_context(), should be called once from each + * thread prior to making any of the other Channel Access calls. If one of the + * above is not called before making other CA calls then a non-preemptive + * context is created by default, and future attempts to create a preemptive + * context for the current threads will fail. + * + * If ::ca_disable_preemptive_callback is specified then additional threads are + * *not* allowed to join the CA context using ca_attach_context() because + * allowing other threads to join implies that CA callbacks will be called + * preemptively from more than one thread. + * + * \param[in] select + * \parblock + * This argument specifies if preemptive invocation of callback + * functions is allowed. If so your callback functions might be called + * when the thread that calls this routine is not executing in the CA + * client library. There are two implications to consider. + * + * First, if preemptive callback mode is enabled the developer must + * provide mutual exclusion protection for his data structures. In this + * mode it's possible for two threads to touch the application's data + * structures at once: this might be the initializing thread (the + * thread that called ca_context_create()) and also a private thread + * created by the CA client library for the purpose of receiving + * network messages and calling callbacks. It might be prudent for + * developers who are unfamiliar with mutual exclusion locking in a + * multi-threaded environment to specify + * ::ca_disable_preemptive_callback. + * + * Second, if preemptive callback mode is enabled the application is no + * longer burdened with the necessity of periodically polling the CA + * client library in order that it might take care of its background + * activities. If ca_enable_preemptive_callback is specified then CA + * client background activities, such as connection management, will + * proceed even if the thread that calls this routine is not executing + * in the CA client library. Furthermore, in preemptive callback mode + * callbacks might be called with less latency because the library is + * not required to wait until the initializing thread (the thread that + * called ca_context_create()) is executing within the CA client library. + * \endparblock + * + * \returns ::ECA_NORMAL - Normal successful completion + * \returns ::ECA_ALLOCMEM - Failed, unable to allocate space in pool + * \returns ::ECA_NOTTHREADED - Current thread is already a member of a non-preemptive callback CA context (possibly created implicitly) + * + * \sa ca_context_destroy() + */ LIBCA_API int epicsStdCall ca_context_create (enum ca_preemptive_callback_select select); -LIBCA_API void epicsStdCall ca_detach_context (); + +/** \brief Detach from any CA context currently attached to the calling thread. + * + * This does *not* cleanup or shutdown any currently attached CA context (for + * that use ca_context_destroy()). + * + * \sa ca_current_context(), ca_attach_context(), ca_context_create(), ca_context_destroy() + */ +LIBCA_API void epicsStdCall ca_detach_context (); /************************************************************************/ /* Remove CA facility from your task */ /* */ /* Normally called automatically at task exit */ /************************************************************************/ + +/** \brief Exit a Channel Access task. + * + * \deprecated Use ca_context_destroy() instead. + */ LIBCA_API int epicsStdCall ca_task_exit (void); + +/** \brief Destroy a Channel Access context. + * + * Shut down the calling thread's channel access client context and free + * any resources allocated. Detach the calling thread from any CA client + * context. + * + * Any user-created threads that have attached themselves to the CA context + * must stop using it prior to its being destroyed. A program running in an + * IOC context must delete all of its channels prior to calling + * ca_context_destroy() to avoid a crash. + * + * A CA client application that calls epicsExit() *must* install an EPICS + * exit handler that calls ca_context_destroy() only *after* first + * calling ca_context_create(). This will guarantee that the EPICS exit + * handlers get called in the correct order. + * + * On many OS that execute programs in a process based environment the + * resources used by the client library such as sockets and allocated + * memory are automatically released by the system when the process exits + * and ca_context_destroy() hasn't been called, but on light weight + * systems such as vxWorks or RTEMS no cleanup occurs unless the + * application calls ca_context_destroy(). + * + * \note This operation blocks until any user callbacks for any channel + * created in the current context have run to completion. If callbacks take + * a lock (mutex) then it is the user's responsibility to ensure that this + * lock is not held when ca_clear_context() is called, otherwise a + * deadlock may ensue. (See also ca_clear_channel() and + * ca_clear_subscription().) + * + * \sa ca_context_create() + */ LIBCA_API void epicsStdCall ca_context_destroy (void); typedef unsigned capri; @@ -196,17 +412,102 @@ typedef unsigned capri; #define CA_PRIORITY_ARCHIVE 20 #define CA_PRIORITY_OPI 0 -/* - * ca_create_channel () +/** \brief Create a Channel Access channel. * - * pChanName R channel name string - * pConnStateCallback R address of connection state change - * callback function - * pUserPrivate R placed in the channel's user private field - * o can be fetched later by ca_puser(CHID) - * o passed as void * arg to *pConnectCallback above - * priority R priority level in the server 0 - 100 - * pChanID RW channel id written here + * This function creates a CA channel. The CA client library will attempt + * to establish and maintain a virtual circuit between the caller's + * application and a named process variable in a CA server. Each call to + * ca_create_channel() allocates resources in the CA client library and + * potentially also a CA server. The function ca_clear_channel() is used + * to release these resources. If successful, the routine writes a channel + * identifier into the user's variable of type "chid". This identifier + * can be used with any channel access call that operates on a channel. + * + * The circuit may be initially connected or disconnected depending on the + * state of the network and the location of the channel. A channel will + * only enter a connected state after the server's address is determined, + * and only if channel access successfully establishes a virtual circuit + * through the network to the server. Channel access routines that send a + * request to a server will return ::ECA_DISCONNCHID if the channel is + * currently disconnected. + * + * There are two ways to obtain asynchronous notification when a channel + * enters a connected state. + * + * - The first and simplest method requires that you call ca_pend_io(), + * and wait for successful completion, prior to using a channel that + * was created specifying a null connection callback function pointer. + * - The second method requires that you register a connection handler by + * supplying a valid connection callback function pointer. This + * connection handler is called whenever the connection state of the + * channel changes. If you have installed a connection handler then + * ca_pend_io() will *not* block waiting for the channel to enter a + * connected state. + * + * The function ca_state(CHID) can be used to test the connection state of + * a channel. Valid connections may be isolated from invalid ones with this + * function if ca_pend_io() times out. + * + * Due to the inherently transient nature of network connections the order + * of connection callbacks relative to the order that ca_create_channel() + * calls are made by the application can't be guaranteed, and application + * programs may need to be prepared for a connected channel to enter a + * disconnected state at any time. + * + * # Example + * + * See `caExample.c` in the example application created by `makeBaseApp.pl`. + * + * \param[in] pChanName A nil terminated process variable name string. + * \parblock + * EPICS process control * function block database variable names are of the + * form `.`. If the field name and the period + * separator are omitted then the `VAL` field is implicit. For example + * `RFHV01` and `RFHV01.VAL` reference the same EPICS process control function + * block database variable. + * \endparblock + * + * \param[in] pConnStateCallback address of connection state change callback function + * \parblock + * Optional pointer to the user's callback function to be run when the + * connection state changes. Casual users of channel access may decide + * to set this field to null or 0 if they do not need to have a + * callback function run in response to each connection state change + * event. + * + * A connection_handler_args structure is passed *by value* to the user's + * connection callback function. The `op` field will be set by the CA + * client library to ::CA_OP_CONN_UP when the channel connects, and to + * ::CA_OP_CONN_DOWN when the channel disconnects. See ca_puser() + * if the `pUserPrivate` argument is required in your callback handler. + * \endparblock + * + * \param[in] pUserPrivate The value of this void pointer argument is retained in storage + * associated with the specified channel. + * Casual users of channel access may wish to set this field to null or 0. + * Can be fetched later by ca_puser(CHID). + * passed as `void *` arg to `*pConnStateCallback` above + * + * \param[in] priority The priority level for dispatch within the server or + * network with 0 specifying the lowest dispatch priority and 99 the highest. + * This parameter currently does not impact dispatch priorities within the + * client, but this might change in the future. The abstract priority range + * specified is mapped into an operating system specific range of priorities + * within the server. This parameter is ignored if the server is running on a + * network or operating system that does not have native support for + * prioritized delivery or execution respectively. Specifying many different + * priorities within the same program can increase resource consumption in the + * client and the server because an independent virtual circuit, and associated + * data structures, is created for each priority that is used on a particular + * server. + * + * \param[inout] pChanID The user supplied channel identifier storage is overwritten + * with a channel identifier if this routine is successful. + * + * \returns ::ECA_NORMAL - Normal successful completion + * \returns ::ECA_BADTYPE - Invalid DBR_XXXX type + * \returns ::ECA_STRTOBIG - Unusually large string + * \returns ::ECA_ALLOCMEM - Unable to allocate memory */ LIBCA_API int epicsStdCall ca_create_channel ( @@ -229,38 +530,112 @@ LIBCA_API int epicsStdCall ca_change_connection_event caCh * pfunc ); -/* - * ca_replace_access_rights_event () +/** \brief Install or replace the access rights state change callback handler + * for the specified channel. * - * chan R channel identifier - * pfunc R address of access rights call-back function + * The callback handler is called in the following situations. + * + * - whenever CA connects the channel immediately before the channel's + * connection handler is called + * - whenever CA disconnects the channel immediately after the channel's + * disconnect callback is called + * - once immediately after installation if the channel is connected. + * - whenever the access rights state of a connected channel changes + * + * When a channel is created no access rights handler is installed. + * + * \param[in] chan Channel identifier. + * \param[in] pfunc Pointer to a user supplied callback function. + * A null pointer uninstalls the current handler. + * An access_rights_handler_args structure is passed *by value* to the supplied callback handler. + * + * \returns ::ECA_NORMAL - Normal successful completion */ LIBCA_API int epicsStdCall ca_replace_access_rights_event ( chid chan, caArh *pfunc ); -/* - * ca_add_exception_event () - * - * replace the default exception handler - * - * pfunc R address of exception call-back function - * pArg R copy of this pointer passed to exception - * call-back function - */ typedef void caExceptionHandler (struct exception_handler_args); + +/** \brief Replace the currently installed CA context global exception handler callback. + * + * When an error occurs in the server asynchronous to the clients thread then + * information about this type of error is passed from the server to the client + * in an exception message. When the client receives this exception message an + * exception handler callback is called. The default exception handler prints a + * diagnostic message on the client's standard out and terminates execution if + * the error condition is severe. + * + * Note that certain fields in struct exception_handler_args are not + * applicable in the context of some error messages. For instance, a failed get + * will supply the address in the client task where the returned value was + * requested to be written. For other failed operations the value of the addr + * field should not be used. + * + * # Example + * + * ```c + * void ca_exception_handler ( + * struct exception_handler_args args) + * { + * char buf[512]; + * char *pName; + * + * if ( args.chid ) { + * pName = ca_name ( args.chid ); + * } + * else { + * pName = "?"; + * } + * sprintf ( buf, + * "%s - with request chan=%s op=%d data type=%s count=%d", + * args.ctx, pName, args.op, dbr_type_to_text ( args.type ), args.count ); + * ca_signal ( args.stat, buf ); + * } + * ca_add_exception_event ( ca_exception_handler , 0 ); + * ``` + * + * \param[in] pfunc Pointer to a user callback function to be executed when exceptions occur. + * Passing a null value causes the default exception handler to be reinstalled. + * An exception_handler_args structure is passed by value to the user's callback function. + * Currently, the `op` field can be one of ::CA_OP_GET, ::CA_OP_PUT, + * ::CA_OP_CREATE_CHANNEL, ::CA_OP_ADD_EVENT, ::CA_OP_CLEAR_EVENT, + * or ::CA_OP_OTHER. + * + * \param[in] pArg Pointer sized variable retained and passed back to user function above. + * + * \returns ::ECA_NORMAL - Normal successful completion + */ LIBCA_API int epicsStdCall ca_add_exception_event ( caExceptionHandler *pfunc, void *pArg ); -/* - * ca_clear_channel() - * - deallocate resources reserved for a channel +/** \brief Shutdown and reclaim resources associated with a channel created by ca_create_channel(). * - * chanId R channel ID + * All remote operation requests such as the above are accumulated + * (buffered) and not forwarded to the IOC until one of ca_flush_io(), + * ca_pend_io(), ca_pend_event(), or ca_sg_block() are called. This + * allows several requests to be efficiently sent over the network in one + * message. + * + * Clearing a channel does not cause its disconnect handler to be called, + * but clearing a channel does shutdown and reclaim any channel state + * change event subscriptions (monitors) registered with the channel. + * + * Note: This operation blocks until any user callbacks for this channel + * have run to completion. If callbacks take a lock (mutex) then it is the + * user's responsibility to ensure that this lock is not held when + * ca_clear_channel() is called, otherwise a deadlock may ensue. + * + * \sa ca_clear_subscription() + * + * \param[in] chanId Identifies the channel to delete. + * + * \returns ::ECA_NORMAL - Normal successful completion + * \returns ::ECA_BADCHID - Corrupted CHID */ LIBCA_API int epicsStdCall ca_clear_channel ( @@ -293,22 +668,108 @@ ca_array_put(DBR_STRING, 1u, chan, (const dbr_string_t *) (pValue)) #define ca_rput(chan,pValue) \ ca_array_put(DBR_FLOAT, 1u, chan, (const dbr_float_t *) pValue) -/* - * ca_put() +/** \brief Write a scalar value to a process variable. * - * type R data type from db_access.h - * chan R channel identifier - * pValue R new channel value copied from this location + * See ca_array_put(). + * + * \param[in] type The external type of the supplied value to be written. + * Conversion will occur if this does not match the native type. Specify one + * from the set of `DBR_XXXX` in `db_access.h` + * + * \param[in] chan Channel identifier. + * + * \param[in] pValue Pointer to a value or array of values provided by the application + * to be written to the channel. + * + * \returns ::ECA_NORMAL - Normal successful completion + * \returns ::ECA_BADCHID - Corrupted CHID + * \returns ::ECA_BADTYPE - Invalid DBR_XXXX type + * \returns ::ECA_BADCOUNT - Requested count larger than native element count + * \returns ::ECA_STRTOBIG - Unusually large string supplied + * \returns ::ECA_NOWTACCESS - Write access denied + * \returns ::ECA_ALLOCMEM - Unable to allocate memory + * \returns ::ECA_DISCONN - Channel is disconnected */ #define ca_put(type, chan, pValue) ca_array_put (type, 1u, chan, pValue) -/* - * ca_array_put() +/** \brief Write a scalar or array value to a process variable. * - * type R data type from db_access.h - * count R array element count - * chan R channel identifier - * pValue R new channel value copied from this location + * When ca_put() or ca_array_put() are invoked the client will receive + * no response unless the request can not be fulfilled in the server. If + * unsuccessful an exception handler is run on the client side. + * + * When ca_put_callback() or ca_array_put_callback() are invoked the + * user supplied asynchronous callback is called only after the initiated + * write operation, and all actions resulting from the initiating write + * operation, complete. The arguments to the user supplied callback function + * are declared in the structure event_handler_args and include the pointer + * sized user argument supplied when ca_array_put_callback() is called. + * + * If unsuccessful the callback function is invoked indicating failure + * status. + * + * If the channel disconnects before a put callback request can be + * completed, then the client's callback function is called with failure + * status, but this does not guarantee that the server did not receive and + * process the request before the disconnect. If a connection is lost and + * then resumed outstanding ca put requests are not automatically reissued + * following reconnect. + * + * All of these functions return ::ECA_DISCONN if the channel is currently + * disconnected. + * + * All put requests are accumulated (buffered) and not forwarded to the IOC + * until one of ca_flush_io(), ca_pend_io(), ca_pend_event(), or + * ca_sg_block() are called. This allows several requests to be + * efficiently combined into one message. + * + * # Description (IOC Database Specific) + * + * A CA put request causes the record to process if the record's SCAN + * field is set to passive, and the field being written has its process + * passive attribute set to true. If such a record is already processing + * when a put request is initiated the specified field is written + * immediately, and the record is scheduled to process again as soon as it + * finishes processing. Earlier instances of multiple put requests + * initiated while the record is being processing may be discarded, but the + * last put request initiated is always written and processed. + * + * A CA put *callback* request causes the record to process if the + * record's SCAN field is set to passive, and the field being written has + * its process passive attribute set to true. For such a record, the + * user's put callback function is not called until after the record, and + * any records that the record links to, finish processing. If such a + * record is already processing when a put *callback* request is initiated + * the put *callback* request is postponed until the record, and any + * records it links to, finish processing. + * + * If the record's SCAN field is not set to passive, or the field being + * written has its process passive attribute set to false then the CA put + * or CA put *callback* request cause the specified field to be immediately + * written, but they do not cause the record to be processed. + * + * \sa ca_flush_io(), ca_pend_event(), ca_sg_array_put() + * + * \param[in] type The external type of the supplied value to be written. + * Conversion will occur if this does not match the native type. Specify one + * from the set of `DBR_XXXX` in `db_access.h` + * + * \param[in] count Element count to be written to the specified channel. + * This must match the array pointed to by pValue. + * + * \param[in] chanId Channel identifier. + * + * \param[in] pValue Pointer to a value or array of values provided by the application + * to be written to the channel. + * + * \returns ::ECA_NORMAL - Normal successful completion + * \returns ::ECA_BADCHID - Corrupted CHID + * \returns ::ECA_BADTYPE - Invalid DBR_XXXX type + * \returns ::ECA_BADCOUNT - Requested count larger than native element count + * \returns ::ECA_STRTOBIG - Unusually large string supplied + * \returns ::ECA_NOWTACCESS - Write access denied + * \returns ::ECA_ALLOCMEM - Unable to allocate memory + * \returns ::ECA_DISCONN - Channel is disconnected */ LIBCA_API int epicsStdCall ca_array_put ( @@ -318,22 +779,36 @@ LIBCA_API int epicsStdCall ca_array_put const void * pValue ); -/* - * ca_array_put_callback() +/** \brief Asynchronously write a scalar or array value to a process variable. * - * This routine functions identically to the original ca put request - * with the addition of a callback to the user supplied function - * after recod processing completes in the IOC. The arguments - * to the user supplied callback function are declared in - * the structure event_handler_args and include the pointer - * sized user argument supplied when ca_array_put_callback() is called. + * See ca_array_put(). * - * type R data type from db_access.h - * count R array element count - * chan R channel identifier - * pValue R new channel value copied from this location - * pFunc R pointer to call-back function - * pArg R copy of this pointer passed to pFunc + * \param[in] type The external type of the supplied value to be written. + * Conversion will occur if this does not match the native type. Specify one + * from the set of `DBR_XXXX` in `db_access.h` + * + * \param[in] count Element count to be written to the specified channel. + * This must match the array pointed to by pValue. + * + * \param[in] chanId Channel identifier. + * + * \param[in] pValue Pointer to a value or array of values provided by the application + * to be written to the channel. + * + * \param[in] pFunc Pointer to a user supplied callback function to be run + * when the requested operation completes. + * + * \param[in] pArg Pointer sized variable retained + * and then passed back to user supplied function above. + * + * \returns ::ECA_NORMAL - Normal successful completion + * \returns ::ECA_BADCHID - Corrupted CHID + * \returns ::ECA_BADTYPE - Invalid DBR_XXXX type + * \returns ::ECA_BADCOUNT - Requested count larger than native element count + * \returns ::ECA_STRTOBIG - Unusually large string supplied + * \returns ::ECA_NOWTACCESS - Write access denied + * \returns ::ECA_ALLOCMEM - Unable to allocate memory + * \returns ::ECA_DISCONN - Channel is disconnected */ LIBCA_API int epicsStdCall ca_array_put_callback ( @@ -345,6 +820,34 @@ LIBCA_API int epicsStdCall ca_array_put_callback void * pArg ); +/** \brief Asynchronously write a scalar value to a process variable. + * + * See ca_array_put(). + * + * \param[in] type The external type of the supplied value to be written. + * Conversion will occur if this does not match the native type. Specify one + * from the set of `DBR_XXXX` in `db_access.h` + * + * \param[in] chan Channel identifier. + * + * \param[in] pValue Pointer to a value or array of values provided by the application + * to be written to the channel. + * + * \param[in] pFunc Pointer to a user supplied callback function to be run + * when the requested operation completes. + * + * \param[in] pArg Pointer sized variable retained + * and then passed back to user supplied function above. + * + * \returns ::ECA_NORMAL - Normal successful completion + * \returns ::ECA_BADCHID - Corrupted CHID + * \returns ::ECA_BADTYPE - Invalid DBR_XXXX type + * \returns ::ECA_BADCOUNT - Requested count larger than native element count + * \returns ::ECA_STRTOBIG - Unusually large string supplied + * \returns ::ECA_NOWTACCESS - Write access denied + * \returns ::ECA_ALLOCMEM - Unable to allocate memory + * \returns ::ECA_DISCONN - Channel is disconnected + */ #define ca_put_callback(type, chan, pValue, pFunc, pArg) \ ca_array_put_callback(type, 1u, chan, pValue, pFunc, pArg) @@ -375,22 +878,88 @@ ca_array_get(DBR_STRING, 1u, chan, (dbr_string_t *)(pValue)) #define ca_rget(chan, pValue) \ ca_array_get(DBR_FLOAT, 1u, chan, (dbr_float_t *)(pValue)) -/* - * ca_rget() +/** \brief Read a scalar value from a process variable. * - * type R data type from db_access.h - * chan R channel identifier - * pValue W channel value copied to this location + * See ca_array_get(). + * + * \param[in] type The external type of the user variable to return the value into. + * Conversion will occur if this does not match the native type. + * Specify one from the set of DBR_XXXX in db_access.h + * + * \param[in] chan Channel identifier. + * + * \param[out] pValue Pointer to an application supplied buffer + * where the current value of the channel is to be written. + * + * \returns ::ECA_NORMAL - Normal successful completion + * \returns ::ECA_BADTYPE - Invalid DBR_XXXX type + * \returns ::ECA_BADCHID - Corrupted CHID + * \returns ::ECA_BADCOUNT - Requested count larger than native element count + * \returns ::ECA_GETFAIL - A local database get failed + * \returns ::ECA_NORDACCESS - Read access denied + * \returns ::ECA_ALLOCMEM - Unable to allocate memory + * \returns ::ECA_DISCONN - Channel is disconnected */ #define ca_get(type, chan, pValue) ca_array_get(type, 1u, chan, pValue) -/* - * ca_array_get() +/** \brief Read a scalar or array value from a process variable. * - * type R data type from db_access.h - * count R array element count - * chan R channel identifier - * pValue W channel value copied to this location + * When ca_get() or ca_array_get() are invoked the returned channel + * value can't be assumed to be stable in the application supplied buffer + * until after ECA_NORMAL is returned from ca_pend_io(). If a connection + * is lost outstanding ca get requests are not automatically reissued + * following reconnect. + * + * When ca_get_callback() or ca_array_get_callback() are invoked a + * value is read from the channel and then the user's callback is invoked + * with a pointer to the retrieved value. Note that ca_pend_io() will not + * block for the delivery of values requested by ca_get_callback(). If + * the channel disconnects before a ca_get_callback() request can be + * completed, then the client's callback function is called with failure + * status. + * + * All of these functions return ::ECA_DISCONN if the channel is currently + * disconnected. + * + * All get requests are accumulated (buffered) and not forwarded to the IOC + * until one of ca_flush_io(), ca_pend_io(), ca_pend_event(), or + * ca_sg_block() are called. This allows several requests to be + * efficiently sent over the network in one message. + * + * ## Description (IOC Database Specific) + * + * A CA get or CA get callback request causes the record's field to be + * read immediately independent of whether the record is currently being + * processed or not. There is currently no mechanism in place to cause a + * record to be processed when a CA get request is initiated. + * + * # Example + * + * See `caExample.c` in the example application created by `makeBaseApp.pl`. + * + * \sa ca_pend_io(), ca_pend_event(), ca_sg_array_get() + * + * \param[in] type The external type of the user variable to return the value into. + * Conversion will occur if this does not match the native type. + * Specify one from the set of DBR_XXXX in db_access.h + * + * \param[in] count Element count to be read from the specified channel. + * Must match the array pointed to by pValue. + * For ca_array_get_callback() a count of zero means use the current element count from the server. + * + * \param[in] chanId Channel identifier. + * + * \param[out] pValue Pointer to an application supplied buffer + * where the current value of the channel is to be written. + * + * \returns ::ECA_NORMAL - Normal successful completion + * \returns ::ECA_BADTYPE - Invalid DBR_XXXX type + * \returns ::ECA_BADCHID - Corrupted CHID + * \returns ::ECA_BADCOUNT - Requested count larger than native element count + * \returns ::ECA_GETFAIL - A local database get failed + * \returns ::ECA_NORDACCESS - Read access denied + * \returns ::ECA_ALLOCMEM - Unable to allocate memory + * \returns ::ECA_DISCONN - Channel is disconnected */ LIBCA_API int epicsStdCall ca_array_get ( @@ -431,25 +1000,62 @@ ca_array_get_callback (DBR_STRING, 1u, chan, pFunc, pArg) #define ca_rget_callback(chan, pFunc, pArg)\ ca_array_get_callback (DBR_FLOAT, 1u, chan, pFunc, pArg) -/* - * ca_get_callback() +/** \brief Asynchronously read a scalar value from a process variable. * - * type R data type from db_access.h - * chan R channel identifier - * pFunc R pointer to call-back function - * pArg R copy of this pointer passed to pFunc + * See ca_array_get(). + * + * \param[in] type The external type of the user variable to return the value into. + * Conversion will occur if this does not match the native type. + * Specify one from the set of DBR_XXXX in db_access.h + * + * \param[in] chan Channel identifier. + * + * \param[in] pFunc Pointer to a user supplied callback function to be run + * when the requested operation completes. + * + * \param[in] pArg Pointer sized variable retained + * and then passed back to user supplied callback function above. + * + * \returns ::ECA_NORMAL - Normal successful completion + * \returns ::ECA_BADTYPE - Invalid DBR_XXXX type + * \returns ::ECA_BADCHID - Corrupted CHID + * \returns ::ECA_BADCOUNT - Requested count larger than native element count + * \returns ::ECA_GETFAIL - A local database get failed + * \returns ::ECA_NORDACCESS - Read access denied + * \returns ::ECA_ALLOCMEM - Unable to allocate memory + * \returns ::ECA_DISCONN - Channel is disconnected */ #define ca_get_callback(type, chan, pFunc, pArg)\ ca_array_get_callback (type, 1u, chan, pFunc, pArg) -/* - * ca_array_get_callback() +/** \brief Asynchronously read a scalar or array value from a process variable. * - * type R data type from db_access.h - * count R array element count - * chan R channel identifier - * pFunc R pointer to call-back function - * pArg R copy of this pointer passed to pFunc + * See ca_array_get(). + * + * \param[in] type The external type of the user variable to return the value into. + * Conversion will occur if this does not match the native type. + * Specify one from the set of DBR_XXXX in db_access.h + * + * \param[in] count Element count to be read from the specified channel. + * Must match the array pointed to by pValue. + * For ca_array_get_callback() a count of zero means use the current element count from the server. + * + * \param[in] chanId Channel identifier. + * + * \param[in] pFunc Pointer to a user supplied callback function to be run + * when the requested operation completes. + * + * \param[in] pArg Pointer sized variable retained + * and then passed back to user supplied callback function above. + * + * \returns ::ECA_NORMAL - Normal successful completion + * \returns ::ECA_BADTYPE - Invalid DBR_XXXX type + * \returns ::ECA_BADCHID - Corrupted CHID + * \returns ::ECA_BADCOUNT - Requested count larger than native element count + * \returns ::ECA_GETFAIL - A local database get failed + * \returns ::ECA_NORDACCESS - Read access denied + * \returns ::ECA_ALLOCMEM - Unable to allocate memory + * \returns ::ECA_DISCONN - Channel is disconnected */ LIBCA_API int epicsStdCall ca_array_get_callback ( @@ -470,16 +1076,97 @@ LIBCA_API int epicsStdCall ca_array_get_callback /* */ /************************************************************************/ -/* - * ca_create_subscription () +/** \brief Register a state change subscription and specify a callback function + * to be invoked whenever the process variable undergoes significant state + * changes. * - * type R data type from db_access.h - * count R array element count - * chan R channel identifier - * mask R event mask - one of {DBE_VALUE, DBE_ALARM, DBE_LOG} - * pFunc R pointer to call-back function - * pArg R copy of this pointer passed to pFunc - * pEventID W event id written at specified address + * A significant change can be a change in the process variable's + * value, alarm status, or alarm severity. In the process control function + * block database the deadband field determines the magnitude of a + * significant change for the process variable's value. Each call to this + * function consumes resources in the client library and potentially a CA + * server until one of ca_clear_channel() or ca_clear_subscription() is + * called. + * + * Subscriptions may be installed or canceled against both connected and + * disconnected channels. The specified pFunc is called once immediately + * after the subscription is installed with the process variable's current + * state if the process variable is connected. Otherwise, the specified + * pFunc is called immediately after establishing a connection (or + * reconnection) with the process variable. The specified pFunc is + * called immediately with the process variable's current state from + * within ca_create_subscription() if the client and the process variable + * share the same address space. + * + * If a subscription is installed on a channel in a disconnected state then + * the requested count will be set to the native maximum element count of + * the channel if the requested count is larger. + * + * All subscription requests such as the above are accumulated (buffered) + * and not forwarded to the IOC until one of ca_flush_io(), + * ca_pend_io(), ca_pend_event(), or ca_sg_block() are called. This + * allows several requests to be efficiently sent over the network in one + * message. + * + * If at any time after subscribing, read access to the specified process + * variable is lost, then the callback will be invoked immediately + * indicating that read access was lost via the status argument. When read + * access is restored normal event processing will resume starting always + * with at least one update indicating the current state of the channel. + * + * A better name for this function might have been ca_subscribe(). + * + * # Example + * + * See `caMonitor.c` in the example application created by `makeBaseApp.pl`. + * + * \sa ca_pend_event(), ca_flush_io() + * + * \param[in] type The type of value presented to the callback function. + * Conversion will occur if it does not match native type. + * Specify one from the set of `DBR_XXXX` in `db_access.h` + * + * \param[in] count The element count to be read from the specified channel. + * A count of zero means use the current element count from the server, + * effectively resulting in a variable size array subscription. + * + * \param[in] chanId Channel identifier. + * + * \param[in] mask + * \parblock + * A mask with bits set for each of the event trigger types requested. + * The event trigger mask must be a *bitwise or* of one or more of the + * following constants. + * + * - ::DBE_VALUE - Trigger events when the channel value exceeds the + * monitor dead band + * - ::DBE_ARCHIVE (or ::DBE_LOG) - Trigger events when the channel value + * exceeds the archival dead band + * - ::DBE_ALARM - Trigger events when the channel alarm state changes + * - ::DBE_PROPERTY - Trigger events when a channel property changes. + * + * For functions above that do not include a trigger specification, + * events will be triggered when there are significant changes in the + * channel's value or when there are changes in the channel's alarm + * state. This is the same as `DBE_VALUE | DBE_ALARM`. + * \endparblock + * + * \param[in] pFunc Pointer to a user supplied callback function to be invoked + * with each subscription update. + * + * \param[in] pArg Pointer sized variable retained and passed back + * to user callback function + * + * \param[out] pEventID This is a pointer to user supplied event id which is overwritten + * if successful. + * This event id can later be used to clear a specific event. + * This option may be omitted by passing a null pointer. + * + * \returns ::ECA_NORMAL - Normal successful completion + * \returns ::ECA_BADCHID - Corrupted CHID + * \returns ::ECA_BADTYPE - Invalid DBR_XXXX type + * \returns ::ECA_ALLOCMEM - Unable to allocate memory + * \returns ::ECA_ADDFAIL - A local database event add failed */ LIBCA_API int epicsStdCall ca_create_subscription ( @@ -497,10 +1184,26 @@ LIBCA_API int epicsStdCall ca_create_subscription /* whenever significant changes occur to a channel */ /* */ /************************************************************************/ -/* - * ca_clear_subscription() + +/** \brief Cancel a subscription. * - * eventID R event id + * All cancel-subscription requests such as the above are accumulated + * (buffered) and not forwarded to the server until one of ca_flush_io(), + * ca_pend_io(), ca_pend_event(), or ca_sg_block() are called. This + * allows several requests to be efficiently sent together in one message. + * + * \note This operation blocks until any user callbacks for this channel + * have run to completion. If callbacks take a lock (mutex) then it is the + * user's responsibility to ensure that this lock is not held when + * ca_clear_subscription() is called, otherwise a deadlock may ensue. + * (See also ca_clear_channel().) + * + * \sa ca_create_subscription() + * + * \param[in] eventID Event id returned by ca_create_subscription(). + * + * \returns ::ECA_NORMAL - Normal successful completion + * \returns ::ECA_BADCHID - Corrupted CHID */ LIBCA_API int epicsStdCall ca_clear_subscription ( @@ -556,48 +1259,142 @@ LIBCA_API chid epicsStdCall ca_evid_to_chid ( evid id ); /* without processing. */ /************************************************************************/ -/* - * ca_pend_event() +/** \brief Flush the send buffer + * and process CA background activity for `timeout` seconds. * - * timeout R wait for this delay in seconds + * The ca_pend_event() function will *not* return before the specified + * timeout expires and all unfinished channel access labor has been + * processed, and unlike ca_pend_io() returning from the + * function does *not* indicate anything about the status of pending IO + * requests. + * + * Both ca_pend_event() and ca_poll() return ::ECA_TIMEOUT when + * successful. This behavior probably isn\'t intuitive, but it is preserved + * to insure backwards compatibility. + * + * See also "Thread Safety and Preemptive Callback to User Code" + * from the Channel Access reference manual. + * + * \sa ca_poll() + * + * \param[in] timeout The duration to block in this routine in seconds. + * A timeout of zero seconds blocks forever. + * + * \returns ::ECA_TIMEOUT - The operation timed out + * \returns ::ECA_EVDISALLOW - Function inappropriate for use within a callback handler */ LIBCA_API int epicsStdCall ca_pend_event (ca_real timeout); + +/** \brief Flush the send buffer + * and process any outstanding CA background activity. + * + * See ca_pend_event(). + * + * \returns ::ECA_TIMEOUT - The operation timed out + * \returns ::ECA_EVDISALLOW - Function inappropriate for use within a callback * handler + */ #define ca_poll() ca_pend_event(1e-12) -/* - * ca_pend_io() +/** \brief Flushes the send buffer and then blocks + * until outstanding ca_get() requests complete, + * and until channels created specifying null connection handler function pointers + * connect for the first time. * - * timeout R wait for this delay in seconds but return early - * if all get requests (or search requests with null - * connection handler pointer have completed) + * - If ::ECA_NORMAL is returned then it can be safely assumed that all + * outstanding ca_get() requests have completed + * successfully and channels created specifying null connection handler + * function pointers have connected for the first time. + * - If ::ECA_TIMEOUT is returned then it must be assumed for all previous + * ca_get() requests and properly qualified first time + * channel connects have failed. + * + * If ::ECA_TIMEOUT is returned then get requests may be reissued followed by + * a subsequent call to ca_pend_io(). Specifically, the function will + * block only for outstanding ca_get() requests issued, and + * also any channels created specifying a null connection handler function + * pointer, after the last call to ca_pend_io() or ca client context + * creation whichever is later. Note that + * ca_create_channel() requests generally should + * not be reissued for the same process variable unless + * ca_clear_channel() is called first. + * + * If no ca_get() or connection state change events are + * outstanding then ca_pend_io() will flush the send buffer and return + * immediately *without processing any outstanding channel access + * background activities*. + * + * The delay specified to ca_pend_io() should take into account worst + * case network delays such as Ethernet collision exponential back off + * until retransmission delays which can be quite long on overloaded + * networks. + * + * Unlike ca_pend_event(), this routine will not + * process CA's background activities if none of the selected IO requests + * are pending. + * + * \sa ca_get(), ca_create_channel(), ca_test_io() + * + * \param[in] timeout Specifies the time out interval. + * A `timeout` interval of zero specifies forever. + * + * \returns ::ECA_NORMAL - Normal successful completion + * \returns ::ECA_TIMEOUT - Selected IO requests didn't complete before specified timeout + * \returns ::ECA_EVDISALLOW - Function inappropriate for use within an event handler */ LIBCA_API int epicsStdCall ca_pend_io (ca_real timeout); /* calls ca_pend_io() if early is true otherwise ca_pend_event() is called */ LIBCA_API int epicsStdCall ca_pend (ca_real timeout, int early); -/* - * ca_test_io() +/** \brief Test to see if all ca_get() requests are complete + * and channels created specifying a null connection callback function pointer are connected. * - * returns TRUE when get requests (or search requests with null - * connection handler pointer) are outstanding + * It will report the status of outstanding ca_get() requests issued, and + * channels created specifying a null connection callback function pointer, + * after the last call to ca_pend_io() or CA context initialization whichever + * is later. + * + * \sa ca_pend_io() + * + * \returns ::ECA_IODONE - All IO operations completed + * \returns ::ECA_IOINPROGRESS - IO operations still in progress */ LIBCA_API int epicsStdCall ca_test_io (void); /************************************************************************/ /* Send out all outstanding messages in the send queue */ /************************************************************************/ -/* - * ca_flush_io() + +/** \brief Flush outstanding IO requests to the server. + * + * This routine might be useful to users who need to flush requests prior to + * performing client side labor in parallel with labor performed in the server. + * + * Outstanding requests are also sent whenever the buffer which holds them + * becomes full. + * + * \returns ::ECA_NORMAL - Normal successful completion */ LIBCA_API int epicsStdCall ca_flush_io (void); - -/* - * ca_signal() +/** \brief Provide the error message character string associated with the supplied channel access error code + * and the supplied error context to diagnostics. * - * errorCode R status returned from channel access function - * pCtxStr R context string included with error print out + * If the error code indicates an unsuccessful operation a stack dump is + * printed, if this capability is available on the local operating system, and + * execution is terminated. + * + * \note SEVCHK() is the recommended error handler for simple applications + * which do not wish to write code testing the status returned from each + * channel access call. + * + * If the application only wishes to print the message associated with an error + * code or test the severity of an error there are also functions provided for + * this purpose. + * + * \param[in] errorCode The status returned from a channel access function. + * \param[in] pCtxStr A null terminated character string to supply + * as error context to diagnostics. */ LIBCA_API void epicsStdCall ca_signal ( @@ -632,37 +1429,86 @@ LIBCA_API void epicsStdCall ca_signal_with_file_and_lineno LIBCA_API void epicsStdCall ca_signal_formated (long ca_status, const char *pfilenm, int lineno, const char *pFormat, ...); -/* - * ca_host_name_function() +/** \brief Return a character string which contains the name of the host + * to which a channel is currently connected. * - * channel R channel identifier + * \warning This function is _not_ thread safe. + * See ca_get_host_name() for a thread safe version. * - * !!!! this function is _not_ thread safe !!!! + * \param[in] channel Channel identifier. + * \returns The process variable server's host name. + * If the channel is disconnected the string `` is returned. */ LIBCA_API const char * epicsStdCall ca_host_name (chid channel); -/* thread safe version */ + +/** \brief Return a character string which contains the name of the host + * to which a channel is currently connected. + * + * \param[in] pChan Channel identifier. + * \param[out] pBuf Where to write the process variable server's host name. + * If the channel is disconnected the string `` is returned. + * \param[out] bufLength The size of the pBuf buffer. + * \returns The effective size of the written host name. + */ LIBCA_API unsigned epicsStdCall ca_get_host_name ( chid pChan, char *pBuf, unsigned bufLength ); -/* - * CA_ADD_FD_REGISTRATION +/** \brief Call their function with their argument whenever + * a new fd is added or removed. * - * call their function with their argument whenever - * a new fd is added or removed - * (for use with a manager of the select system call under UNIX) + * For use with a manager of the select system call under UNIX. * * if (opened) then fd was created * if (!opened) then fd was deleted - * */ typedef void CAFDHANDLER (void *parg, int fd, int opened); -/* - * ca_add_fd_registration() +/** \brief For use with the services provided by a file descriptor manager + * (IO multiplexor) such as "fdmgr.c". * - * pHandler R pointer to function which is to be called - * when an fd is created or deleted - * pArg R argument passed to above function + * A file descriptor manager is often needed when two file descriptor IO + * intensive libraries such as the EPICS channel access client library and the + * X window system client library must coexist in the same UNIX process. This + * function allows an application code to be notified whenever the CA client + * library places a new file descriptor into service and whenever the CA client + * library removes a file descriptor from service. Specifying pHandler=NULL + * disables file descriptor registration (this is the default). + * + * # Example + * + * ```c + * int s; + * static struct myStruct aStruct; + * + * void fdReg ( struct myStruct *pStruct, int fd, int opened ) + * { + * if ( opened ) printf ( "fd %d was opened\n", fd ); + * else printf ( "fd %d was closed\n", fd ); + * } + * s = ca_add_fd_registration ( fdReg, & aStruct ); + * SEVCHK ( s, NULL ); + * ``` + * + * # Comments + * + * When using this function it is advisable to call it only once prior to + * calling any other CA function, or once just after creating the CA context + * (if you create the context explicitly). Use of this interface can improve + * latency slightly in applications that use non preemptive callback mode at + * the expense of some additional runtime overhead when compared to the + * alternative which is just polling ca_pend_event() periodically. It would + * probably not be appropriate to use this function with preemptive callback + * mode. Starting with R3.14 this function is implemented in a special backward + * compatibility mode. if ca_add_fd_registration() is called, a single pseudo + * UDP fd is created which CA pokes whenever something significant happens. Xt + * and others can watch this fd so that backwards compatibility is preserved, + * and so that they will not need to use preemptive callback mode but they will + * nevertheless get the lowest latency response to the arrival of CA messages. + * + * \param[in] pHandler Pointer to a user supplied C function returning null with the above arguments. + * \param[in] pArg User supplied pointer sized variable passed to the above function. + * + * \returns ::ECA_NORMAL - Normal successful completion */ LIBCA_API int epicsStdCall ca_add_fd_registration ( @@ -681,64 +1527,174 @@ LIBCA_API int epicsStdCall ca_add_fd_registration * block for IO completion within any one of the groups as needed. */ -/* - * ca_sg_create() +/** \brief Create a synchronous group and return an identifier for it. * - * create a sync group + * A synchronous group can be used to guarantee that a set of channel access + * requests have completed. Once a synchronous group has been created then + * channel access get and put requests may be issued within it using + * ca_sg_array_get() and ca_sg_array_put() respectively. The routines + * ca_sg_block() and ca_sg_test() can be used to block for and test for + * completion respectively. The routine ca_sg_reset() is used to discard + * knowledge of old requests which have timed out and in all likelihood will + * never be satisfied. * - * pgid W pointer to sync group id that will be written + * Any number of asynchronous groups can have application requested operations + * outstanding within them at any given time. + * + * # Examples + * + * ```c + * CA_SYNC_GID gid; + * status = ca_sg_create ( &gid ); + * SEVCHK ( status, Sync group create failed ); + * ``` + * + * \sa ca_sg_delete(), ca_sg_block(), ca_sg_test(), ca_sg_reset(), + * ca_sg_array_put(), ca_sg_array_get() + * + * \param[out] pgid Pointer to a user supplied CA_SYNC_GID + * that will be written. + * + * \returns ::ECA_NORMAL - Normal successful completion + * \returns ::ECA_ALLOCMEM - Failed, unable to allocate memory */ LIBCA_API int epicsStdCall ca_sg_create (CA_SYNC_GID * pgid); -/* - * ca_sg_delete() +/** \brief Deletes a synchronous group. * - * delete a sync group + * # Examples * - * gid R sync group id + * ```c + * CA_SYNC_GID gid; + * status = ca_sg_delete ( gid ); + * SEVCHK ( status, Sync group delete failed ); + * ``` + * + * \sa ca_sg_create() + * + * \param[in] gid Identifier of the synchronous group to be deleted. + * + * \returns ::ECA_NORMAL - Normal successful completion + * \returns ::ECA_BADSYNCGRP - Invalid synchronous group */ LIBCA_API int epicsStdCall ca_sg_delete (const CA_SYNC_GID gid); -/* - * ca_sg_block() +/** \brief Flushes the send buffer + * and then waits until outstanding requests complete + * or the specified time out expires. * - * block for IO performed within a sync group to complete + * At this time outstanding requests include calls to ca_sg_array_get() and + * calls to ca_sg_array_put(). If ECA_TIMEOUT is returned then failure must be + * assumed for all outstanding queries. Operations can be reissued followed by + * another ca_sg_block(). This routine will only block on outstanding queries + * issued after the last call to ca_sg_block(), ca_sg_reset(), or + * ca_sg_create() whichever occurs later in time. If no queries are outstanding + * then ca_sg_block() will return immediately without processing any pending + * channel access activities. * - * gid R sync group id - * timeout R wait for this duration prior to timing out - * and returning ECA_TIMEOUT + * Values written into your program's variables by a channel access synchronous + * group request should not be referenced by your program until ECA_NORMAL has + * been received from ca_sg_block(). This routine will process pending channel + * access background activity while it is waiting. + * + * # Examples + * + * ```c + * CA_SYNC_GID gid; + * status = ca_sg_block(gid, 0.0); + * SEVCHK(status, Sync group block failed); + * ``` + * + * \sa ca_sg_test(), ca_sg_reset() + * + * \param[in] gid Identifier of the synchronous group. + * \param[in] timeout The duration to block in this routine in seconds. + * A timeout of zero seconds blocks forever. + * + * \returns ::ECA_NORMAL - Normal successful completion + * \returns ::ECA_TIMEOUT - The operation timed out + * \returns ::ECA_EVDISALLOW - Function inappropriate for use within an event handler + * \returns ::ECA_BADSYNCGRP - Invalid synchronous group */ LIBCA_API int epicsStdCall ca_sg_block (const CA_SYNC_GID gid, ca_real timeout); -/* - * ca_sg_test() +/** \brief Test to see if all requests made within a synchronous group have completed. * - * test for sync group IO operations in progress + * # Examples * - * gid R sync group id + * ```c + * CA_SYNC_GID gid; + * status = ca_sg_test ( gid ); + * ``` * - * returns one of ECA_BADSYNCGRP, ECA_IOINPROGRESS, ECA_IODONE + * \param[in] gid Identifier of the synchronous group. + * + * \returns ::ECA_IODONE - IO operations completed + * \returns ::ECA_IOINPROGRESS - Some IO operations still in progress + * \returns ::ECA_BADSYNCGRP - Invalid synchronous group */ LIBCA_API int epicsStdCall ca_sg_test (const CA_SYNC_GID gid); -/* - * ca_sg_reset +/** \brief Reset the number of outstanding requests within the specified synchronous group to zero. * - * gid R sync group id + * So that ca_sg_test() will return ::ECA_IODONE and ca_sg_block() will not + * block unless additional subsequent requests are made. + * + * # Examples + * + * ```c + * CA_SYNC_GID gid; + * status = ca_sg_reset(gid); + * ``` + * + * \param[in] gid Identifier of the synchronous group. + * + * \returns ::ECA_NORMAL - Normal successful completion + * \returns ::ECA_BADSYNCGRP - Invalid synchronous group */ LIBCA_API int epicsStdCall ca_sg_reset(const CA_SYNC_GID gid); -/* - * ca_sg_array_get() + +/** \brief Read an array of values from a channel + * and increment the outstanding request count of a synchronous group. * - * initiate a get within a sync group - * (essentially a ca_array_get() with a sync group specified) + * The ca_sg_get() and ca_sg_array_get() functionality is implemented using + * ca_array_get_callback(). * - * gid R sync group id - * type R data type from db_access.h - * count R array element count - * chan R channel identifier - * pValue W channel value copied to this location + * The values written into your program's variables by ca_sg_get() or + * ca_sg_array_get() should not be referenced by your program until + * ::ECA_NORMAL has been received from ca_sg_block(), or until ca_sg_test() + * returns ::ECA_IODONE. + * + * All remote operation requests such as the above are accumulated (buffered) + * and not forwarded to the server until one of ca_flush_io(), ca_pend_io(), + * ca_pend_event(), or ca_sg_block() are called. This allows several requests + * to be efficiently sent in one message. + * + * If a connection is lost and then resumed outstanding gets are not reissued. + * + * \sa ca_sg_get(), ca_pend_io(), ca_flush_io(), ca_get_callback() + * + * \param[in] gid Identifier of the synchronous group. + * + * \param[in] type External type of returned value. + * Conversion will occur if this does not match native type. + * Specify one from the set of `DBR_XXXX` in `db_access.h`. + * + * \param[in] count Element count to be read from the specified channel. + * It must match the array pointed to by `pValue`. + * + * \param[in] chan Channel identifier. + * + * \param[out] pValue Pointer to application supplied buffer + * that is to contain the value or array of values to be returned. + * + * \returns ::ECA_NORMAL - Normal successful completion + * \returns ::ECA_BADSYNCGRP - Invalid synchronous group + * \returns ::ECA_BADCHID - Corrupted CHID + * \returns ::ECA_BADCOUNT - Requested count larger than native element count + * \returns ::ECA_BADTYPE - Invalid DBR_XXXX type + * \returns ::ECA_GETFAIL - A local database get failed */ LIBCA_API int epicsStdCall ca_sg_array_get ( @@ -749,20 +1705,68 @@ LIBCA_API int epicsStdCall ca_sg_array_get void *pValue ); +/** \brief Read a value from a channel + * and increment the outstanding request count of a synchronous group. + * + * See ca_sg_array_get() + * + * \param[in] gid Identifier of the synchronous group. + * + * \param[in] type External type of returned value. + * Conversion will occur if this does not match native type. + * Specify one from the set of `DBR_XXXX` in `db_access.h`. + * + * \param[in] chan Channel identifier. + * + * \param[out] pValue Pointer to application supplied buffer + * that is to contain the value or array of values to be returned. + * + * \returns ::ECA_NORMAL - Normal successful completion + * \returns ::ECA_BADSYNCGRP - Invalid synchronous group + * \returns ::ECA_BADCHID - Corrupted CHID + * \returns ::ECA_BADCOUNT - Requested count larger than native element count + * \returns ::ECA_BADTYPE - Invalid DBR_XXXX type + * \returns ::ECA_GETFAIL - A local database get failed + */ #define ca_sg_get(gid, type, chan, pValue) \ ca_sg_array_get (gid, type, 1u, chan, pValue) -/* - * ca_sg_array_put() +/** \brief Write an array of values to a channel + * and increment the outstanding request count of a synchronous group. * - * initiate a put within a sync group - * (essentially a ca_array_put() with a sync group specified) + * The ca_sg_put() and ca_sg_array_put() functionality is implemented using + * ca_array_put_callback(). * - * gid R sync group id - * type R data type from db_access.h - * count R array element count - * chan R channel identifier - * pValue R new channel value copied from this location + * All remote operation requests such as the above are accumulated (buffered) + * and not forwarded to the server until one of ca_flush_io(), ca_pend_io(), + * ca_pend_event(), or ca_sg_block() are called. This allows several requests + * to be efficiently sent in one message. + * + * If a connection is lost and then resumed outstanding puts are not reissued. + * + * \sa ca_sg_get(), ca_flush_io() + * + * \param[in] gid Identifier of the synchronous group. + * + * \param[in] type The type of supplied value. + * Conversion will occur if it does not match the native type. + * Specify one from the set of `DBR_XXXX` in `db_access.h`. + * + * \param[in] count Element count to be written to the specified channel. + * Must match the array pointed to by `pValue`. + * + * \param[in] chan Channel identifier. + * + * \param[out] pValue A pointer to an application supplied buffer + * containing the value or array of values returned. + * + * \returns ::ECA_NORMAL - Normal successful completion + * \returns ::ECA_BADSYNCGRP - Invalid synchronous group + * \returns ::ECA_BADCHID - Corrupted CHID + * \returns ::ECA_BADTYPE - Invalid DBR_XXXX type + * \returns ::ECA_BADCOUNT - Requested count larger than native element count + * \returns ::ECA_STRTOBIG - Unusually large string supplied + * \returns ::ECA_PUTFAIL - A local database put failed */ LIBCA_API int epicsStdCall ca_sg_array_put ( @@ -773,6 +1777,30 @@ LIBCA_API int epicsStdCall ca_sg_array_put const void *pValue ); +/** \brief Write a value to a channel + * and increment the outstanding request count of a synchronous group. + * + * See ca_sg_array_get(). + * + * \param[in] gid Identifier of the synchronous group. + * + * \param[in] type The type of supplied value. + * Conversion will occur if it does not match the native type. + * Specify one from the set of `DBR_XXXX` in `db_access.h`. + * + * \param[in] chan Channel identifier. + * + * \param[out] pValue A pointer to an application supplied buffer + * containing the value or array of values returned. + * + * \returns ::ECA_NORMAL - Normal successful completion + * \returns ::ECA_BADSYNCGRP - Invalid synchronous group + * \returns ::ECA_BADCHID - Corrupted CHID + * \returns ::ECA_BADTYPE - Invalid DBR_XXXX type + * \returns ::ECA_BADCOUNT - Requested count larger than native element count + * \returns ::ECA_STRTOBIG - Unusually large string supplied + * \returns ::ECA_PUTFAIL - A local database put failed + */ #define ca_sg_put(gid, type, chan, pValue) \ ca_sg_array_put (gid, type, 1u, chan, pValue) @@ -785,9 +1813,15 @@ ca_sg_array_put (gid, type, 1u, chan, pValue) */ LIBCA_API int epicsStdCall ca_sg_stat (CA_SYNC_GID gid); +/** \brief Dumps the specified dbr data type to standard out. + * + * \param[in] type The data type + * (from the `DBR_XXXX` set described in `db_access.h`). + * \param[in] count The array element count + * \param[in] pbuffer A pointer to data of the specified count and number. + */ LIBCA_API void epicsStdCall ca_dump_dbr (chtype type, unsigned count, const void * pbuffer); - /* * ca_v42_ok() * @@ -814,12 +1848,32 @@ LIBCA_API const char * epicsStdCall ca_version (void); * text output goes * * use two ifdef's for trad C compatibility - * - * ca_printf_func R pointer to new function called when - * CA prints an error message */ #ifndef CA_DONT_INCLUDE_STDARGH typedef int caPrintfFunc (const char *pformat, va_list args); + +/** \brief Replace the default handler for formatted diagnostic message output. + * + * The default handler uses fprintf to send messages to 'stderr'. + * + * \param[in] ca_printf_func A pointer to a user supplied callback handler + * to be invoked when CA prints diagnostic messages. + * Installing a null pointer will cause the default callback handler to be reinstalled. + * + * # Examples + * + * ```c + * int my_printf ( char *pformat, va_list args ) { + * int status; + * status = vfprintf( stderr, pformat, args); + * return status; + * } + * status = ca_replace_printf_handler ( my_printf ); + * SEVCHK ( status, "failed to install my printf handler" ); + * ``` + * + * \returns ::ECA_NORMAL - Normal successful completion + */ LIBCA_API int epicsStdCall ca_replace_printf_handler ( caPrintfFunc *ca_printf_func ); @@ -836,16 +1890,57 @@ LIBCA_API unsigned epicsStdCall ca_search_attempts (chid chan); LIBCA_API double epicsStdCall ca_beacon_period (chid chan); LIBCA_API double epicsStdCall ca_receive_watchdog_delay (chid chan); -/* - * used when an auxiliary thread needs to join a CA client context started +/** \brief Returns a pointer to the current thread's CA context. + * + * If none then null is returned. + * + * Used when an auxiliary thread needs to join a CA client context started * by another thread + * + * \sa ca_attach_context(), ca_detach_context(), ca_context_create(), ca_context_destroy() */ LIBCA_API struct ca_client_context * epicsStdCall ca_current_context (); + +/** \brief The calling thread becomes a member of the specified CA context. + * + * If ca_disable_preemptive_callback is specified when ca_context_create() is + * called (or if ca_task_initialize() is called) then additional threads are + * *not* allowed to join the CA context because allowing other threads to join + * implies that CA callbacks will be called preemptively from more than one + * thread. + * + * \sa ca_current_context(), ca_detach_context(), ca_context_create(), ca_context_destroy() + * + * \param[in] context A pointer to the CA context to join with. + * + * \returns ::ECA_NORMAL - Normal successful completion + * \returns ::ECA_NOTTHREADED - Context is not preemptive so cannot be joined + * \returns ::ECA_ISATTACHED - Thread already attached to a CA context + */ LIBCA_API int epicsStdCall ca_attach_context ( struct ca_client_context * context ); - +/** \brief Prints information about the client context. + * + * Including, at higher interest levels, status for each channel. Lacking a CA + * context pointer, ca_client_status() prints information about the calling + * threads CA context. + * + * \param[in] level The interest level. + * Increasing level produces increasing detail. + */ LIBCA_API int epicsStdCall ca_client_status ( unsigned level ); -LIBCA_API int epicsStdCall ca_context_status ( struct ca_client_context *, unsigned level ); + +/** \brief Prints information about the client context. + * + * Including, at higher interest levels, status for each channel. Lacking a CA + * context pointer, ca_client_status() prints information about the calling + * threads CA context. + * + * \param[in] context A pointer to the CA context to examine. + * \param[in] level The interest level. + * Increasing level produces increasing detail. + */ +LIBCA_API int epicsStdCall ca_context_status ( struct ca_client_context *context, unsigned level ); /* * deprecated @@ -857,15 +1952,39 @@ ca_build_and_connect(NAME, XXXXX, ZZZZZZ, CHIDPTR, YYYYY, 0, 0) LIBCA_API int epicsStdCall ca_build_and_connect ( const char *pChanName, chtype, unsigned long, chid * pChanID, void *, caCh * pFunc, void * pArg ); + +/** \brief Search for a channel over Channel Access. + * + * \deprecated Use ca_create_channel() instead. + */ #define ca_search(pChanName, pChanID)\ ca_search_and_connect (pChanName, pChanID, 0, 0) + +/** \brief Search and connect to a channel over Channel Access. + * + * \deprecated Use ca_create_channel() instead. + */ LIBCA_API int epicsStdCall ca_search_and_connect ( const char * pChanName, chid * pChanID, caCh *pFunc, void * pArg ); + LIBCA_API int epicsStdCall ca_channel_status (epicsThreadId tid); + +/** \brief Cancel a subscription. + * + * \deprecated Use ca_clear_subscription() instead. + */ LIBCA_API int epicsStdCall ca_clear_event ( evid eventID ); + +/** \brief Register a state change subscription and specify a callback function + * to be invoked whenever the process variable undergoes significant state + * changes. + * + * \deprecated Use ca_create_subscription() instead. + */ #define ca_add_event(type,chan,pFunc,pArg,pEventID)\ ca_add_array_event(type,1u,chan,pFunc,pArg,0.0,0.0,0.0,pEventID) + #define ca_add_delta_event(TYPE,CHID,ENTRY,ARG,DELTA,EVID)\ ca_add_array_event(TYPE,1,CHID,ENTRY,ARG,DELTA,DELTA,0.0,EVID) #define ca_add_general_event(TYPE,CHID,ENTRY,ARG,P_DELTA,N_DELTA,TO,EVID)\ diff --git a/modules/ca/src/client/caerr.h b/modules/ca/src/client/caerr.h index bc6f654d1..95df2cebc 100644 --- a/modules/ca/src/client/caerr.h +++ b/modules/ca/src/client/caerr.h @@ -19,6 +19,10 @@ * */ +/** \file caerr.h + * + * \brief Channel access error definitions. + */ #ifndef INC_caerr_H #define INC_caerr_H @@ -75,72 +79,139 @@ * servers on earlier releases that communicate with current clients * might still generate exceptions with these error constants */ + +/// Normal successful completion #define ECA_NORMAL DEFMSG(CA_K_SUCCESS, 0) /* success */ +/// Maximum simultaneous IOC connections exceeded #define ECA_MAXIOC DEFMSG(CA_K_ERROR, 1) /* defunct */ +/// Unknown internet host #define ECA_UKNHOST DEFMSG(CA_K_ERROR, 2) /* defunct */ +/// Unknown internet service #define ECA_UKNSERV DEFMSG(CA_K_ERROR, 3) /* defunct */ +/// Unable to allocate a new socket #define ECA_SOCK DEFMSG(CA_K_ERROR, 4) /* defunct */ +/// Unable to connect to internet host or service #define ECA_CONN DEFMSG(CA_K_WARNING, 5) /* defunct */ +/// Unable to allocate additional dynamic memory #define ECA_ALLOCMEM DEFMSG(CA_K_WARNING, 6) +/// Unknown IO channel #define ECA_UKNCHAN DEFMSG(CA_K_WARNING, 7) /* defunct */ +/// ECA_UKNFIELD - Record field specified inappropriate for channel specified #define ECA_UKNFIELD DEFMSG(CA_K_WARNING, 8) /* defunct */ +/// The requested data transfer is greater than available memory or EPICS_CA_MAX_ARRAY_BYTES #define ECA_TOLARGE DEFMSG(CA_K_WARNING, 9) +/// User specified timeout on IO operation expired #define ECA_TIMEOUT DEFMSG(CA_K_WARNING, 10) +/// Sorry, that feature is planned but not supported at this time #define ECA_NOSUPPORT DEFMSG(CA_K_WARNING, 11) /* defunct */ +/// The supplied string is unusually large #define ECA_STRTOBIG DEFMSG(CA_K_WARNING, 12) /* defunct */ +/// The request was ignored because the specified channel is disconnected #define ECA_DISCONNCHID DEFMSG(CA_K_ERROR, 13) /* defunct */ +/// The data type specifed is invalid #define ECA_BADTYPE DEFMSG(CA_K_ERROR, 14) +/// Remote Channel not found #define ECA_CHIDNOTFND DEFMSG(CA_K_INFO, 15) /* defunct */ +/// Unable to locate all user specified channels #define ECA_CHIDRETRY DEFMSG(CA_K_INFO, 16) /* defunct */ +/// Channel Access Internal Failure #define ECA_INTERNAL DEFMSG(CA_K_FATAL, 17) +/// The requested local DB operation failed #define ECA_DBLCLFAIL DEFMSG(CA_K_WARNING, 18) /* defunct */ +/// Channel read request failed #define ECA_GETFAIL DEFMSG(CA_K_WARNING, 19) +/// Channel write request failed #define ECA_PUTFAIL DEFMSG(CA_K_WARNING, 20) +/// Channel subscription request failed #define ECA_ADDFAIL DEFMSG(CA_K_WARNING, 21) /* defunct */ +/// Invalid element count requested #define ECA_BADCOUNT DEFMSG(CA_K_WARNING, 22) +/// Invalid string #define ECA_BADSTR DEFMSG(CA_K_ERROR, 23) +/// Virtual circuit disconnect #define ECA_DISCONN DEFMSG(CA_K_WARNING, 24) +/// Identical process variable names on multiple servers #define ECA_DBLCHNL DEFMSG(CA_K_WARNING, 25) +/// Request inappropriate within subscription (monitor) update callback #define ECA_EVDISALLOW DEFMSG(CA_K_ERROR, 26) +/// Database value get for that channel failed during channel search #define ECA_BUILDGET DEFMSG(CA_K_WARNING, 27) /* defunct */ +/// Unable to initialize without the vxWorks VX_FP_TASK task option set #define ECA_NEEDSFP DEFMSG(CA_K_WARNING, 28) /* defunct */ +/// Event queue overflow has prevented first pass event after event add #define ECA_OVEVFAIL DEFMSG(CA_K_WARNING, 29) /* defunct */ +/// Bad event subscription (monitor) identifier #define ECA_BADMONID DEFMSG(CA_K_ERROR, 30) +/// Remote channel has new network address #define ECA_NEWADDR DEFMSG(CA_K_WARNING, 31) /* defunct */ +/// New or resumed network connection #define ECA_NEWCONN DEFMSG(CA_K_INFO, 32) /* defunct */ +/// Specified task isnt a member of a CA context #define ECA_NOCACTX DEFMSG(CA_K_WARNING, 33) /* defunct */ +/// Attempt to use defunct CA feature failed #define ECA_DEFUNCT DEFMSG(CA_K_FATAL, 34) /* defunct */ +/// The supplied string is empty #define ECA_EMPTYSTR DEFMSG(CA_K_WARNING, 35) /* defunct */ +/// Unable to spawn the CA repeater thread- auto reconnect will fail #define ECA_NOREPEATER DEFMSG(CA_K_WARNING, 36) /* defunct */ +/// No channel id match for search reply- search reply ignored #define ECA_NOCHANMSG DEFMSG(CA_K_WARNING, 37) /* defunct */ +/// Reseting dead connection- will try to reconnect #define ECA_DLCKREST DEFMSG(CA_K_WARNING, 38) /* defunct */ +/// Server (IOC) has fallen behind or is not responding- still waiting #define ECA_SERVBEHIND DEFMSG(CA_K_WARNING, 39) /* defunct */ +/// No internet interface with broadcast available #define ECA_NOCAST DEFMSG(CA_K_WARNING, 40) /* defunct */ +/// Invalid event selection mask #define ECA_BADMASK DEFMSG(CA_K_ERROR, 41) +/// IO operations have completed #define ECA_IODONE DEFMSG(CA_K_INFO, 42) +/// IO operations are in progress #define ECA_IOINPROGRESS DEFMSG(CA_K_INFO, 43) +/// Invalid synchronous group identifier #define ECA_BADSYNCGRP DEFMSG(CA_K_ERROR, 44) +/// Put callback timed out #define ECA_PUTCBINPROG DEFMSG(CA_K_ERROR, 45) +/// Read access denied #define ECA_NORDACCESS DEFMSG(CA_K_WARNING, 46) +/// Write access denied #define ECA_NOWTACCESS DEFMSG(CA_K_WARNING, 47) +/// Requested feature is no longer supported #define ECA_ANACHRONISM DEFMSG(CA_K_ERROR, 48) +/// Empty PV search address list #define ECA_NOSEARCHADDR DEFMSG(CA_K_WARNING, 49) +/// No reasonable data conversion between client and server types #define ECA_NOCONVERT DEFMSG(CA_K_WARNING, 50) +/// Invalid channel identifier #define ECA_BADCHID DEFMSG(CA_K_ERROR, 51) +/// Invalid function pointer #define ECA_BADFUNCPTR DEFMSG(CA_K_ERROR, 52) +/// Thread is already attached to a client context #define ECA_ISATTACHED DEFMSG(CA_K_WARNING, 53) +/// Not supported by attached service #define ECA_UNAVAILINSERV DEFMSG(CA_K_WARNING, 54) +/// User destroyed channel #define ECA_CHANDESTROY DEFMSG(CA_K_WARNING, 55) +/// Invalid channel priority #define ECA_BADPRIORITY DEFMSG(CA_K_ERROR, 56) +/// Preemptive callback not enabled - additional threads may not join context #define ECA_NOTTHREADED DEFMSG(CA_K_ERROR, 57) +/// Client's protocol revision does not support transfers exceeding 16k bytes #define ECA_16KARRAYCLIENT DEFMSG(CA_K_WARNING, 58) +/// Virtual circuit connection sequence aborted #define ECA_CONNSEQTMO DEFMSG(CA_K_WARNING, 59) +/// Virtual circuit unresponsive #define ECA_UNRESPTMO DEFMSG(CA_K_WARNING, 60) #ifdef __cplusplus extern "C" { #endif +/** \brief Return a message character string corresponding to a user specified CA status code. + * + * \param[in] ca_status A CA status code. + * \returns The corresponding error message string. + */ LIBCA_API const char * epicsStdCall ca_message(long ca_status); LIBCA_API extern const char * ca_message_text []; diff --git a/modules/ca/src/client/caeventmask.h b/modules/ca/src/client/caeventmask.h index 949f2743b..adf298ea9 100644 --- a/modules/ca/src/client/caeventmask.h +++ b/modules/ca/src/client/caeventmask.h @@ -8,37 +8,43 @@ * in file LICENSE that is included with this distribution. \*************************************************************************/ +/** \file caeventmask.h + * + * \brief Event selections + */ + #ifndef INCLcaeventmaskh #define INCLcaeventmaskh /* - event selections (If any more than 8 of these are needed then update the select field in the event_block struct in db_event.c from unsigned char to unsigned short) + */ - - DBE_VALUE - Trigger an event when a significant change in the channel's value - occurs. Relies on the monitor deadband field under DCT. - - DBE_ARCHIVE (DBE_LOG) - Trigger an event when an archive significant change in the channel's - value occurs. Relies on the archiver monitor deadband field under DCT. - - DBE_ALARM - Trigger an event when the alarm state changes - - DBE_PROPERTY - Trigger an event when a property change (control limit, graphical - limit, status string, enum string ...) occurs. - -*/ - +/** \brief Trigger an event when a significant change in the channel's value occurs. + * + * Relies on the monitor deadband field under DCT. + */ #define DBE_VALUE (1<<0) + +/** \brief Trigger an event when an archive significant change in the channel's value occurs. + * + * Relies on the archiver monitor deadband field under DCT. + */ #define DBE_ARCHIVE (1<<1) + +/** \brief Same as ::DBE_ARCHIVE. + */ #define DBE_LOG DBE_ARCHIVE + +/** \brief Trigger an event when the alarm state changes. + */ #define DBE_ALARM (1<<2) + +/** \brief Trigger an event when a property change occurs. + * (control limit, graphical limit, status string, enum string ...) + */ #define DBE_PROPERTY (1<<3) #endif diff --git a/modules/ca/src/client/db_access.h b/modules/ca/src/client/db_access.h index cca17a512..0fd9c5691 100644 --- a/modules/ca/src/client/db_access.h +++ b/modules/ca/src/client/db_access.h @@ -516,13 +516,40 @@ struct dbr_ctrl_double{ dbr_double_t value; /* current value */ }; +/** \brief Returns the size in bytes for a `DBR_XXXX` type with `COUNT` elements. + * + * If the DBR type is a structure then the value field is the last field in the + * structure. If `COUNT` is greater than one then `COUNT-1` elements are + * appended to the end of the structure so that they can be addressed as an + * array through a pointer to the value field. + * + * \sa dbr_size, dbr_value_size + * + * \param[in] TYPE The data type. + * \param[in] COUNT The element count. + * \returns The size in bytes of the specified type + * with the specified number of elements. + */ #define dbr_size_n(TYPE,COUNT)\ ((unsigned)((COUNT)<0?dbr_size[TYPE]:dbr_size[TYPE]+((COUNT)-1)*dbr_value_size[TYPE])) -/* size for each type - array indexed by the DBR_ type code */ +/** \brief Size in bytes for each `DBR_XXXX` type. + * + * Array indexed by the `DBR_XXXX` type code. + * + * \sa dbr_size_n() + */ LIBCA_API extern const unsigned short dbr_size[]; -/* size for each type's value - array indexed by the DBR_ type code */ +/** \brief Size in bytes for each type's value. + * + * Array indexed by the `DBR_XXXX` type code. + * + * If the type is a structure the size of the value field is returned otherwise + * the size of the type is returned. + * + * \sa dbr_size_n() + */ LIBCA_API extern const unsigned short dbr_value_size[]; #ifndef db_accessHFORdb_accessC @@ -685,6 +712,14 @@ union db_access_val{ break; \ } +/** \brief Returns a constant null terminated string + * corresponding to the specified dbr type. + * + * \param[in] type The data type code. + * A member of the set of `DBR_XXXX` in `db_access.h`. + * + * \returns The const string corresponding to the `DBR_XXXX` type. + */ #define dbr_type_to_text(type) \ ( ((type) >= 0 && (type) < dbr_text_dim) ? \ dbr_text[(type)] : dbr_text_invalid )