From d3c5e5dc07682fc37b6197d9f8425d90ba9f5393 Mon Sep 17 00:00:00 2001 From: "ben.franksen" <ben.franksen@online.de> Date: Fri, 12 Jul 2013 16:18:13 +0000 Subject: [PATCH] reduce pv layer to what is needed: a thin wrapper around CA client API This patch gets rid of most of the pv layer, including all remaining C++ code. Also removed is the C++ test/example code for the pv layer. The interface (pv.h) is not the same, but similar; mostly it is much simpler and more statically typed. --- src/pv/Makefile | 45 +- src/pv/pv.c | 306 +++++++++ src/pv/pv.cc | 560 ---------------- src/pv/pv.h | 374 ++--------- src/pv/pvAlarm.h | 11 - src/pv/pvCa.cc | 871 ------------------------- src/pv/pvCa.h | 119 ---- src/pv/pvFile.cc | 337 ---------- src/pv/pvFile.h | 82 --- src/pv/pvKtl.cc | 1416 ----------------------------------------- src/pv/pvKtl.h | 273 -------- src/pv/pvKtlCnv.cc | 295 --------- src/pv/pvKtlCnv.h | 55 -- src/pv/pvNew.cc | 49 -- src/pv/pvType.h | 69 +- src/seq/seqCom.h | 1 - src/seq/seqPvt.h | 25 +- src/seq/seq_ca.c | 115 ++-- src/seq/seq_if.c | 19 +- src/seq/seq_main.c | 14 - src/seq/seq_prog.c | 17 +- src/seq/seq_task.c | 11 +- test/Makefile | 1 - test/pv/Makefile | 30 - test/pv/arrput.cc | 52 -- test/pv/arrputCA.cc | 43 -- test/pv/pvsimpleC.c | 59 -- test/pv/pvsimpleCC.cc | 56 -- test/pv/pvtest.cc | 108 ---- 29 files changed, 450 insertions(+), 4963 deletions(-) create mode 100644 src/pv/pv.c delete mode 100644 src/pv/pv.cc delete mode 100644 src/pv/pvCa.cc delete mode 100644 src/pv/pvCa.h delete mode 100644 src/pv/pvFile.cc delete mode 100644 src/pv/pvFile.h delete mode 100644 src/pv/pvKtl.cc delete mode 100644 src/pv/pvKtl.h delete mode 100644 src/pv/pvKtlCnv.cc delete mode 100644 src/pv/pvKtlCnv.h delete mode 100644 src/pv/pvNew.cc delete mode 100644 test/pv/Makefile delete mode 100644 test/pv/arrput.cc delete mode 100644 test/pv/arrputCA.cc delete mode 100644 test/pv/pvsimpleC.c delete mode 100644 test/pv/pvsimpleCC.cc delete mode 100644 test/pv/pvtest.cc diff --git a/src/pv/Makefile b/src/pv/Makefile index 4e1f058d..0ff3a94e 100644 --- a/src/pv/Makefile +++ b/src/pv/Makefile @@ -4,54 +4,17 @@ include $(TOP)/configure/CONFIG #---------------------------------------- # ADD MACRO DEFINITIONS AFTER THIS LINE -#---------------------------------------- -# Message system-independent support - -INC += pv.h pvAlarm.h pvType.h +INC += pv.h pvAlarm.h pvType.h LIBRARY += pv -pv_SRCS += pvNew.cc pv.cc + +pv_SRCS += pv.c pv_LIBS += ca Com # For R3.13 compatibility only -OBJLIB_vxWorks=pv +OBJLIB_vxWorks = pv OBJLIB_SRCS = $(pv_SRCS) -#---------------------------------------- -# KTL (Keck Task Library) supported? (never under VxWorks) -ifeq "$(PVKTL)" "TRUE" - -USR_CPPFLAGS_vxWorks += -nil- -USR_CPPFLAGS_DEFAULT += -DPVKTL -USR_INCLUDES_vxWorks += -nil- -USR_INCLUDES_DEFAULT += -I$(KROOT)/rel/default/include - -pv_SRCS_vxWorks += -nil- -pv_SRCS_DEFAULT += pvKtl.cc pvKtlCnv.cc - -endif - -#---------------------------------------- -# CA (Channel Access) supported? also link into pvLibrary under VxWorks -ifeq "$(PVCA)" "TRUE" - -USR_CPPFLAGS += -DPVCA - -pv_SRCS += pvCa.cc - -endif - -#---------------------------------------- -# FILE (Demo File... from the manual) supported? -ifeq "$(PVFILE)" "TRUE" - -USR_CPPFLAGS += -DPVFILE - -pv_SRCS += pvFile.cc - -endif - include $(TOP)/configure/RULES #---------------------------------------- # ADD RULES AFTER THIS LINE - diff --git a/src/pv/pv.c b/src/pv/pv.c new file mode 100644 index 00000000..a16f0270 --- /dev/null +++ b/src/pv/pv.c @@ -0,0 +1,306 @@ +#include <assert.h> +#include <limits.h> + +#include "errlog.h" +#include "cadef.h" + +#define epicsExportSharedSymbols +#include "pv.h" + +#define INVOKE(expr) \ + {\ + int _status = expr;\ + if (!(_status & CA_M_SUCCESS)) {\ + errlogSevPrintf(sevrFromCA(_status), "%s: %s", #expr, ca_message(_status));\ + return statFromCA(_status);\ + }\ + } + +epicsShareDef const struct pvSystem nullPvSys = {NULL}; +epicsShareDef const struct pvVar nullPvVar = {NULL,NULL,NULL,NULL,NULL,NULL}; + +/* utilities */ +static pvSevr sevrFromCA(long status); /* CA severity as pvSevr */ +static pvStat statFromCA(long status); /* CA status as pvStat */ +static pvType typeFromCA(long type); /* DBR type as pvType */ +static chtype typeToCA(pvType type); /* pvType as DBR type */ + +epicsShareFunc pvStat pvSysCreate(pvSystem *pSys) +{ + assert(pSys); + assert(!ca_current_context()); + INVOKE(ca_context_create(ca_enable_preemptive_callback)); + pSys->id = ca_current_context(); + return pvStatOK; +} + +epicsShareFunc pvStat pvSysFlush(pvSystem sys) +{ + INVOKE(ca_flush_io()); + return pvStatOK; +} + +epicsShareFunc pvStat pvSysAttach(pvSystem sys) +{ + if (!ca_current_context()) + INVOKE(ca_attach_context(sys.id)); + return pvStatOK; +} + +static void pvCaConnectionHandler(struct connection_handler_args args) +{ + pvVar *var = (pvVar *)ca_puser(args.chid); + var->conn_handler(args.op == CA_OP_CONN_UP, var->arg); +} + +epicsShareFunc pvStat pvVarCreate(pvSystem sys, const char *name, + pvConnFunc *conn_func, pvEventFunc *event_func, void *arg, pvVar *var) +{ + assert(var); + var->conn_handler = conn_func; + var->event_handler = event_func; + var->arg = arg; + INVOKE(ca_create_channel(name, pvCaConnectionHandler, var, CA_PRIORITY_DEFAULT, &var->chid)); + return pvStatOK; +} + +epicsShareFunc pvStat pvVarDestroy(pvVar *var) +{ + assert(var); + INVOKE(ca_clear_channel(var->chid)); + *var = nullPvVar; + return pvStatOK; +} + +static void pvCaEventHandler(struct event_handler_args args, pvEventType evt) +{ + pvVar *var = (pvVar *)ca_puser(args.chid); + unsigned count = (unsigned)args.count; + assert(args.count >= 0); + assert((long)count == args.count); + var->event_handler(evt, args.usr, typeFromCA(args.type), count, (pvValue*)args.dbr, statFromCA(args.status)); +} + +static void pvCaGetHandler(struct event_handler_args args) +{ + pvCaEventHandler(args, pvEventGet); +} + +static void pvCaPutHandler(struct event_handler_args args) +{ + pvCaEventHandler(args, pvEventPut); +} + +static void pvCaMonitorHandler(struct event_handler_args args) +{ + pvCaEventHandler(args, pvEventMonitor); +} + +epicsShareFunc pvStat pvVarGetCallback(pvVar *var, pvType type, unsigned count, void *arg) +{ + assert(var); + assert(pv_is_valid_type(type)); + INVOKE(ca_array_get_callback( + typeToCA(type), count, var->chid, pvCaGetHandler, arg)); + return pvStatOK; +} + +epicsShareFunc pvStat pvVarPutNoBlock(pvVar *var, pvType type, unsigned count, pvValue *value) +{ + assert(var); + assert(pv_is_simple_type(type)); + INVOKE(ca_array_put(typeToCA(type), count, var->chid, value)); + return pvStatOK; +} + +epicsShareFunc pvStat pvVarPutCallback(pvVar *var, pvType type, unsigned count, pvValue *value, void *arg) +{ + assert(var); + assert(pv_is_simple_type(type)); + INVOKE(ca_array_put_callback( + typeToCA(type), count, var->chid, value, pvCaPutHandler, arg)); + return pvStatOK; +} + +epicsShareFunc pvStat pvVarMonitorOn(pvVar *var, pvType type, unsigned count, void *arg) +{ + assert(var); + assert(pv_is_valid_type(type)); + if (var->monid == NULL) { + INVOKE(ca_create_subscription(typeToCA(type), count, var->chid, + DBE_VALUE | DBE_ALARM, pvCaMonitorHandler, arg, &var->monid)); + } + return pvStatOK; +} + +epicsShareFunc pvStat pvVarMonitorOff(pvVar *var) +{ + assert(var); + if (var->monid != NULL) { + INVOKE(ca_clear_event(var->monid)); + var->monid = NULL; + } + return pvStatOK; +} + +epicsShareFunc unsigned pvVarGetCount(pvVar *var) +{ + unsigned long c = ca_element_count(var->chid); + assert(c <= UINT_MAX); + return (unsigned)c; +} + +epicsShareFunc int pvTimeGetCurrentDouble(double *pTime) +{ + epicsTimeStamp stamp; + + assert(pTime); + *pTime = 0.0; + if (epicsTimeGetCurrent(&stamp) == epicsTimeERROR) + return pvStatERROR; + + *pTime = (double) stamp.secPastEpoch + ((double) stamp.nsec / 1e9); + return pvStatOK; +} + +#include "alarm.h" + +static pvSevr sevrFromCA(long status) +{ + switch (CA_EXTRACT_SEVERITY(status)) { + case CA_K_INFO: return pvSevrNONE; + case CA_K_SUCCESS: return pvSevrNONE; + case CA_K_WARNING: return pvSevrMINOR; + case CA_K_ERROR: return pvSevrMAJOR; + case CA_K_SEVERE: return pvSevrINVALID; + default: return pvSevrERROR; + } +} + +static pvStat statFromCA(long status) +{ + pvSevr sevr = sevrFromCA(status); + return (sevr == pvSevrNONE || sevr == pvSevrMINOR) ? + pvStatOK : pvStatERROR; +} + +static pvType typeFromCA(long type) +{ + switch (type) { + case DBR_CHAR: return pvTypeCHAR; + case DBR_SHORT: return pvTypeSHORT; + case DBR_ENUM: return pvTypeSHORT; + case DBR_LONG: return pvTypeLONG; + case DBR_FLOAT: return pvTypeFLOAT; + case DBR_DOUBLE: return pvTypeDOUBLE; + case DBR_STRING: return pvTypeSTRING; + case DBR_TIME_CHAR: return pvTypeTIME_CHAR; + case DBR_TIME_SHORT: return pvTypeTIME_SHORT; + case DBR_TIME_ENUM: return pvTypeTIME_SHORT; + case DBR_TIME_LONG: return pvTypeTIME_LONG; + case DBR_TIME_FLOAT: return pvTypeTIME_FLOAT; + case DBR_TIME_DOUBLE: return pvTypeTIME_DOUBLE; + case DBR_TIME_STRING: return pvTypeTIME_STRING; + default: return pvTypeERROR; + } +} + +static chtype typeToCA(pvType type) +{ + switch (type) { + case pvTypeCHAR: return DBR_CHAR; + case pvTypeSHORT: return DBR_SHORT; + case pvTypeLONG: return DBR_LONG; + case pvTypeFLOAT: return DBR_FLOAT; + case pvTypeDOUBLE: return DBR_DOUBLE; + case pvTypeSTRING: return DBR_STRING; + case pvTypeTIME_CHAR: return DBR_TIME_CHAR; + case pvTypeTIME_SHORT: return DBR_TIME_SHORT; + case pvTypeTIME_LONG: return DBR_TIME_LONG; + case pvTypeTIME_FLOAT: return DBR_TIME_FLOAT; + case pvTypeTIME_DOUBLE: return DBR_TIME_DOUBLE; + case pvTypeTIME_STRING: return DBR_TIME_STRING; + default: return -1; + } +} + +#include "db_access.h" + +typedef struct dbr_time_char pvTimeChar; +typedef struct dbr_time_short pvTimeShort; +typedef struct dbr_time_long pvTimeLong; +typedef struct dbr_time_float pvTimeFloat; +typedef struct dbr_time_double pvTimeDouble; +typedef struct dbr_time_string pvTimeString; + +epicsShareDef const size_t pv_sizes[] = { + sizeof(pvChar ), + sizeof(pvShort ), + sizeof(pvLong ), + sizeof(pvFloat ), + sizeof(pvDouble ), + sizeof(pvString ), + sizeof(pvTimeChar ), + sizeof(pvTimeShort ), + sizeof(pvTimeLong ), + sizeof(pvTimeFloat ), + sizeof(pvTimeDouble), + sizeof(pvTimeString), +}; + +epicsShareDef const size_t pv_value_sizes[] = { + sizeof(pvChar ), + sizeof(pvShort ), + sizeof(pvLong ), + sizeof(pvFloat ), + sizeof(pvDouble), + sizeof(pvString), + sizeof(pvChar ), + sizeof(pvShort ), + sizeof(pvLong ), + sizeof(pvFloat ), + sizeof(pvDouble), + sizeof(pvString), +}; + +epicsShareDef const size_t pv_value_offsets[] = { + 0, + 0, + 0, + 0, + 0, + 0, + offsetof(pvTimeChar , value), + offsetof(pvTimeShort , value), + offsetof(pvTimeLong , value), + offsetof(pvTimeFloat , value), + offsetof(pvTimeDouble, value), + offsetof(pvTimeString, value), +}; + +epicsShareDef const size_t pv_status_offsets[] = { + offsetof(pvTimeChar , status), + offsetof(pvTimeShort , status), + offsetof(pvTimeLong , status), + offsetof(pvTimeFloat , status), + offsetof(pvTimeDouble, status), + offsetof(pvTimeString, status), +}; + +epicsShareDef const size_t pv_severity_offsets[] = { + offsetof(pvTimeChar , severity), + offsetof(pvTimeShort , severity), + offsetof(pvTimeLong , severity), + offsetof(pvTimeFloat , severity), + offsetof(pvTimeDouble, severity), + offsetof(pvTimeString, severity), +}; + +epicsShareDef const size_t pv_stamp_offsets[] = { + offsetof(pvTimeChar , stamp), + offsetof(pvTimeShort , stamp), + offsetof(pvTimeLong , stamp), + offsetof(pvTimeFloat , stamp), + offsetof(pvTimeDouble, stamp), + offsetof(pvTimeString, stamp), +}; diff --git a/src/pv/pv.cc b/src/pv/pv.cc deleted file mode 100644 index bc5c2d76..00000000 --- a/src/pv/pv.cc +++ /dev/null @@ -1,560 +0,0 @@ -/* Implementation of EPICS sequencer message system-independent library (pv) - * (NB, "pv" = "process variable"). - * - * William Lupton, W. M. Keck Observatory - */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <epicsString.h> - -#define epicsExportSharedSymbols -#include "pv.h" - -//////////////////////////////////////////////////////////////////////////////// -/*+ - * Routine: pvSystem::pvSystem - * - * Purpose: pvSystem constructor - * - * Description: - */ -pvSystem::pvSystem( int debug ) : - - magic_( PV_MAGIC ), - debug_( debug ), - status_( 0 ), - sevr_( pvSevrNONE ), - stat_( pvStatOK ), - mess_( NULL ) -#if 0 - ,lock_( epicsMutexMustCreate() ) -#endif -{ - if ( getDebug() > 0 ) - printf( "%8p: pvSystem::pvSystem( %d )\n", (void *)this, debug ); -} - -/*+ - * Routine: pvSystem::~pvSystem - * - * Purpose: pvSystem destructor - * - * Description: - */ -pvSystem::~pvSystem() -{ - if ( getDebug() > 0 ) - printf( "%8p: pvSystem::~pvSystem()\n", (void *)this ); -} - -#if 0 -/*+ - * Routine: pvSystem::lock()/unlock() - * - * Purpose: Take/give lock - * - * Description: - * - * Function value: - */ -void pvSystem::lock() -{ - epicsMutexMustLock( lock_ ); - - if ( getDebug() > 1 ) - printf( "%8p: pvSystem::lock()\n", (void *)this ); -} - -void pvSystem::unlock() -{ - epicsMutexUnlock( lock_ ); - - if ( getDebug() > 1 ) - printf( "%8p: pvSystem::unlock()\n", (void *)this ); -} -#endif - -/*+ - * Routine: pvSystem::setError() - * - * Purpose: Copy error information - * - * Description: - * - * Function value: - */ -void pvSystem::setError( int status, pvSevr sevr, pvStat stat, - const char *mess ) -{ - status_ = status; - sevr_ = sevr; - stat_ = stat; - mess_ = mess; -} - -//////////////////////////////////////////////////////////////////////////////// -/*+ - * Routine: pvVariable::pvVariable - * - * Purpose: pvVariable constructor - * - * Description: - */ -pvVariable::pvVariable( pvSystem *system, const char *name, pvConnFunc func, - void *priv, int debug ) : - magic_( PV_MAGIC ), - debug_( debug ), - func_( func ), - system_( system ), - name_( epicsStrDup( name ) ), - private_( priv ), - status_( 0 ), - sevr_( pvSevrNONE ), - stat_( pvStatOK ), - mess_( NULL ) -{ - if ( getDebug() == 0 ) - setDebug( system->getDebug() ); - - if ( getDebug() > 0 ) - printf( "%8p: pvVariable::pvVariable( %s, %d )\n", - (void *)this, name, debug ); -} - -/*+ - * Routine: pvVariable::~pvVariable - * - * Purpose: pvVariable destructor - * - * Description: - */ -pvVariable::~pvVariable() -{ - if ( getDebug() > 0 ) - printf( "%8p: pvVariable::~pvVariable()\n", (void *)this ); - - if ( name_ != NULL ) - free( name_ ); -} - -/*+ - * Routine: pvVariable::setError() - * - * Purpose: Copy error information - * - * Description: - * - * Function value: - */ -void pvVariable::setError( int status, pvSevr sevr, pvStat stat, - const char *mess ) -{ - status_ = status; - sevr_ = sevr; - stat_ = stat; - mess_ = mess; -} - -//////////////////////////////////////////////////////////////////////////////// -/*+ - * Routine: pvCallback::pvCallback - * - * Purpose: pvCallback constructor - * - * Description: - */ -pvCallback::pvCallback( pvVariable *variable, pvType type, unsigned count, - pvEventFunc func, void *arg, int debug ) : - magic_( PV_MAGIC ), - debug_( debug ), - variable_( variable ), - type_( type ), - count_( count ), - func_( func ), - arg_( arg ), - private_( NULL ) -{ - // should be associated with a system? - if ( getDebug() > 0 ) - printf( "%8p: pvCallback::pvCallback( %d, %d, %p, %p, %d )\n", - (void *)this, type, count, (void *)func, arg, debug ); -} - -/*+ - * Routine: pvCallback::~pvCallback - * - * Purpose: pvCallback destructor - * - * Description: - */ -pvCallback::~pvCallback() -{ - if ( getDebug() > 0 ) - printf( "%8p: pvCallback::~pvCallback()\n", (void *)this ); -} - -//epicsSingleton < tsFreeList < class pvCallback > > pvCallback::pFreeList; - -//////////////////////////////////////////////////////////////////////////////// -/* C interface */ - -#define SYS_CHECK(_erract) \ - pvSystem *Sys = ( pvSystem * ) sys; \ - if ( Sys == NULL || Sys->getMagic() != PV_MAGIC ) \ - _erract - -epicsShareFunc pvStat epicsShareAPI pvSysCreate( const char *name, int debug, void **pSys ) { - *pSys = newPvSystem( name, debug ); - return ( *pSys == NULL ) ? pvStatERROR : pvStatOK; -} - -epicsShareFunc pvStat epicsShareAPI pvSysDestroy( void *sys ) { - SYS_CHECK( return pvStatERROR ); - delete Sys; - return pvStatOK; -} - -epicsShareFunc pvStat epicsShareAPI pvSysAttach( void *sys ) { - SYS_CHECK( return pvStatERROR ); - return Sys->attach(); -} - -epicsShareFunc pvStat epicsShareAPI pvSysFlush( void *sys ) { - SYS_CHECK( return pvStatERROR ); - return Sys->flush(); -} - -epicsShareFunc pvStat epicsShareAPI pvSysPend( void *sys, double seconds, int wait ) { - SYS_CHECK( return pvStatERROR ); - return Sys->pend( seconds, wait ); -} - -#if 0 -epicsShareFunc pvStat epicsShareAPI pvSysLock( void *sys ) { - SYS_CHECK( return pvStatERROR ); - Sys->lock(); - return pvStatOK; -} - -epicsShareFunc pvStat epicsShareAPI pvSysUnlock( void *sys ) { - SYS_CHECK( return pvStatERROR ); - Sys->unlock(); - return pvStatOK; -} -#endif - -epicsShareFunc int epicsShareAPI pvSysGetMagic( void *sys ) { - SYS_CHECK( return pvStatERROR ); - return Sys->getMagic(); -} - -epicsShareFunc void epicsShareAPI pvSysSetDebug( void *sys, int debug ) { - SYS_CHECK( {} ); - Sys->setDebug( debug ); -} - -epicsShareFunc int epicsShareAPI pvSysGetDebug( void *sys ) { - SYS_CHECK( return pvStatERROR ); - return Sys->getDebug(); -} - -epicsShareFunc int epicsShareAPI pvSysGetStatus( void *sys ) { - SYS_CHECK( return pvStatERROR ); - return Sys->getStatus(); -} - -epicsShareFunc pvSevr epicsShareAPI pvSysGetSevr( void *sys ) { - SYS_CHECK( return pvSevrERROR ); - return Sys->getSevr(); -} - -epicsShareFunc pvStat epicsShareAPI pvSysGetStat( void *sys ) { - SYS_CHECK( return pvStatERROR ); - return Sys->getStat(); -} - -epicsShareFunc const char * epicsShareAPI pvSysGetMess( void *sys ) { - SYS_CHECK( return "" ); - return Sys->getMess(); -} - -#define VAR_CHECK(_erract) \ - pvVariable *Var = ( pvVariable * ) var; \ - if ( Var == NULL || Var->getMagic() != PV_MAGIC ) \ - _erract - -epicsShareFunc pvStat epicsShareAPI pvVarCreate( void *sys, const char *name, pvConnFunc func, void *priv, - int debug, void **pVar ) { - SYS_CHECK( return pvStatERROR ); - *pVar = Sys->newVariable( name, func, priv, debug ); - return ( *pVar == NULL ) ? pvStatERROR : pvStatOK; -} - -epicsShareFunc pvStat epicsShareAPI pvVarDestroy( void *var ) { - VAR_CHECK( return pvStatERROR ); - delete Var; - return pvStatOK; -} - -epicsShareFunc pvStat epicsShareAPI pvVarGet( void *var, pvType type, unsigned count, pvValue *value ) { - VAR_CHECK( return pvStatERROR ); - return Var->get( type, count, value ); -} - -epicsShareFunc pvStat epicsShareAPI pvVarGetNoBlock( void *var, pvType type, unsigned count, pvValue *value ) { - VAR_CHECK( return pvStatERROR ); - return Var->getNoBlock( type, count, value ); -} - -epicsShareFunc pvStat epicsShareAPI pvVarGetCallback( void *var, pvType type, unsigned count, - pvEventFunc func, void *arg ) { - VAR_CHECK( return pvStatERROR ); - return Var->getCallback( type, count, func, arg ); -} - -epicsShareFunc pvStat epicsShareAPI pvVarPut( void *var, pvType type, unsigned count, pvValue *value ) { - VAR_CHECK( return pvStatERROR ); - return Var->put( type, count, value ); -} - -epicsShareFunc pvStat epicsShareAPI pvVarPutNoBlock( void *var, pvType type, unsigned count, pvValue *value ) { - VAR_CHECK( return pvStatERROR ); - return Var->putNoBlock( type, count, value ); -} - -epicsShareFunc pvStat epicsShareAPI pvVarPutCallback( void *var, pvType type, unsigned count, pvValue *value, - pvEventFunc func, void *arg ) { - VAR_CHECK( return pvStatERROR ); - return Var->putCallback( type, count, value, func, arg ); -} - -epicsShareFunc pvStat epicsShareAPI pvVarMonitorOn( void *var, pvType type, unsigned count, - pvEventFunc func, void *arg, void **pCallback ) { - VAR_CHECK( return pvStatERROR ); - return Var->monitorOn( type, count, func, arg, ( pvCallback ** ) pCallback); -} - -epicsShareFunc pvStat epicsShareAPI pvVarMonitorOff( void *var, void *callback ) { - VAR_CHECK( return pvStatERROR ); - return Var->monitorOff( ( pvCallback * ) callback ); -} - -epicsShareFunc int epicsShareAPI pvVarGetMagic( void *var ) { - VAR_CHECK( return pvStatERROR ); - return Var->getMagic(); -} - -epicsShareFunc void epicsShareAPI pvVarSetDebug( void *var, int debug ) { - VAR_CHECK( {} ); - Var->setDebug( debug ); -} - -epicsShareFunc int epicsShareAPI pvVarGetDebug( void *var ) { - VAR_CHECK( return pvStatERROR ); - return Var->getDebug(); -} - -epicsShareFunc int epicsShareAPI pvVarGetConnected( void *var ) { - VAR_CHECK( return pvStatERROR ); - return Var->getConnected(); -} - -epicsShareFunc pvType epicsShareAPI pvVarGetType( void *var ) { - VAR_CHECK( return pvTypeERROR ); - return Var->getType(); -} - -epicsShareFunc unsigned epicsShareAPI pvVarGetCount( void *var ) { - VAR_CHECK( return pvStatERROR ); - return Var->getCount(); -} - -epicsShareFunc void epicsShareAPI pvVarSetPrivate( void *var, void *priv ) { - VAR_CHECK( {} ); - Var->setPrivate( priv ); -} - -epicsShareFunc char *epicsShareAPI pvVarGetName( void *var ) { - VAR_CHECK( return NULL ); - return Var->getName(); -} - -epicsShareFunc void *epicsShareAPI pvVarGetPrivate( void *var ) { - VAR_CHECK( return NULL ); - return Var->getPrivate(); -} - -epicsShareFunc int epicsShareAPI pvVarGetStatus( void *var ) { - VAR_CHECK( return pvStatERROR ); - return Var->getStatus(); -} - -epicsShareFunc pvSevr epicsShareAPI pvVarGetSevr( void *var ) { - VAR_CHECK( return pvSevrERROR ); - return Var->getSevr(); -} - -epicsShareFunc pvStat epicsShareAPI pvVarGetStat( void *var ) { - VAR_CHECK( return pvStatERROR ); - return Var->getStat(); -} - -epicsShareFunc const char *epicsShareAPI pvVarGetMess( void *var ) { - VAR_CHECK( return "" ); - return Var->getMess(); -} - -/* - * Time utilities - */ -epicsShareFunc int epicsShareAPI pvTimeGetCurrentDouble( double *pTime ) { - epicsTimeStamp stamp; - - *pTime = 0.0; - if ( epicsTimeGetCurrent( &stamp ) == epicsTimeERROR ) - return pvStatERROR; - - *pTime = ( double ) stamp.secPastEpoch + ( ( double ) stamp.nsec / 1e9 ); - return pvStatOK; -} - -/* - * Type tables - */ -epicsShareDef const size_t pv_sizes[] = { - sizeof(pvChar ), - sizeof(pvShort ), - sizeof(pvLong ), - sizeof(pvFloat ), - sizeof(pvDouble ), - sizeof(pvString ), - sizeof(pvTimeChar ), - sizeof(pvTimeShort ), - sizeof(pvTimeLong ), - sizeof(pvTimeFloat ), - sizeof(pvTimeDouble), - sizeof(pvTimeString), -}; - -epicsShareDef const size_t pv_value_sizes[] = { - sizeof(pvChar ), - sizeof(pvShort ), - sizeof(pvLong ), - sizeof(pvFloat ), - sizeof(pvDouble), - sizeof(pvString), - sizeof(pvChar ), - sizeof(pvShort ), - sizeof(pvLong ), - sizeof(pvFloat ), - sizeof(pvDouble), - sizeof(pvString), -}; - -epicsShareDef const size_t pv_value_offsets[] = { - 0, - 0, - 0, - 0, - 0, - 0, - offsetof(pvTimeChar , value), - offsetof(pvTimeShort , value), - offsetof(pvTimeLong , value), - offsetof(pvTimeFloat , value), - offsetof(pvTimeDouble, value), - offsetof(pvTimeString, value), -}; - -epicsShareDef const size_t pv_status_offsets[] = { - offsetof(pvTimeChar , status), - offsetof(pvTimeShort , status), - offsetof(pvTimeLong , status), - offsetof(pvTimeFloat , status), - offsetof(pvTimeDouble, status), - offsetof(pvTimeString, status), -}; - -epicsShareDef const size_t pv_severity_offsets[] = { - offsetof(pvTimeChar , severity), - offsetof(pvTimeShort , severity), - offsetof(pvTimeLong , severity), - offsetof(pvTimeFloat , severity), - offsetof(pvTimeDouble, severity), - offsetof(pvTimeString, severity), -}; - -epicsShareDef const size_t pv_stamp_offsets[] = { - offsetof(pvTimeChar , stamp), - offsetof(pvTimeShort , stamp), - offsetof(pvTimeLong , stamp), - offsetof(pvTimeFloat , stamp), - offsetof(pvTimeDouble, stamp), - offsetof(pvTimeString, stamp), -}; - -/* - * pv.cc,v - * Revision 1.4 2001/02/16 21:45:16 norume - * Many 3.14-related changes. - * - * Revision 1.3 2001/02/16 18:45:39 mrk - * changes for latest version of 3.14 - * - * Revision 1.2 2000/04/14 21:53:28 jba - * Changes for win32 build. - * - * Revision 1.1.1.1 2000/04/04 03:22:13 wlupton - * first commit of seq-2-0-0 - * - * Revision 1.16 2000/03/29 01:59:14 wlupton - * added pvVarGetName - * - * Revision 1.15 2000/03/18 04:00:25 wlupton - * converted to use new configure scheme - * - * Revision 1.14 2000/03/16 02:10:24 wlupton - * added newly-needed debug argument - * - * Revision 1.13 2000/03/07 09:27:39 wlupton - * drastically reduced use of references - * - * Revision 1.12 2000/03/06 19:19:13 wlupton - * avoided compilation warnings - * - * Revision 1.11 2000/03/01 02:07:14 wlupton - * converted to use new OSI library - * - * Revision 1.10 2000/02/19 01:08:55 wlupton - * added dynamic allocation of message string (and support for both sys & var) - * - * Revision 1.9 2000/02/16 02:31:43 wlupton - * merged in v1.9.5 changes - * - * Revision 1.8 1999/07/07 03:14:36 wlupton - * corrected get/putNoBlock (mis-edit) - * - * Revision 1.7 1999/07/01 20:50:18 wlupton - * Working under VxWorks - * - * Revision 1.6 1999/06/15 10:11:02 wlupton - * demo sequence mostly working with KTL - * - * Revision 1.5 1999/06/10 00:35:03 wlupton - * demo sequencer working with pvCa - * - * Revision 1.4 1999/06/08 19:21:43 wlupton - * CA version working; about to use in sequencer - * - * Revision 1.3 1999/06/08 03:25:20 wlupton - * nearly complete CA implementation - * - * Revision 1.2 1999/06/07 21:46:44 wlupton - * working with simple pvtest program - * - * Revision 1.1 1999/06/04 20:48:27 wlupton - * initial version of pv.h and pv.cc - * - */ diff --git a/src/pv/pv.h b/src/pv/pv.h index ea2df5e4..9f86f8d0 100644 --- a/src/pv/pv.h +++ b/src/pv/pv.h @@ -11,22 +11,14 @@ in the file LICENSE that is included with this distribution. * * William Lupton, W. M. Keck Observatory */ - #ifndef INCLpvh #define INCLpvh -#include "shareLib.h" /* reset share lib defines */ -#include "epicsThread.h" /* for thread ids */ -#if 0 -#include "epicsMutex.h" /* for locks */ -#endif +#include "shareLib.h" /* reset share lib defines */ -#include "pvAlarm.h" /* status and severity definitions */ -#include "pvType.h" /* pv type definitions */ +#include "pvAlarm.h" /* status and severity definitions */ +#include "pvType.h" /* pv type definitions */ -/* - * Standard FALSE and TRUE macros - */ #ifndef FALSE #define FALSE 0 #endif @@ -35,340 +27,58 @@ in the file LICENSE that is included with this distribution. #define TRUE 1 #endif -/* - * Magic number for validating structures / versions - */ -#define PV_MAGIC 0xfeddead /* ...a sad tale of food poisoning? */ - -/* - * Connect (connect/disconnect and event (get, put and monitor) functions - */ -typedef void (*pvConnFunc)( void *var, int connected ); - -typedef void (*pvEventFunc)( void *var, pvType type, unsigned count, - pvValue *value, void *arg, pvStat status ); - -/* - * Most of the rest is C++. The C interface is at the bottom. - */ -#ifdef __cplusplus - -/* - * Forward references - */ -class pvVariable; -class pvCallback; - -//////////////////////////////////////////////////////////////////////////////// -/* - * System - * - * This is somewhat analogous to a cdevSystem object (CA has no equivalent) - */ - -class epicsShareClass pvSystem { - -public: - pvSystem( int debug = 0 ); - virtual ~pvSystem(); - - inline pvSystem *getSystem() { return this; } - - virtual pvStat attach() { return pvStatOK; } - virtual pvStat flush() { return pvStatOK; } - virtual pvStat pend( double seconds = 0.0, int wait = FALSE ) = 0; - - virtual pvVariable *newVariable( const char *name, pvConnFunc func = NULL, - void *priv = NULL, int debug = 0 ) = 0; - -#if 0 - void lock(); - void unlock(); -#endif - - inline int getMagic() const { return magic_; } - inline void setDebug( int debug ) { debug_ = debug; } - inline int getDebug() const { return debug_; } +typedef enum { + pvEventGet, + pvEventPut, + pvEventMonitor +} pvEventType; - void setError( int status, pvSevr sevr, pvStat stat, const char *mess ); - inline int getStatus() const { return status_; } - inline pvSevr getSevr() const { return sevr_; } - inline pvStat getStat() const { return stat_; } - inline void setStatus( int status ) { status_ = status; } - inline void setStat( pvStat stat ) { stat_ = stat; } - inline const char *getMess() const { return mess_?mess_:""; } +typedef struct pvSystem pvSystem; +typedef struct pvVar pvVar; +typedef void pvConnFunc(int connected, void *arg); +typedef void pvEventFunc(pvEventType evt, void *arg, pvType type, unsigned count, pvValue *value, pvStat status); -private: - int magic_; /* magic number (used for authentication) */ - int debug_; /* debugging level (inherited by pvs) */ +/* structures must be allocated by client code */ - int status_; /* message system-specific status code */ - pvSevr sevr_; /* severity */ - pvStat stat_; /* status */ - const char *mess_; /* error message */ - -#if 0 - epicsMutexId lock_; /* prevents more than one thread in library */ -#endif +struct pvSystem { + struct ca_client_context *id; }; -//////////////////////////////////////////////////////////////////////////////// -/* - * Process variable - * - * This is somewhat analogous to a cdevDevice object (or a CA channel) - */ -class epicsShareClass pvVariable { - -public: - // private data is constructor argument so that it is guaranteed set - // before connection callback is invoked - pvVariable( pvSystem *system, const char *name, pvConnFunc func = NULL, - void *priv = NULL, int debug = 0 ); - virtual ~pvVariable(); - - virtual pvStat get( pvType type, unsigned count, pvValue *value ) = 0; - virtual pvStat getNoBlock( pvType type, unsigned count, pvValue *value ) = 0; - virtual pvStat getCallback( pvType type, unsigned count, - pvEventFunc func, void *arg = NULL ) = 0; - virtual pvStat put( pvType type, unsigned count, pvValue *value ) = 0; - virtual pvStat putNoBlock( pvType type, unsigned count, pvValue *value ) = 0; - virtual pvStat putCallback( pvType type, unsigned count, pvValue *value, - pvEventFunc func, void *arg = NULL ) = 0; - virtual pvStat monitorOn( pvType type, unsigned count, - pvEventFunc func, void *arg = NULL, - pvCallback **pCallback = NULL ) = 0; - virtual pvStat monitorOff( pvCallback *callback = NULL ) = 0; - - virtual int getConnected() const = 0; - virtual pvType getType() const = 0; - virtual unsigned getCount() const = 0; - - inline int getMagic() const { return magic_; } - inline void setDebug( int debug ) { debug_ = debug; } - inline int getDebug() const { return debug_; } - inline pvConnFunc getFunc() const { return func_; } - - inline pvSystem *getSystem() const { return system_; } - inline char *getName() const { return name_; } - inline void setPrivate( void *priv ) { private_ = priv; } - inline void *getPrivate() const { return private_; } - - void setError( int status, pvSevr sevr, pvStat stat, const char *mess ); - inline int getStatus() const { return status_; } - inline pvSevr getSevr() const { return sevr_; } - inline pvStat getStat() const { return stat_; } - inline void setStatus( int status ) { status_ = status; } - inline void setStat( pvStat stat ) { stat_ = stat; } - inline const char *getMess() const { return mess_?mess_:""; } - -private: - int magic_; /* magic number (used for authentication) */ - int debug_; /* debugging level (inherited from system) */ - pvConnFunc func_; /* connection state change function */ - - pvSystem *system_; /* associated system */ - char *name_; /* variable name */ - void *private_; /* client's private data */ - - int status_; /* message system-specific status code */ - pvSevr sevr_; /* severity */ - pvStat stat_; /* status */ - const char *mess_; /* error message */ -}; - -//////////////////////////////////////////////////////////////////////////////// -/* - * Callback - * - * This is somewhat analogous to a cdevCallback object - */ -#include "tsFreeList.h" -#include "epicsSingleton.h" - -class epicsShareClass pvCallback { - -public: - pvCallback( pvVariable *variable, pvType type, unsigned count, - pvEventFunc func, void *arg, int debug = 0); - ~pvCallback(); - - inline int getMagic() { return magic_; } - inline void setDebug( int debug ) { debug_ = debug; } - inline int getDebug() { return debug_; } - - inline pvVariable *getVariable() { return variable_; } - inline pvType getType() { return type_; } - inline unsigned getCount() { return count_; }; - inline pvEventFunc getFunc() { return func_; }; - inline void *getArg() { return arg_; }; - inline void setPrivate( void *priv ) { private_ = priv; } - inline void *getPrivate() { return private_; } - - // static inline void* operator new(size_t size); - // static inline void operator delete(void *pCadaver, size_t size); - -private: - int magic_; /* magic number (used for authentication) */ - int debug_; /* debugging level (inherited from variable) */ - - pvVariable *variable_; /* associated variable */ - pvType type_; /* variable's native type */ - int count_; /* variable's element count */ - pvEventFunc func_; /* user's event function */ - void *arg_; /* user's event function argument */ - void *private_; /* message system's private data */ - - // static epicsSingleton < tsFreeList < class pvCallback > > pFreeList; +struct pvVar { + struct oldChannelNotify *chid; + struct oldSubscription *monid; + pvConnFunc *conn_handler; + pvEventFunc *event_handler; + void *arg; + const char *msg; }; -// inline void * pvCallback::operator new ( size_t size ) -// { - // epicsSingleton < tsFreeList < class pvCallback > >::reference ref = - // pFreeList.getReference (); - // return ref->allocate ( size ); -// } +#define pvSysIsDefined(x) ((x).id != NULL) +#define pvVarIsDefined(x) ((x).chid != NULL) +#define pvMonIsDefined(x) ((x).monid != NULL) -// inline void pvCallback::operator delete ( void *pCadaver, size_t size ) -// { - // epicsSingleton < tsFreeList < class pvCallback > >::reference ref = - // pFreeList.getReference (); - // ref->release ( pCadaver, size ); -// } +epicsShareExtern const struct pvSystem nullPvSys; +epicsShareExtern const struct pvVar nullPvVar; -//////////////////////////////////////////////////////////////////////////////// -/* - * End of C++. - */ -#endif /* __cplusplus */ +epicsShareFunc pvStat pvSysCreate(pvSystem *pSys); +epicsShareFunc pvStat pvSysFlush(pvSystem sys); +epicsShareFunc pvStat pvSysAttach(pvSystem sys); -/* - * C interface - */ -#ifdef __cplusplus -extern "C" { -epicsShareFunc pvSystem * epicsShareAPI newPvSystem( const char *name, int debug = 0 ); -#endif +epicsShareFunc pvStat pvVarCreate(pvSystem sys, const char *name, + pvConnFunc *conn_func, pvEventFunc *event_func, void *arg, pvVar *var); +epicsShareFunc pvStat pvVarDestroy(pvVar *var); +epicsShareFunc pvStat pvVarGetCallback(pvVar *var, pvType type, unsigned count, void *arg); +epicsShareFunc pvStat pvVarPutNoBlock(pvVar *var, pvType type, unsigned count, pvValue *value); +epicsShareFunc pvStat pvVarPutCallback(pvVar *var, pvType type, unsigned count, pvValue *value, void *arg); -epicsShareFunc pvStat epicsShareAPI pvSysCreate( const char *name, int debug, void **pSys ); -epicsShareFunc pvStat epicsShareAPI pvSysDestroy( void *sys ); -epicsShareFunc pvStat epicsShareAPI pvSysFlush( void *sys ); -epicsShareFunc pvStat epicsShareAPI pvSysPend( void *sys, double seconds, int wait ); -#if 0 -epicsShareFunc pvStat epicsShareAPI pvSysLock( void *sys ); -epicsShareFunc pvStat epicsShareAPI pvSysUnlock( void *sys ); -#endif -epicsShareFunc pvStat epicsShareAPI pvSysAttach( void *sys ); -epicsShareFunc int epicsShareAPI pvSysGetMagic( void *sys ); -epicsShareFunc void epicsShareAPI pvSysSetDebug( void *sys, int debug ); -epicsShareFunc int epicsShareAPI pvSysGetDebug( void *sys ); -epicsShareFunc int epicsShareAPI pvSysGetStatus( void *sys ); -epicsShareFunc pvSevr epicsShareAPI pvSysGetSevr( void *sys ); -epicsShareFunc pvStat epicsShareAPI pvSysGetStat( void *sys ); -epicsShareFunc const char * epicsShareAPI pvSysGetMess( void *sys ); +epicsShareFunc pvStat pvVarMonitorOn(pvVar *var, pvType type, unsigned count, void *arg); +epicsShareFunc pvStat pvVarMonitorOff(pvVar *var); -epicsShareFunc pvStat epicsShareAPI pvVarCreate( void *sys, const char *name, pvConnFunc func, void *priv, - int debug, void **pVar ); -epicsShareFunc pvStat epicsShareAPI pvVarDestroy( void *var ); -epicsShareFunc pvStat epicsShareAPI pvVarGet( void *var, pvType type, unsigned count, pvValue *value ); -epicsShareFunc pvStat epicsShareAPI pvVarGetNoBlock( void *var, pvType type, unsigned count, pvValue *value ); -epicsShareFunc pvStat epicsShareAPI pvVarGetCallback( void *var, pvType type, unsigned count, - pvEventFunc func, void *arg ); -epicsShareFunc pvStat epicsShareAPI pvVarPut( void *var, pvType type, unsigned count, pvValue *value ); -epicsShareFunc pvStat epicsShareAPI pvVarPutNoBlock( void *var, pvType type, unsigned count, pvValue *value ); -epicsShareFunc pvStat epicsShareAPI pvVarPutCallback( void *var, pvType type, unsigned count, pvValue *value, - pvEventFunc func, void *arg ); -epicsShareFunc pvStat epicsShareAPI pvVarMonitorOn( void *var, pvType type, unsigned count, - pvEventFunc func, void *arg, void **pId ); -epicsShareFunc pvStat epicsShareAPI pvVarMonitorOff( void *var, void *id ); -epicsShareFunc int epicsShareAPI pvVarGetMagic( void *var ); -epicsShareFunc void epicsShareAPI pvVarSetDebug( void *var, int debug ); -epicsShareFunc int epicsShareAPI pvVarGetDebug( void *var ); -epicsShareFunc int epicsShareAPI pvVarGetConnected( void *var ); -epicsShareFunc pvType epicsShareAPI pvVarGetType( void *var ); -epicsShareFunc unsigned epicsShareAPI pvVarGetCount( void *var ); -epicsShareFunc char * epicsShareAPI pvVarGetName( void *var ); -epicsShareFunc void epicsShareAPI pvVarSetPrivate( void *var, void *priv ); -epicsShareFunc void * epicsShareAPI pvVarGetPrivate( void *var ); -epicsShareFunc int epicsShareAPI pvVarGetStatus( void *var ); -epicsShareFunc pvSevr epicsShareAPI pvVarGetSevr( void *var ); -epicsShareFunc pvStat epicsShareAPI pvVarGetStat( void *var ); -epicsShareFunc const char * epicsShareAPI pvVarGetMess( void *var ); +epicsShareFunc unsigned pvVarGetCount(pvVar *var); -/* - * Time utilities - */ -epicsShareFunc int epicsShareAPI pvTimeGetCurrentDouble( double *pTime ); +#define pvVarGetPrivate(var) (var).arg +#define pvVarGetMess(var) (var).msg -#ifdef __cplusplus -} -#endif +epicsShareFunc pvStat pvTimeGetCurrentDouble(double *pTime); #endif /* INCLpvh */ - -/* - * pv.h,v - * Revision 1.3 2001/02/16 18:45:39 mrk - * changes for latest version of 3.14 - * - * Revision 1.2 2000/04/14 21:53:28 jba - * Changes for win32 build. - * - * Revision 1.1.1.1 2000/04/04 03:22:13 wlupton - * first commit of seq-2-0-0 - * - * Revision 1.18 2000/03/31 23:00:42 wlupton - * added default attach and flush implementations; added setStatus - * - * Revision 1.17 2000/03/29 01:58:48 wlupton - * split off pvAlarm.h; added pvVarGetName - * - * Revision 1.16 2000/03/18 04:00:25 wlupton - * converted to use new configure scheme - * - * Revision 1.15 2000/03/16 02:10:24 wlupton - * added newly-needed debug argument - * - * Revision 1.14 2000/03/07 09:27:39 wlupton - * drastically reduced use of references - * - * Revision 1.13 2000/03/07 08:46:29 wlupton - * created ktlKeyword class (works but a bit messy) - * - * Revision 1.12 2000/03/06 19:19:43 wlupton - * misc type conversion and error reporting mods - * - * Revision 1.11 2000/03/01 02:07:14 wlupton - * converted to use new OSI library - * - * Revision 1.10 2000/02/19 01:09:51 wlupton - * added PV_SIMPLE() and prototypes for var-level error info - * - * Revision 1.9 2000/02/16 02:31:44 wlupton - * merged in v1.9.5 changes - * - * Revision 1.8 1999/09/07 20:42:59 epics - * removed unnecessary comment - * - * Revision 1.7 1999/07/07 18:50:33 wlupton - * supported full mapping from EPICS status and severity to pvStat and pvSevr - * - * Revision 1.6 1999/07/01 20:50:18 wlupton - * Working under VxWorks - * - * Revision 1.5 1999/06/10 00:35:03 wlupton - * demo sequencer working with pvCa - * - * Revision 1.4 1999/06/08 19:21:43 wlupton - * CA version working; about to use in sequencer - * - * Revision 1.3 1999/06/08 03:25:21 wlupton - * nearly complete CA implementation - * - * Revision 1.2 1999/06/07 21:46:44 wlupton - * working with simple pvtest program - * - * Revision 1.1 1999/06/04 20:48:27 wlupton - * initial version of pv.h and pv.cc - * - */ diff --git a/src/pv/pvAlarm.h b/src/pv/pvAlarm.h index ac13bfca..91830420 100644 --- a/src/pv/pvAlarm.h +++ b/src/pv/pvAlarm.h @@ -60,14 +60,3 @@ typedef enum { } pvSevr; #endif /* INCLpvAlarmh */ - -/* - * pvAlarm.h,v - * Revision 1.1.1.1 2000/04/04 03:22:15 wlupton - * first commit of seq-2-0-0 - * - * Revision 1.1 2000/03/29 01:58:59 wlupton - * initial insertion - * - */ - diff --git a/src/pv/pvCa.cc b/src/pv/pvCa.cc deleted file mode 100644 index bec9e8f7..00000000 --- a/src/pv/pvCa.cc +++ /dev/null @@ -1,871 +0,0 @@ -/* Implementation of EPICS sequencer CA library (pvCa) - * - * William Lupton, W. M. Keck Observatory - */ - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> - -#ifdef _WIN32 -# include <malloc.h> -#elif (__STDC_VERSION__ < 199901L) && !defined(__GNUC__) -# include <alloca.h> -#endif - -#include "alarm.h" -#include "cadef.h" - -#define epicsExportSharedSymbols -#include "pvCa.h" - -/* handlers */ -extern "C" { -void pvCaConnectionHandler( struct connection_handler_args args ); -void pvCaAccessHandler( struct event_handler_args args ); -void pvCaMonitorHandler( struct event_handler_args args ); -} - -/* utilities */ -static pvSevr sevrFromCA( int status ); /* CA severity as pvSevr */ -static pvSevr sevrFromEPICS( int sevr ); - /* EPICS severity as pvSevr */ -static pvStat statFromCA( int status ); /* CA status as pvStat */ -static pvStat statFromEPICS( int stat ); - /* EPICS status as pvStat */ -static pvType typeFromCA( int type ); /* DBR type as pvType */ -static int typeToCA( pvType type ); /* pvType as DBR type */ -static void copyToCA( pvType type, unsigned count, - const pvValue *value, union db_access_val *caValue ); - /* copy pvValue to DBR value */ -static void copyFromCA( int type, unsigned count, - const union db_access_val *caValue, pvValue *value ); - /* copy DBR value to pvValue */ - -/* invoke CA function and send error details to system or variable object */ -#define INVOKE(_function) \ - do { \ - int _status = _function; \ - if ( _status & CA_M_SUCCESS ) \ - setStat( pvStatOK ); \ - else \ - setError( _status, sevrFromCA( _status ), \ - statFromCA( _status ), ca_message( _status ) ); \ - } while ( FALSE ) - -//////////////////////////////////////////////////////////////////////////////// -/*+ - * Routine: caSystem::caSystem - * - * Purpose: caSystem constructor - * - * Description: - */ -caSystem::caSystem( int debug ) : - pvSystem( debug ), - context_( NULL ) -{ - if ( getDebug() > 0 ) - printf( "%8p: caSystem::caSystem( %d )\n", this, debug ); - - INVOKE( ca_context_create(ca_enable_preemptive_callback) ); - this->context_ = ca_current_context (); -} - -/*+ - * Routine: caSystem::~caSystem - * - * Purpose: caSystem destructor - * - * Description: - */ -caSystem::~caSystem() -{ - if ( getDebug() > 0 ) - printf( "%8p: caSystem::~caSystem()\n", this ); - - INVOKE( ca_task_exit() ); -} - -/*+ - * Routine: caSystem::attach - * - * Purpose: caSystem attach to context of creator of caSystem - * - * Description: - */ -pvStat caSystem::attach() -{ - if ( getDebug() > 0 ) - printf( "%8p: caSystem::attach()\n", this ); - - INVOKE( ca_attach_context( context_ ) ); - return getStat(); -} - -/*+ - * Routine: caSystem::flush - * - * Purpose: caSystem flush routine - * - * Description: - */ -pvStat caSystem::flush() -{ - if ( getDebug() > 0 ) - printf( "%8p: caSystem::flush()\n", this ); - - INVOKE( ca_flush_io() ); - return getStat(); -} - -/*+ - * Routine: caSystem::pend - * - * Purpose: caSystem pend routine - * - * Description: - */ -pvStat caSystem::pend( double seconds, int wait ) -{ - if ( getDebug() > 1 ) - printf( "%8p: caSystem::pend( %g, %d )\n", this, seconds, wait ); - - if ( seconds <= 0.0 || !wait ) seconds = 1e-8; - INVOKE( ca_pend_event( seconds ) ); - return getStat(); -} - -/*+ - * Routine: caSystem::newVariable - * - * Purpose: caSystem variable creation routine - * - * Description: - */ -pvVariable *caSystem::newVariable( const char *name, pvConnFunc func, void *priv, - int debug ) -{ - if ( getDebug() > 0 ) - printf( "%8p: caSystem::newVariable( %s, %p, %p, %d )\n", - this, name, func, priv, debug ); - - return new caVariable( this, name, func, priv, debug ); -} - -//////////////////////////////////////////////////////////////////////////////// -/*+ - * Routine: caVariable::caVariable - * - * Purpose: caVariable constructor - * - * Description: - */ -caVariable::caVariable( caSystem *system, const char *name, pvConnFunc func, - void *priv, int debug ) : - pvVariable( system, name, func, priv, debug ), - chid_( NULL ) -{ - if ( getDebug() > 0 ) - printf( "%8p: caVariable::caVariable( %s, %d )\n", - this, name, debug ); - - if ( getFunc() != NULL ) - INVOKE( ca_search_and_connect( name, &chid_, pvCaConnectionHandler, this )); - else - INVOKE( ca_search_and_connect( name, &chid_, NULL, NULL )); -} - -/*+ - * Routine: caVariable::~caVariable - * - * Purpose: caVariable destructor - * - * Description: - */ -caVariable::~caVariable() -{ - if ( getDebug() > 0 ) - printf( "%8p: caVariable::~caVariable()\n", this ); - - INVOKE( ca_clear_channel( chid_ ) ); -} - -/*+ - * Routine: caVariable::get - * - * Purpose: caVariable blocking get routine - * - * Description: - */ -pvStat caVariable::get( pvType type, unsigned count, pvValue *value ) -{ - if ( getDebug() > 0 ) - printf( "%8p: caVariable::get( %d, %d )\n", this, type, count ); - - int caType = typeToCA( type ); -#if (__STDC_VERSION__ >= 199901L) || defined(__GNUC__) - char caValue[dbr_size_n( caType, count )]; -#else - char *caValue = (char*)alloca( dbr_size_n( caType, count ) ); -#endif - INVOKE( ca_array_get( caType, count, chid_, caValue ) ); - // ### must block so can convert value; should use ca_get_callback() - if ( getStat() == pvStatOK ) - INVOKE( ca_pend_io( 5.0 ) ); - if ( getStat() == pvStatOK ) - copyFromCA( caType, count, ( union db_access_val * ) caValue, value ); - - return getStat(); -} - -/*+ - * Routine: caVariable::getNoBlock - * - * Purpose: caVariable non-blocking get routine - * - * Description: - */ -pvStat caVariable::getNoBlock( pvType type, unsigned count, pvValue *value ) -{ - if ( getDebug() > 0 ) - printf( "%8p: caVariable::getNoBlock( %d, %d )\n", this, - type, count ); - - // ### must block so can convert value; should use ca_get_callback() - return get( type, count, value ); -} - - -/*+ - * Routine: caVariable::getCallback - * - * Purpose: caVariable get with callback routine - * - * Description: - */ -pvStat caVariable::getCallback( pvType type, unsigned count, - pvEventFunc func, void *arg ) -{ - if ( getDebug() > 0 ) - printf( "%8p: caVariable::getCallback( %d, %d )\n", - this, type, count ); - - pvCallback *callback = new pvCallback( this, type, count, func, arg, - getDebug() ); - - INVOKE( ca_array_get_callback( typeToCA( type ), count, chid_, - pvCaAccessHandler, callback ) ); - return getStat(); -} - -/*+ - * Routine: caVariable::put - * - * Purpose: caVariable blocking put routine - * - * Description: - */ -pvStat caVariable::put( pvType type, unsigned count, pvValue *value ) -{ - if ( getDebug() > 0 ) - printf( "%8p: caVariable::put( %d, %d )\n", this, type, count ); - - int caType = typeToCA( type ); -#if (__STDC_VERSION__ >= 199901L) || defined(__GNUC__) - char caValue[dbr_size_n( caType, count )]; -#else - char *caValue = (char*)alloca( dbr_size_n( caType, count ) ); -#endif - copyToCA( type, count, value, ( union db_access_val * ) caValue ); - INVOKE( ca_array_put( caType, count, chid_, caValue ) ); - if ( getStat() == pvStatOK ) - INVOKE( ca_pend_io( 5.0 ) ); - return getStat(); -} - -/*+ - * Routine: caVariable::putNoBlock - * - * Purpose: caVariable non-blocking put routine - * - * Description: - */ -pvStat caVariable::putNoBlock( pvType type, unsigned count, pvValue *value ) -{ - if ( getDebug() > 0 ) - printf( "%8p: caVariable::putNoBlock( %d, %d )\n", this, - type, count ); - - int caType = typeToCA( type ); -#if (__STDC_VERSION__ >= 199901L) || defined(__GNUC__) - char caValue[dbr_size_n( caType, count )]; -#else - char *caValue = (char*)alloca( dbr_size_n( caType, count ) ); -#endif - copyToCA( type, count, value, ( union db_access_val * ) caValue ); - INVOKE( ca_array_put( caType, count, chid_, caValue ) ); - return getStat(); -} - -/*+ - * Routine: caVariable::putCallback - * - * Purpose: caVariable put with callback routine - * - * Description: - */ -pvStat caVariable::putCallback( pvType type, unsigned count, pvValue *value, - pvEventFunc func, void *arg ) -{ - if ( getDebug() > 0 ) - printf( "%8p: caVariable::putCallback( %d, %d )\n", - this, type, count ); - - pvCallback *callback = new pvCallback( this, type, count, func, arg, - getDebug() ); - - INVOKE( ca_array_put_callback( typeToCA( type ), count, chid_, value, - pvCaAccessHandler, callback ) ); - return getStat(); -} - -/*+ - * Routine: caVariable::monitorOn - * - * Purpose: caVariable monitor enable routine - * - * Description: - */ -pvStat caVariable::monitorOn( pvType type, unsigned count, pvEventFunc func, - void *arg, pvCallback **pCallback ) -{ - if ( getDebug() > 0 ) - printf( "%8p: caVariable::monitorOn( %d, %d )\n", - this, type, count ); - - pvCallback *callback = new pvCallback( this, type, count, func, arg, - getDebug() ); - - evid id = NULL; - INVOKE( ca_add_masked_array_event( typeToCA( type ), count, chid_, - pvCaMonitorHandler, callback, 0.0, 0.0, 0.0, - &id, DBE_VALUE|DBE_ALARM ) ); - callback->setPrivate( id ); - - if ( pCallback != NULL ) - *pCallback = callback; - return getStat(); -} - -/*+ - * Routine: caVariable::monitorOff - * - * Purpose: caVariable monitor disable routine - * - * Description: - */ -pvStat caVariable::monitorOff( pvCallback *callback ) -{ - if ( getDebug() > 0 ) - printf( "%8p: caVariable::monitorOff()\n", this ); - - if ( callback != NULL ) { - evid id = ( evid ) callback->getPrivate(); - INVOKE( ca_clear_event( id ) ); - delete callback; - return getStat(); - } else { - return pvStatOK; - } -} - -/*+ - * Routine: caVariable::getConnected - * - * Purpose: caVariable "are we connected?" routine - * - * Description: - */ -int caVariable::getConnected() const -{ - if ( getDebug() > 1 ) - printf( "%8p: caVariable::getConnected()\n", this ); - - return ( ca_state( chid_ ) == cs_conn ); -} - -/*+ - * Routine: caVariable::getType - * - * Purpose: caVariable "what type are we?" routine - * - * Description: - */ -pvType caVariable::getType() const -{ - if ( getDebug() > 1 ) - printf( "%8p: caVariable::getType()\n", this ); - - return typeFromCA( ca_field_type( chid_ ) ); -} - -/*+ - * Routine: caVariable::getCount - * - * Purpose: caVariable "what count do we have?" routine - * - * Description: - */ -unsigned caVariable::getCount() const -{ - if ( getDebug() > 1 ) - printf( "%8p: caVariable::getCount()\n", this ); - - return ca_element_count( chid_ ); -} - -//////////////////////////////////////////////////////////////////////////////// -/*+ - * Routine: pvCaConnectionHandler - * - * Purpose: CA connection handler - * - * Description: - */ -void pvCaConnectionHandler( struct connection_handler_args args ) -{ - pvVariable *variable = ( pvVariable * ) ca_puser( args.chid ); - pvConnFunc func = variable->getFunc(); - - ( *func ) ( ( void * ) variable, ( args.op == CA_OP_CONN_UP ) ); -} - -/*+ - * Routine: pvCaAccessHandler - * - * Purpose: CA get/put callback event handler - * - * Description: - */ -void pvCaAccessHandler( struct event_handler_args args ) -{ - pvCaMonitorHandler( args ); - - pvCallback *callback = ( pvCallback * ) args.usr; - delete callback; -} - -/*+ - * Routine: pvCaMonitorHandler - * - * Purpose: CA monitor event handler - * - * Description: - */ -void pvCaMonitorHandler( struct event_handler_args args ) -{ - pvCallback *callback = ( pvCallback * ) args.usr; - pvEventFunc func = callback->getFunc(); - pvVariable *variable = callback->getVariable(); - pvType type = callback->getType(); - unsigned count = callback->getCount(); - void *arg = callback->getArg(); - - // put completion messages pass a NULL value - if ( args.dbr == NULL ) { - ( *func ) ( ( void * ) variable, type, count, NULL, arg, - statFromCA( args.status ) ); - } else { -#if (__STDC_VERSION__ >= 199901L) || defined(__GNUC__) - char value[pv_size_n(typeFromCA(args.type), count)]; -#else - char *value = (char*)alloca( pv_size_n(typeFromCA(args.type), count) ); -#endif - copyFromCA( args.type, args.count, ( union db_access_val * ) args.dbr, - (pvValue *) value ); - // ### should assert args.type is equiv to type and args.count is count - ( *func ) ( ( void * ) variable, type, count, (pvValue *) value, arg, - statFromCA( args.status ) ); - } -} - -//////////////////////////////////////////////////////////////////////////////// -/*+ - * Routine: sevrFromCA - * - * Purpose: extract pvSevr from CA status - * - * Description: - */ -static pvSevr sevrFromCA( int status ) -{ - switch ( CA_EXTRACT_SEVERITY( status ) ) { - case CA_K_INFO: return pvSevrNONE; - case CA_K_SUCCESS: return pvSevrNONE; - case CA_K_WARNING: return pvSevrMINOR; - case CA_K_ERROR: return pvSevrMAJOR; - case CA_K_SEVERE: return pvSevrINVALID; - default: return pvSevrERROR; - } -} - -/*+ - * Routine: sevrFromEPICS - * - * Purpose: extract pvSevr from EPICS severity - * - * Description: - */ -static pvSevr sevrFromEPICS( int sevr ) -{ - switch ( sevr ) { - case NO_ALARM: return pvSevrNONE; - case MINOR_ALARM: return pvSevrMINOR; - case MAJOR_ALARM: return pvSevrMAJOR; - case INVALID_ALARM: return pvSevrINVALID; - default: return pvSevrERROR; - } -} - -/*+ - * Routine: statFromCA - * - * Purpose: extract pvStat from CA status - * - * Description: - */ -static pvStat statFromCA( int status ) -{ - pvSevr sevr = sevrFromCA( status ); - return ( sevr == pvSevrNONE || sevr == pvSevrMINOR ) ? - pvStatOK : pvStatERROR; -} - -/*+ - * Routine: statFromEPICS - * - * Purpose: extract pvStat from EPICS status - * - * Description: - */ -static pvStat statFromEPICS( int stat ) -{ - switch ( stat ) { - case NO_ALARM: return pvStatOK; - case READ_ALARM: return pvStatREAD; - case WRITE_ALARM: return pvStatWRITE; - case HIHI_ALARM: return pvStatHIHI; - case HIGH_ALARM: return pvStatHIGH; - case LOLO_ALARM: return pvStatLOLO; - case LOW_ALARM: return pvStatLOW; - case STATE_ALARM: return pvStatSTATE; - case COS_ALARM: return pvStatCOS; - case COMM_ALARM: return pvStatCOMM; - case TIMEOUT_ALARM: return pvStatTIMEOUT; - case HW_LIMIT_ALARM: return pvStatHW_LIMIT; - case CALC_ALARM: return pvStatCALC; - case SCAN_ALARM: return pvStatSCAN; - case LINK_ALARM: return pvStatLINK; - case SOFT_ALARM: return pvStatSOFT; - case BAD_SUB_ALARM: return pvStatBAD_SUB; - case UDF_ALARM: return pvStatUDF; - case DISABLE_ALARM: return pvStatDISABLE; - case SIMM_ALARM: return pvStatSIMM; - case READ_ACCESS_ALARM: return pvStatREAD_ACCESS; - case WRITE_ACCESS_ALARM: return pvStatWRITE_ACCESS; - default: return pvStatERROR; - } -} - -/*+ - * Routine: typeFromCA - * - * Purpose: extract pvType from DBR type - * - * Description: - */ -static pvType typeFromCA( int type ) -{ - switch ( type ) { - case DBR_CHAR: return pvTypeCHAR; - case DBR_SHORT: return pvTypeSHORT; - case DBR_ENUM: return pvTypeSHORT; - case DBR_LONG: return pvTypeLONG; - case DBR_FLOAT: return pvTypeFLOAT; - case DBR_DOUBLE: return pvTypeDOUBLE; - case DBR_STRING: return pvTypeSTRING; - case DBR_TIME_CHAR: return pvTypeTIME_CHAR; - case DBR_TIME_SHORT: return pvTypeTIME_SHORT; - case DBR_TIME_ENUM: return pvTypeTIME_SHORT; - case DBR_TIME_LONG: return pvTypeTIME_LONG; - case DBR_TIME_FLOAT: return pvTypeTIME_FLOAT; - case DBR_TIME_DOUBLE: return pvTypeTIME_DOUBLE; - case DBR_TIME_STRING: return pvTypeTIME_STRING; - default: return pvTypeERROR; - } -} - -/*+ - * Routine: typeToCA - * - * Purpose: extract DBR type from pvType - * - * Description: - */ -static int typeToCA( pvType type ) -{ - switch ( type ) { - case pvTypeCHAR: return DBR_CHAR; - case pvTypeSHORT: return DBR_SHORT; - case pvTypeLONG: return DBR_LONG; - case pvTypeFLOAT: return DBR_FLOAT; - case pvTypeDOUBLE: return DBR_DOUBLE; - case pvTypeSTRING: return DBR_STRING; - case pvTypeTIME_CHAR: return DBR_TIME_CHAR; - case pvTypeTIME_SHORT: return DBR_TIME_SHORT; - case pvTypeTIME_LONG: return DBR_TIME_LONG; - case pvTypeTIME_FLOAT: return DBR_TIME_FLOAT; - case pvTypeTIME_DOUBLE: return DBR_TIME_DOUBLE; - case pvTypeTIME_STRING: return DBR_TIME_STRING; - default: return -1; - } -} - -/*+ - * Routine: copyToCA - * - * Purpose: copy pvValue to DBR value - * - * Description: - */ -static void copyToCA( pvType type, unsigned count, - const pvValue *value, union db_access_val *caValue ) -{ - // ### inefficient to do all this here - dbr_char_t *charval = (dbr_char_t *) dbr_value_ptr(caValue, DBR_CHAR ); - dbr_short_t *shrtval = (dbr_short_t *) dbr_value_ptr(caValue, DBR_SHORT ); - dbr_long_t *longval = (dbr_long_t *) dbr_value_ptr(caValue, DBR_LONG ); - dbr_float_t *fltval = (dbr_float_t *) dbr_value_ptr(caValue, DBR_FLOAT ); - dbr_double_t*doubleval= (dbr_double_t *) dbr_value_ptr(caValue, DBR_DOUBLE); - dbr_string_t*strval = (dbr_string_t *) dbr_value_ptr(caValue, DBR_STRING); - - int s = sizeof( dbr_string_t ); - unsigned i; - - switch ( type ) { - case pvTypeCHAR: - for ( i = 0; i < count; i++ ) - charval[i] = value->charVal[i]; - break; - case pvTypeSHORT: - for ( i = 0; i < count; i++ ) - shrtval[i] = value->shortVal[i]; - break; - case pvTypeLONG: - for ( i = 0; i < count; i++ ) - longval[i] = value->longVal[i]; - break; - case pvTypeFLOAT: - for ( i = 0; i < count; i++ ) - fltval[i] = value->floatVal[i]; - break; - case pvTypeDOUBLE: - for ( i = 0; i < count; i++ ) - doubleval[i] = value->doubleVal[i]; - break; - case pvTypeSTRING: - for ( i = 0; i < count; i++ ) { - strncpy( strval[i], value->stringVal[i], s ); - strval[i][s-1] = '\0'; - } - break; - default: - // ### no check for invalid types - // ### assume that no TIME_XXX types are written to CA - break; - } -} - -/*+ - * Routine: copyFromCA - * - * Purpose: copy DBR value to pvValue - * - * Description: - */ -static void copyFromCA( int type, unsigned count, - const union db_access_val *caValue, pvValue *value ) -{ - // ### inefficient to do all this here - dbr_char_t *charval = (dbr_char_t *) dbr_value_ptr(caValue, DBR_CHAR ); - dbr_short_t *shrtval = (dbr_short_t *) dbr_value_ptr(caValue, DBR_SHORT ); - dbr_long_t *longval = (dbr_long_t *) dbr_value_ptr(caValue, DBR_LONG ); - dbr_float_t *fltval = (dbr_float_t *) dbr_value_ptr(caValue, DBR_FLOAT ); - dbr_double_t*doubleval= (dbr_double_t *) dbr_value_ptr(caValue, DBR_DOUBLE); - dbr_string_t*strval = (dbr_string_t *) dbr_value_ptr(caValue, DBR_STRING); - - dbr_char_t *tchrval = (dbr_char_t *) dbr_value_ptr(caValue, DBR_TIME_CHAR ); - dbr_short_t *tshrtval = (dbr_short_t *) dbr_value_ptr(caValue, DBR_TIME_SHORT ); - dbr_long_t *tlngval = (dbr_long_t *) dbr_value_ptr(caValue, DBR_TIME_LONG ); - dbr_float_t *tfltval = (dbr_float_t *) dbr_value_ptr(caValue, DBR_TIME_FLOAT ); - dbr_double_t*tdblval = (dbr_double_t *) dbr_value_ptr(caValue, DBR_TIME_DOUBLE); - dbr_string_t*tstrval = (dbr_string_t *) dbr_value_ptr(caValue, DBR_TIME_STRING); - - int s = sizeof( pvString ); - unsigned i; - - switch ( type ) { - case DBR_CHAR: - for ( i = 0; i < count; i++ ) - value->charVal[i] = charval[i]; - break; - case DBR_SHORT: - case DBR_ENUM: - for ( i = 0; i < count; i++ ) - value->shortVal[i] = shrtval[i]; - break; - case DBR_LONG: - for ( i = 0; i < count; i++ ) - value->longVal[i] = longval[i]; - break; - case DBR_FLOAT: - for ( i = 0; i < count; i++ ) - value->floatVal[i] = fltval[i]; - break; - case DBR_DOUBLE: - for ( i = 0; i < count; i++ ) - value->doubleVal[i] = doubleval[i]; - break; - case DBR_STRING: - for ( i = 0; i < count; i++ ) { - strncpy( value->stringVal[i], strval[i], s ); - value->stringVal[i][s-1] = '\0'; - } - break; - case DBR_TIME_CHAR: - value->timeCharVal.status = statFromEPICS( caValue->tchrval.status ); - value->timeCharVal.severity = sevrFromEPICS( caValue->tchrval.severity); - value->timeCharVal.stamp = caValue->tchrval.stamp; - for ( i = 0; i < count; i++ ) - value->timeCharVal.value[i] = tchrval[i]; - break; - case DBR_TIME_SHORT: - case DBR_TIME_ENUM: - value->timeShortVal.status = statFromEPICS( caValue->tshrtval.status ); - value->timeShortVal.severity =sevrFromEPICS(caValue->tshrtval.severity); - value->timeShortVal.stamp = caValue->tshrtval.stamp; - for ( i = 0; i < count; i++ ) - value->timeShortVal.value[i] = tshrtval[i]; - break; - case DBR_TIME_LONG: - value->timeLongVal.status = statFromEPICS( caValue->tlngval.status ); - value->timeLongVal.severity = sevrFromEPICS( caValue->tlngval.severity); - value->timeLongVal.stamp = caValue->tlngval.stamp; - for ( i = 0; i < count; i++ ) - value->timeLongVal.value[i] = tlngval[i]; - break; - case DBR_TIME_FLOAT: - value->timeFloatVal.status = statFromEPICS( caValue->tfltval.status ); - value->timeFloatVal.severity = sevrFromEPICS(caValue->tfltval.severity); - value->timeFloatVal.stamp = caValue->tfltval.stamp; - for ( i = 0; i < count; i++ ) - value->timeFloatVal.value[i] = tfltval[i]; - break; - case DBR_TIME_DOUBLE: - value->timeDoubleVal.status = statFromEPICS( caValue->tdblval.status ); - value->timeDoubleVal.severity =sevrFromEPICS(caValue->tdblval.severity); - value->timeDoubleVal.stamp = caValue->tdblval.stamp; - for ( i = 0; i < count; i++ ) - value->timeDoubleVal.value[i] = tdblval[i]; - break; - case DBR_TIME_STRING: - value->timeStringVal.status = statFromEPICS( caValue->tstrval.status ); - value->timeStringVal.severity =sevrFromEPICS(caValue->tstrval.severity); - value->timeStringVal.stamp = caValue->tstrval.stamp; - for ( i = 0; i < count; i++ ) { - strncpy( value->timeStringVal.value[i], tstrval[i], s ); - value->timeStringVal.value[i][s-1] = '\0'; - } - break; - default: - // ### no check for invalid types - break; - } -} - -/* - * pvCa.cc,v - * Revision 1.7 2001/10/04 18:33:25 jhill - * context_ variable wasnt initialized - * - * Revision 1.6 2001/07/05 14:42:15 mrk - * ca changed client contect - * - * Revision 1.5 2001/03/21 19:42:45 mrk - * handlers must be C callable and external to satisfy all compilers - * - * Revision 1.4 2001/03/21 15:03:35 mrk - * declare extern "C" - * - * Revision 1.3 2001/03/09 21:11:51 mrk - * ca_pend no longer exists - * - * Revision 1.2 2000/04/14 21:53:28 jba - * Changes for win32 build. - * - * Revision 1.1.1.1 2000/04/04 03:22:14 wlupton - * first commit of seq-2-0-0 - * - * Revision 1.17 2000/03/29 01:59:38 wlupton - * accounted for possibility of NULL args.dbr in callback - * - * Revision 1.16 2000/03/18 04:00:25 wlupton - * converted to use new configure scheme - * - * Revision 1.15 2000/03/16 02:11:28 wlupton - * supported KTL_ANYPOLY (plus misc other mods) - * - * Revision 1.14 2000/03/07 19:55:32 wlupton - * nearly sufficient tidying up - * - * Revision 1.13 2000/03/07 09:27:39 wlupton - * drastically reduced use of references - * - * Revision 1.12 2000/03/07 08:46:29 wlupton - * created ktlKeyword class (works but a bit messy) - * - * Revision 1.11 2000/03/06 19:20:22 wlupton - * only set error on failure; tidy error reporting - * - * Revision 1.10 2000/03/01 02:07:14 wlupton - * converted to use new OSI library - * - * Revision 1.9 2000/02/19 01:11:33 wlupton - * changed INVOKE to operate on current object (sys or var) - * - * Revision 1.8 2000/02/16 02:31:44 wlupton - * merged in v1.9.5 changes - * - * Revision 1.7 1999/07/07 18:50:33 wlupton - * supported full mapping from EPICS status and severity to pvStat and pvSevr - * - * Revision 1.6 1999/07/01 20:50:19 wlupton - * Working under VxWorks - * - * Revision 1.5 1999/06/15 10:11:03 wlupton - * demo sequence mostly working with KTL - * - * Revision 1.4 1999/06/10 00:35:04 wlupton - * demo sequencer working with pvCa - * - * Revision 1.3 1999/06/08 19:21:44 wlupton - * CA version working; about to use in sequencer - * - * Revision 1.2 1999/06/08 03:25:21 wlupton - * nearly complete CA implementation - * - * Revision 1.1 1999/06/07 21:46:45 wlupton - * working with simple pvtest program - * - */ diff --git a/src/pv/pvCa.h b/src/pv/pvCa.h deleted file mode 100644 index 562350c9..00000000 --- a/src/pv/pvCa.h +++ /dev/null @@ -1,119 +0,0 @@ -/*************************************************************************\ -This file is distributed subject to a Software License Agreement found -in the file LICENSE that is included with this distribution. -\*************************************************************************/ -/* Definitions for EPICS sequencer CA library (pvCa) - * - * William Lupton, W. M. Keck Observatory - */ - -#ifndef INCLpvCah -#define INCLpvCah - -#include "alarm.h" -#include "cadef.h" - -#include "shareLib.h" -#include "pv.h" - -/* - * System - */ -class caSystem : public pvSystem { - -public: - caSystem( int debug = 0 ); - ~caSystem(); - - virtual pvStat attach(); - virtual pvStat flush(); - virtual pvStat pend( double seconds = 0.0, int wait = FALSE ); - - virtual pvVariable *newVariable( const char *name, pvConnFunc func = NULL, - void *priv = NULL, int debug = 0 ); - -private: - ca_client_context *context_; /* channel access context of creator */ -}; - -/* - * Process variable - */ -class caVariable : public pvVariable { - -public: - caVariable( caSystem *system, const char *name, pvConnFunc func = NULL, - void *priv = NULL, int debug = 0 ); - ~caVariable(); - - virtual pvStat get( pvType type, unsigned count, pvValue *value ); - virtual pvStat getNoBlock( pvType type, unsigned count, pvValue *value ); - virtual pvStat getCallback( pvType type, unsigned count, - pvEventFunc func, void *arg = NULL ); - virtual pvStat put( pvType type, unsigned count, pvValue *value ); - virtual pvStat putNoBlock( pvType type, unsigned count, pvValue *value ); - virtual pvStat putCallback( pvType type, unsigned count, pvValue *value, - pvEventFunc func, void *arg = NULL ); - virtual pvStat monitorOn( pvType type, unsigned count, - pvEventFunc func, void *arg = NULL, - pvCallback **pCallback = NULL ); - virtual pvStat monitorOff( pvCallback *callback = NULL ); - - virtual int getConnected() const; - virtual pvType getType() const; - virtual unsigned getCount() const; - -private: - chid chid_; /* channel access id */ -}; - -#endif /* INCLpvCah */ - -/* - * pvCa.h,v - * Revision 1.4 2001/10/15 21:41:42 jhill - * fixed to match R3.14 CA client lib - * - * Revision 1.3 2001/07/05 14:42:16 mrk - * ca changed client contect - * - * Revision 1.2 2000/04/14 21:53:28 jba - * Changes for win32 build. - * - * Revision 1.1.1.1 2000/04/04 03:22:14 wlupton - * first commit of seq-2-0-0 - * - * Revision 1.11 2000/03/18 04:00:25 wlupton - * converted to use new configure scheme - * - * Revision 1.10 2000/03/16 02:11:29 wlupton - * supported KTL_ANYPOLY (plus misc other mods) - * - * Revision 1.9 2000/03/07 09:27:39 wlupton - * drastically reduced use of references - * - * Revision 1.8 2000/02/19 01:13:03 wlupton - * fixed log entry formatting - * - * Revision 1.7 2000/02/16 02:31:44 wlupton - * merged in v1.9.5 changes - * - * Revision 1.6 1999/07/07 18:50:34 wlupton - * supported full mapping from EPICS status and severity to pvStat and pvSevr - * - * Revision 1.5 1999/07/01 20:50:19 wlupton - * Working under VxWorks - * - * Revision 1.4 1999/06/10 00:35:04 wlupton - * demo sequencer working with pvCa - * - * Revision 1.3 1999/06/08 19:21:44 wlupton - * CA version working; about to use in sequencer - * - * Revision 1.2 1999/06/08 03:25:22 wlupton - * nearly complete CA implementation - * - * Revision 1.1 1999/06/07 21:46:46 wlupton - * working with simple pvtest program - * - */ diff --git a/src/pv/pvFile.cc b/src/pv/pvFile.cc deleted file mode 100644 index 7280cef1..00000000 --- a/src/pv/pvFile.cc +++ /dev/null @@ -1,337 +0,0 @@ -/* Implementation of demonstration EPICS sequencer file library (pvFile) - * - * William Lupton, W. M. Keck Observatory - */ - -#include <errno.h> -#include <math.h> -#include <stdio.h> -#include <string.h> - -#include "pvFile.h" - -//////////////////////////////////////////////////////////////////////////////// -/*+ - * Routine: fileSystem::fileSystem - * - * Purpose: fileSystem constructor - * - * Description: - */ -fileSystem::fileSystem( int debug ) : - pvSystem( debug ), - ifd_( fopen( "iFile", "r" ) ), - ofd_( fopen( "oFile", "a" ) ) -{ - if ( getDebug() > 0 ) - printf( "%8p: fileSystem::fileSystem( %d )\n", this, debug ); - - // check for file open failure - if ( ifd_ == NULL || ofd_ == NULL ) { - setError( -1, pvSevrERROR, pvStatERROR, "failed to open iFile or " - "oFile" ); - return; - } - - // initialize fd_set for select() - FD_ZERO( &readfds_ ); - FD_SET( fileno( ifd_ ), &readfds_ ); -} - -/*+ - * Routine: fileSystem::~fileSystem - * - * Purpose: fileSystem destructor - * - * Description: - */ -fileSystem::~fileSystem() -{ - if ( getDebug() > 0 ) - printf( "%8p: fileSystem::~fileSystem()\n", this ); - - if ( ifd_ != NULL ) fclose( ifd_ ); - if ( ofd_ != NULL ) fclose( ofd_ ); -} - -/*+ - * Routine: fileSystem::pend - * - * Purpose: fileSystem pend routine - * - * Description: - */ -pvStat fileSystem::pend( double seconds, int wait ) -{ - double secsAtStart; // OSI time at start - double secsNow; // OSI time now - double secsWaited; // number of seconds waited - - if ( getDebug() > 0 ) - printf( "%8p: fileSystem::pend( %g, %d )\n", this, seconds, wait ); - - // if not asked to wait, return immediately (there is no async activity) - if ( !wait ) - return pvStatOK; - - // utility macro for setting a timeval structure (not very portable) -#define DOUBLE_TO_TIMEVAL(_t) { ( time_t ) (_t), \ - ( long ) ( 1e6 * ( (_t) - ( int ) (_t) ) ) } - - // loop waiting for activity and handling events until the requested - // timeout has elapsed (always go through the loop at least once in case - // timeout is zero, which is a poll; negative timeout means for ever) - for ( pvTimeGetCurrentDouble( &secsAtStart ), secsWaited = 0.0; - secsWaited == 0.0 || seconds < 0.0 || secsWaited < seconds; - pvTimeGetCurrentDouble( &secsNow ), - secsWaited = secsNow - secsAtStart ) { - - // collect fds (copy because select() modifies them) - fd_set readfds = readfds_; - - // select (read fds only) - int nfd; - if ( seconds < 0.0 ) { - nfd = select( FD_SETSIZE, &readfds, NULL, NULL, NULL ); - } else { - struct timeval timeout = DOUBLE_TO_TIMEVAL( seconds - secsWaited ); - nfd = select( FD_SETSIZE, &readfds, NULL, NULL, &timeout ); - } - - // ignore EINTR; fail on other errors - if ( nfd < 0 ) { - if ( errno == EINTR ) { - continue; - } else { - setError( -errno, pvSevrMAJOR, pvStatERROR, "select failure" ); - return pvStatERROR; - } - } - - // continue on timeout - if ( nfd == 0 ) - continue; - - // otherwise, read and parse file - char line[132]; - while ( fgets( line, sizeof( line ), ifd_ ) != NULL ) { - char key[132]; - pvValue val; - if ( sscanf( line, "%s %s", key, val.stringVal[0] ) != 2 ) { - fprintf( stderr, "invalid line ignored: %s", line ); - } else { - - // ### create and set variable (very inefficient!) - pvVariable *var = newVariable( key ); - var->put( pvTypeSTRING, 1, &val ); - delete var; - } - } - } - - return pvStatOK; -} - -/*+ - * Routine: fileSystem::newVariable - * - * Purpose: fileSystem variable creation routine - * - * Description: - */ -pvVariable *fileSystem::newVariable( const char *name, pvConnFunc func, - void *priv, int debug ) -{ - if ( getDebug() > 0 ) - printf( "%8p: fileSystem::newVariable( %s, %p, %p, %d )\n", - this, name, func, priv, debug ); - - return new fileVariable( this, name, func, priv, debug ); -} - -//////////////////////////////////////////////////////////////////////////////// -/*+ - * Routine: fileVariable::fileVariable - * - * Purpose: fileVariable constructor - * - * Description: - */ -fileVariable::fileVariable( fileSystem *system, const char *name, pvConnFunc - func, void *priv, int debug ) : - pvVariable( system, name, func, priv, debug ) -{ - if ( getDebug() > 0 ) - printf( "%8p: fileVariable::fileVariable( %s, %d )\n", - this, name, debug ); -} - -/*+ - * Routine: fileVariable::~fileVariable - * - * Purpose: fileVariable destructor - * - * Description: - */ -fileVariable::~fileVariable() -{ - if ( getDebug() > 0 ) - printf( "%8p: fileVariable::~fileVariable()\n", this ); -} - -/*+ - * Routine: fileVariable::get - * - * Purpose: fileVariable blocking get routine - * - * Description: - */ -pvStat fileVariable::get( pvType type, unsigned count, pvValue *value ) -{ - if ( getDebug() > 0 ) - printf( "%8p: fileVariable::get( %d, %d )\n", this, type, count ); - - // ### not implemented (assumes string) - printf( "would read %s\n", getName() ); - strcpy( value->stringVal[0], "string" ); - return pvStatOK; -} - -/*+ - * Routine: fileVariable::getNoBlock - * - * Purpose: fileVariable non-blocking get routine - * - * Description: - */ -pvStat fileVariable::getNoBlock( pvType type, unsigned count, pvValue *value ) -{ - if ( getDebug() > 0 ) - printf( "%8p: fileVariable::getNoBlock( %d, %d )\n", this, - type, count ); - - // ### must block so can convert value - return get( type, count, value ); -} - - -/*+ - * Routine: fileVariable::getfilellback - * - * Purpose: fileVariable get with filellback routine - * - * Description: - */ -pvStat fileVariable::getCallback( pvType type, unsigned count, - pvEventFunc func, void *arg ) -{ - if ( getDebug() > 0 ) - printf( "%8p: fileVariable::getCallback( %d, %d )\n", - this, type, count ); - - // ### larger than needed (status not checked) - pvValue *value = new pvValue[count]; - pvStat stat = get( type, count, value ); - ( *func ) ( ( void * ) this, type, count, value, arg, stat ); - delete [] value; - return stat; -} - -/*+ - * Routine: fileVariable::put - * - * Purpose: fileVariable blocking put routine - * - * Description: - */ -pvStat fileVariable::put( pvType type, unsigned count, pvValue *value ) -{ - if ( getDebug() > 0 ) - printf( "%8p: fileVariable::put( %d, %d )\n", this, type, count ); - - // ### not implemented - printf( "would write %s\n", getName() ); - return pvStatOK; -} - -/*+ - * Routine: fileVariable::putNoBlock - * - * Purpose: fileVariable non-blocking put routine - * - * Description: - */ -pvStat fileVariable::putNoBlock( pvType type, unsigned count, pvValue *value ) -{ - if ( getDebug() > 0 ) - printf( "%8p: fileVariable::putNoBlock( %d, %d )\n", this, - type, count ); - - return put( type, count, value ); -} - -/*+ - * Routine: fileVariable::putfilellback - * - * Purpose: fileVariable put with filellback routine - * - * Description: - */ -pvStat fileVariable::putCallback( pvType type, unsigned count, pvValue *value, - pvEventFunc func, void *arg ) -{ - if ( getDebug() > 0 ) - printf( "%8p: fileVariable::putCallback( %d, %d )\n", - this, type, count ); - - pvStat stat = put( type, count, value ); - ( *func ) ( ( void * ) this, type, count, value, arg, stat ); - return stat; -} - -/*+ - * Routine: fileVariable::monitorOn - * - * Purpose: fileVariable monitor enable routine - * - * Description: - */ -pvStat fileVariable::monitorOn( pvType type, unsigned count, pvEventFunc func, - void *arg, pvCallback **pCallback ) -{ - if ( getDebug() > 0 ) - printf( "%8p: fileVariable::monitorOn( %d, %d )\n", - this, type, count ); - - // ### not implemented - printf( "would monitor %s\n", getName() ); - return pvStatOK; -} - -/*+ - * Routine: fileVariable::monitorOff - * - * Purpose: fileVariable monitor disable routine - * - * Description: - */ -pvStat fileVariable::monitorOff( pvCallback *callback ) -{ - if ( getDebug() > 0 ) - printf( "%8p: fileVariable::monitorOff()\n", this ); - - // ### not implemented - printf( "would cancel monitor on %s\n", getName() ); - return pvStatOK; -} - -/* - * pvFile.cc,v - * Revision 1.1.1.1 2000/04/04 03:22:15 wlupton - * first commit of seq-2-0-0 - * - * Revision 1.1 2000/03/31 23:00:06 wlupton - * initial insertion - * - */ - diff --git a/src/pv/pvFile.h b/src/pv/pvFile.h deleted file mode 100644 index 94418cb0..00000000 --- a/src/pv/pvFile.h +++ /dev/null @@ -1,82 +0,0 @@ -/*************************************************************************\ -This file is distributed subject to a Software License Agreement found -in the file LICENSE that is included with this distribution. -\*************************************************************************/ -/* Definitions for demonstration EPICS sequencer file library (pvFile) - * - * William Lupton, W. M. Keck Observatory - */ - -#ifndef INCLpvFileh -#define INCLpvFileh - -#include "osiSock.h" - -#include "pv.h" - -/* - * System - */ -class fileSystem : public pvSystem { - -public: - fileSystem( int debug = 0 ); - ~fileSystem(); - - virtual pvStat pend( double seconds = 0.0, int wait = FALSE ); - - virtual pvVariable *newVariable( const char *name, pvConnFunc func = NULL, - void *priv = NULL, int debug = 0 ); - -private: - FILE *ifd_; /* input file descriptor */ - FILE *ofd_; /* output file descriptor */ - fd_set readfds_; /* read file descriptor (contains fileno(ifd_)) */ -}; - -/* - * Process variable - */ -class fileVariable : public pvVariable { - -public: - fileVariable( fileSystem *system, const char *name, pvConnFunc func = NULL, - void *priv = NULL, int debug = 0 ); - ~fileVariable(); - - virtual pvStat get( pvType type, unsigned count, pvValue *value ); - virtual pvStat getNoBlock( pvType type, unsigned count, pvValue *value ); - virtual pvStat getCallback( pvType type, unsigned count, - pvEventFunc func, void *arg = NULL ); - virtual pvStat put( pvType type, unsigned count, pvValue *value ); - virtual pvStat putNoBlock( pvType type, unsigned count, pvValue *value ); - virtual pvStat putCallback( pvType type, unsigned count, pvValue *value, - pvEventFunc func, void *arg = NULL ); - virtual pvStat monitorOn( pvType type, unsigned count, - pvEventFunc func, void *arg = NULL, - pvCallback **pCallback = NULL ); - virtual pvStat monitorOff( pvCallback *callback = NULL ); - - virtual int getConnected() const { return TRUE; } - virtual pvType getType() const { return pvTypeSTRING; } - virtual unsigned getCount() const { return 1; } - -private: - char *value_; /* current value */ -}; - -#endif /* INCLpvFileh */ - -/* - * pvFile.h,v - * Revision 1.2 2001/02/23 20:45:22 jba - * Change for win32. - * - * Revision 1.1.1.1 2000/04/04 03:22:15 wlupton - * first commit of seq-2-0-0 - * - * Revision 1.1 2000/03/31 23:00:07 wlupton - * initial insertion - * - */ - diff --git a/src/pv/pvKtl.cc b/src/pv/pvKtl.cc deleted file mode 100644 index 020fa493..00000000 --- a/src/pv/pvKtl.cc +++ /dev/null @@ -1,1416 +0,0 @@ -/* Implementation of EPICS sequencer KTL library (pvKtl) - * - * William Lupton, W. M. Keck Observatory - */ - -// ### check all object creation and call cantProceed on failure - -// ### review locking policy (need to be clear on why, how and when) - -#include <stdio.h> -#include <string.h> -#include <sys/time.h> -#include <sys/types.h> - -#include "gpHash.h" - -#include "pvKtl.h" -#include "pvKtlCnv.h" - -/* handlers */ -static void connectionHandler( ktlKeyword *variable, char *name, - int connected ); -static void accessHandler( char *name, pvCallback *callback, - KTL_ANYPOLY *ktlValue, KTL_CONTEXT *context ); -static void monitorHandler( char *name, ktlKeyword *keyword, - KTL_ANYPOLY *ktlValue, KTL_CONTEXT *context ); -static void commonHandler( char *name, pvCallback *callback, - KTL_ANYPOLY *ktlValue, KTL_CONTEXT *context ); - -/* utilities */ -static char *serviceName( const char *name ); - /* service name from "srv.key" name */ -static char *keywordName( const char *name ); - /* keyword name from "srv.key" name */ -static pvSevr sevrFromKTL( int status ); - /* severity as pvSevr */ -static pvStat statFromKTL( int status ); - /* status as pvStat */ -static pvType typeFromKTL( int type ); - /* KTL type as pvType */ -static int copyFromKTL( int ktlFlags, KTL_DATATYPE ktlType, int ktlCount, - const KTL_ANYPOLY *ktlValue, pvType type, int count, - pvValue *value ); - /* copy KTL value to pvValue */ -static int copyToKTL( pvType type, int count, const pvValue *value, - KTL_DATATYPE ktlType, int ktlCount, KTL_POLYMORPH *ktlValue ); - /* copy pvValue to KTL value */ -static int mallocKTL( KTL_DATATYPE ktlType, int ktlCount, - KTL_POLYMORPH *ktlValue ); - /* alloc dynamic data ref'd by value */ -static void freeKTL( KTL_DATATYPE ktlType, KTL_POLYMORPH *ktlValue ); - /* free dynamic data ref'd by value */ - -/* invoke KTL function and send error details to system or variable object */ -#define INVOKE(_function) \ - do { \ - int _status = _function; \ - if ( _status >= 0 ) { \ - setStatus( _status ); \ - setStat( pvStatOK ); \ - } \ - else \ - setError( _status, sevrFromKTL( _status ), \ - statFromKTL( _status ), ktl_get_errtxt() ); \ - } while ( FALSE ) - -/* lock / unlock shorthands */ -#define LOCK getSystem()->lock() -#define UNLOCK getSystem()->unlock() - -//////////////////////////////////////////////////////////////////////////////// -/*+ - * Routine: ktlSystem::ktlSystem - * - * Purpose: ktlSystem constructor - * - * Description: - */ -ktlSystem::ktlSystem( int debug ) : - pvSystem( debug ), - attach_( FALSE ) -{ - if ( getDebug() > 0 ) - printf( "%8p: ktlSystem::ktlSystem( %d )\n", this, debug ); -} - -/*+ - * Routine: ktlSystem::~ktlSystem - * - * Purpose: ktlSystem destructor - * - * Description: - */ -ktlSystem::~ktlSystem() -{ - if ( getDebug() > 0 ) - printf( "%8p: ktlSystem::~ktlSystem()\n", this ); -} - -/*+ - * Routine: ktlSystem::attach - * - * Purpose: ktlSystem attach routine - * - * Description: - */ -pvStat ktlSystem::attach() -{ - if ( getDebug() > 0 ) - printf( "%8p: ktlSystem::attach()\n", this ); - - // attach all services that are already open - for ( ktlService *service = ktlService::first(); service != NULL; - service = service->next() ) - ( void ) ktl_ioctl( service->getHandle(), KTL_ATTACH ); - - // attach all future services as they are opened - attach_ = TRUE; - - return pvStatOK; -} - -/*+ - * Routine: ktlSystem::flush - * - * Purpose: ktlSystem flush routine - * - * Description: - */ -pvStat ktlSystem::flush() -{ - if ( getDebug() > 1 ) - printf( "%8p: ktlSystem::flush()\n", this ); - - // KTL has no way of deferring buffer flush - return pvStatOK; -} - -/*+ - * Routine: ktlSystem::pend - * - * Purpose: ktlSystem pend routine - * - * Description: - */ -pvStat ktlSystem::pend( double seconds, int wait ) -{ - double secsAtStart; // OSI time at start - double secsNow; // OSI time now - double secsWaited; // number of seconds waited - - if ( getDebug() > 1 ) - printf( "%8p: ktlSystem::pend( %g, %d )\n", this, seconds, wait ); - - // if wait==FALSE, should wait for all operations initiated via KTL_NOWAIT - // (assuming that the keyword library really supports KTL_NOWAIT as - // documented in KSD/28, which is very unlikely) - // ### for now, ignore the above issue - - // utility macro for setting a timeval structure (not very portable) -#define DOUBLE_TO_TIMEVAL(_t) { ( time_t ) (_t), \ - ( long ) ( 1e6 * ( (_t) - ( int ) (_t) ) ) } - - // loop waiting for activity and handling events until the requested - // timeout has elapsed (always go through the loop at least once in case - // timeout is zero, which is a poll; negative timeout means for ever) - for ( pvTimeGetCurrentDouble( &secsAtStart ), secsWaited = 0.0; - secsWaited == 0.0 || seconds < 0.0 || secsWaited < seconds; - pvTimeGetCurrentDouble( &secsNow ), - secsWaited = secsNow - secsAtStart ) { - - // collect fds from all services - fd_set *readfds = ktlService::getFdsetsAll(); - - // select (read fds only) - int nfd; - if ( seconds < 0.0 ) { - nfd = select( FD_SETSIZE, readfds, NULL, NULL, NULL ); - } else { - // ### hard-code 0.1s pending better solution - //struct timeval timeout = DOUBLE_TO_TIMEVAL( seconds - secsWaited); - struct timeval timeout = DOUBLE_TO_TIMEVAL( 0.1 ); - nfd = select( FD_SETSIZE, readfds, NULL, NULL, &timeout ); - } - - // ignore EINTR; fail on other errors - if ( nfd < 0 ) { - if ( errno == EINTR ) { - continue; - } else { - setError( -errno, pvSevrMAJOR, pvStatERROR, "select failure" ); - return pvStatERROR; - } - } - - // continue or break on timeout (depending on "wait"; not an error) - if ( nfd == 0 ) { - if ( wait ) - continue; - else - break; - } - - // otherwise, dispatch all open services - LOCK; - pvStat stat = ktlService::dispatchAll(); - UNLOCK; - if ( stat != pvStatOK ) { - return pvStatERROR; - } - } - - return pvStatOK; -} - -/*+ - * Routine: ktlSystem::newVariable - * - * Purpose: ktlSystem variable creation routine - * - * Description: - */ -pvVariable *ktlSystem::newVariable( const char *name, pvConnFunc func, void *priv, - int debug ) -{ - if ( getDebug() > 0 ) - printf( "%8p: ktlSystem::newVariable( %s, %p, %p, %d )\n", - this, name, func, priv, debug ); - - return new ktlVariable( this, name, func, priv, debug ); -} - -//////////////////////////////////////////////////////////////////////////////// -/* - * list of ktlService objects (statically initialized) - */ -ELLLIST ktlService::list_ = {{NULL,NULL}, 0}; - -/*+ - * Routine: ktlService::ktlService - * - * Purpose: ktlService constructor - * - * Description: - */ -ktlService::ktlService( ktlSystem *system, const char *name, int debug ) : - debug_( debug ), - name_( strdup( name ) ), - flags_( 0 ), - keys_( NULL ), - status_( 0 ), - sevr_( pvSevrNONE ), - stat_( pvStatOK ), - mess_( NULL ) -{ - if ( getDebug() > 0 ) - printf( "%8p: ktlService::ktlService( %s, %d )\n", - this, name, debug ); - - handle_ = NULL; - INVOKE( ktl_open( name_, "keyword", 0, &handle_ ) ); - - if ( system->getAttach() ) - ( void ) ktl_ioctl( handle_, KTL_ATTACH ); - - // use KTL_SUPERSUPP to see whether KTL_SUPER is supported - ( void ) ktl_ioctl( handle_, KTL_SUPERSUPP, &flags_ ); - flags_ = flags_ ? ( KTL_SUPER | KTL_STAMP ) : 0; - - // create keyword hash table (aborts on failure) - gphInitPvt( &keys_, 256 ); - - // ### not calling FDREG but perhaps should try to? - - // link into list of services - node_.setData( this ); - ellAdd( &list_, ( ELLNODE * ) &node_ ); -} - -/*+ - * Routine: ktlService::~ktlService - * - * Purpose: ktlService destructor - * - * Description: - */ -ktlService::~ktlService() -{ - if ( getDebug() > 0 ) - printf( "%8p: ktlService::~ktlService()\n", this ); - - // remove from list of services - ellDelete( &list_, ( ELLNODE * ) &node_ ); - - // free keyword hash table memory - gphFreeMem( keys_ ); - - // close KTL connection (ignore failure) - INVOKE( ktl_close( handle_ ) ); - - // free name - if ( name_ != NULL ) - free( name_ ); -} - -/*+ - * Routine: ktlService::getService - * - * Purpose: ktlService static accessor routine - * - * Description: - */ -ktlService *ktlService::getService( ktlSystem *system, char *name, int debug ) -{ - // search for service with this name; return if found; create if not - ktlService *service; - for ( service = ktlService::first(); service != NULL; - service = service->next() ) { - if ( strcmp( service->name_, name ) == 0 ) - break; - } - - return ( service != NULL ) ? service : new ktlService( system, name, debug); -} - -/*+ - * Routine: ktlService::first - * - * Purpose: ktlService first service routine - * - * Description: - */ -ktlService *ktlService::first() -{ - ktlNode *node = ( ktlNode * ) ellFirst( &list_ ); - return ( node != NULL ) ? ( ktlService * ) node->getData() : NULL; -} - -/*+ - * Routine: ktlService::next - * - * Purpose: ktlService next service routine - * - * Description: - */ -ktlService *ktlService::next() const -{ - ktlNode *node = ( ktlNode * ) ellNext( ( ELLNODE * ) &node_ ); - return ( node != NULL ) ? ( ktlService * ) node->getData() : NULL; -} - -/*+ - * Routine: ktlService::add - * - * Purpose: ktlService add keyword to hash table routine - * - * Description: - */ -void ktlService::add( const ktlKeyword *keyword ) -{ - // ignore failure (means keyword had already been added) - GPHENTRY *ent = gphAdd( keys_, keyword->getKeyName(), NULL ); - if ( ent != NULL ) ent->userPvt = ( void * ) keyword; -} - -/*+ - * Routine: ktlService::remove - * - * Purpose: ktlService remove keyword from hash table routine - * - * Description: - */ -void ktlService::remove( const ktlKeyword *keyword ) -{ - gphDelete( keys_, keyword->getKeyName(), NULL ); -} - -/*+ - * Routine: ktlService::find - * - * Purpose: ktlService find keyword in hash table routine - * - * Description: - */ -ktlKeyword *ktlService::find( const char *keyName ) -{ - GPHENTRY *ent = gphFind( keys_, keyName, NULL ); - return ( ent != NULL ) ? ( ktlKeyword * ) ent->userPvt : NULL; -} - -/*+ - * Routine: ktlService::getFdsetsAll - * - * Purpose: ktlService routine to return fd_set combining fds from all - * open services - * - * Description: - */ -fd_set *ktlService::getFdsetsAll() -{ - static fd_set fdset; - FD_ZERO( &fdset ); - - for ( ktlService *service = ktlService::first(); service != NULL; - service = service->next() ) { - - if ( service->handle_ == NULL ) - continue; - - fd_set temp; - ( void ) ktl_ioctl( service->handle_, KTL_FDSET, &temp ); - for ( int fd = 0; fd < FD_SETSIZE; fd++ ) { - if ( FD_ISSET( fd, &temp ) ) { - FD_SET( fd, &fdset ); - } - } - } - - return &fdset; -} - -/*+ - * Routine: ktlService::dispatchAll - * - * Purpose: ktlService routine to dispatch events on all open services - * - * Description: - */ -pvStat ktlService::dispatchAll() -{ - for ( ktlService *service = ktlService::first(); service != NULL; - service = service->next() ) { - - if ( service->handle_ == NULL ) - continue; - - if ( ktl_dispatch( service->handle_ ) < 0 ) { - service->setError( -1, pvSevrMAJOR, pvStatERROR, - "dispatch failure" ); - return pvStatERROR; - } - } - - return pvStatOK; -} - -/*+ - * Routine: ktlService::setError() - * - * Purpose: Copy error information - * - * Description: - * - * Function value: - */ -void ktlService::setError( int status, pvSevr sevr, pvStat stat, - const char *mess ) -{ - status_ = status; - sevr_ = sevr; - stat_ = stat; - mess_ = Strdcpy( mess_, mess ); -} - -//////////////////////////////////////////////////////////////////////////////// -/*+ - * Routine: ktlKeyword::ktlKeyword - * - * Purpose: ktlKeyword constructor - * - * Description: - */ -ktlKeyword::ktlKeyword( ktlService *service, const char *keyName, int debug ) : - debug_( debug ), - service_( service ), - keyName_( strdup( keyName ) ), - monitored_( FALSE ), - status_( 0 ), - sevr_( pvSevrNONE ), - stat_( pvStatOK ), - mess_( NULL ) -{ - if ( getDebug() > 0 ) - printf( "%8p: ktlKeyword::ktlKeyword( %d )\n", this, debug ); - - // add to service's hash table of keywords - service->add( this ); - - // initialize list of associated variables - ellInit( &list_ ); -} - -/*+ - * Routine: ktlKeyword::~ktlKeyword - * - * Purpose: ktlKeyword destructor - * - * Description: - */ -ktlKeyword::~ktlKeyword() -{ - if ( getDebug() > 0 ) - printf( "%8p: ktlKeyword::~ktlKeyword()\n", this ); - - // remove any remaining associated variables from list and free list - for ( ktlVariable *variable = first(); variable != NULL; - variable = next( variable ) ) { - remove( variable ); - } - ellFree( &list_ ); - - // remove from service's hash table of keywords - service_->remove( this ); - - // free keyword name - if ( keyName_ != NULL ) - free( ( char * ) keyName_ ); -} - -/*+ - * Routine: ktlKeyword::getKeyword - * - * Purpose: ktlKeyword static accessor routine - * - * Description: - */ -ktlKeyword *ktlKeyword::getKeyword( ktlService *service, const char *keyName, - int debug ) -{ - // search for keyword with this name; return if found; create if not - ktlKeyword *keyword = service->find( keyName ); - return ( keyword != NULL ) ? keyword : - new ktlKeyword( service, keyName, debug ); -} - -/*+ - * Routine: ktlKeyword::add - * - * Purpose: ktlKeyword add variable routine - * - * Description: - */ -int ktlKeyword::add( ktlVariable *variable ) -{ - if ( getDebug() > 0 ) - printf( "%8p: ktlKeyword::add( %p )\n", this, variable ); - - ktlNode *node = variable->getNode(); - node->setData( variable ); - ellAdd( &list_, ( ELLNODE * ) node ); - - // attempt to enable connection handler - INVOKE( ktl_ioctl( variable->getHandle(), KTL_KEYCONNREG, - variable->getKeyName(), connectionHandler, this ) ); - return getStatus(); -} - -/*+ - * Routine: ktlKeyword::remove - * - * Purpose: ktlKeyword remove variable routine - * - * Description: - */ -void ktlKeyword::remove( ktlVariable *variable ) -{ - if ( getDebug() > 0 ) - printf( "%8p: ktlKeyword::remove( %p )\n", this, variable ); - - ( void ) monitorOff( variable ); - ellDelete( &list_, ( ELLNODE * ) variable->getNode() ); -} - -/*+ - * Routine: ktlKeyword::monitorOn - * - * Purpose: ktlKeyword monitor on variable routine - * - * Description: - */ -int ktlKeyword::monitorOn( ktlVariable *variable ) -{ - if ( getDebug() > 0 ) - printf( "%8p: ktlKeyword::monitorOn( %p, %d )\n", this, variable, - monitored_ ); - - if ( ! monitored_++ ) { - KTL_CONTEXT *context; - INVOKE( ktl_context_create( variable->getHandle(), ( int(*)() ) - monitorHandler, NULL, NULL, &context ) ); - if ( getStat() == pvStatOK ) { - int flags = KTL_ENABLEREADCONT | KTL_NOPRIME | variable->getFlags(); - INVOKE( ktl_read( variable->getHandle(), flags, variable-> - getKeyName(), ( void * ) this, NULL, context ) ); - ( void ) ktl_context_delete( context ); - } - } - return getStatus(); -} - -/*+ - * Routine: ktlKeyword::monitorOff - * - * Purpose: ktlKeyword monitor off variable routine - * - * Description: - */ -int ktlKeyword::monitorOff( ktlVariable *variable ) -{ - if ( getDebug() > 0 ) - printf( "%8p: ktlKeyword::monitorOff( %p, %d )\n", this, variable, - monitored_ ); - - if ( ! --monitored_ ) { - int flags = KTL_DISABLEREADCONT | variable->getFlags(); - INVOKE( ktl_read( variable->getHandle(), flags, variable->getKeyName(), - NULL, NULL, NULL ) ); - } - return getStatus(); -} - -/*+ - * Routine: ktlKeyword::first - * - * Purpose: ktlKeyword first variable routine - * - * Description: - */ -ktlVariable *ktlKeyword::first() -{ - ktlNode *node = ( ktlNode * ) ellFirst( &list_ ); - return ( node != NULL ) ? ( ktlVariable * ) node->getData() : NULL; -} - -/*+ - * Routine: ktlKeyword::next - * - * Purpose: ktlKeyword next variable routine - * - * Description: - */ -ktlVariable *ktlKeyword::next( ktlVariable *variable ) -{ - ktlNode *node = ( ktlNode * ) ellNext( ( ELLNODE * ) variable->getNode() ); - return ( node != NULL ) ? ( ktlVariable * ) node->getData() : NULL; -} - -/*+ - * Routine: ktlKeyword::setError() - * - * Purpose: Copy error information - * - * Description: - * - * Function value: - */ -void ktlKeyword::setError( int status, pvSevr sevr, pvStat stat, - const char *mess ) -{ - status_ = status; - sevr_ = sevr; - stat_ = stat; - mess_ = Strdcpy( mess_, mess ); -} - -//////////////////////////////////////////////////////////////////////////////// -/*+ - * Routine: ktlVariable::ktlVariable - * - * Purpose: ktlVariable constructor - * - * Description: - */ -ktlVariable::ktlVariable( ktlSystem *system, const char *name, pvConnFunc func, - void *priv, int debug ) : - pvVariable( system, name, func, priv, debug ), - service_( ktlService::getService( system, serviceName( name ), getDebug())), - keyName_( strdup( keywordName( name ) ) ), - keyword_( ktlKeyword::getKeyword( service_, keyName_, getDebug() ) ), - type_( KTL_DOUBLE ), - count_( 1 ), - readNot_( FALSE ), - writeNot_( FALSE ), - readCont_( FALSE ), - connected_( FALSE ), - monitor_( NULL ) -{ - if ( getDebug() > 0 ) - printf( "%8p: ktlVariable::ktlVariable( %s, %d )\n", - this, name, debug ); - - // use KTL_FLAGS to check whether keyword exists - // ### ignored at the moment (don't want to abort part of constructor - // because complicates destructor) - int flags; - INVOKE( ktl_ioctl( getHandle(), KTL_FLAGS, keyName_, &flags ) ); - - // cache keyword attributes - INVOKE( ktl_ioctl( getHandle(), KTL_TYPE | KTL_BINOUT, keyName_, - &type_, &count_ ) ); - - KTL_IMPL_CAPS impl_caps; - INVOKE( ktl_ioctl( getHandle(), KTL_IMPLCAPS, &impl_caps ) ); - // ### will be FALSE (should have per keyword inquiry) - readNot_ = impl_caps.read_notify; - - INVOKE( ktl_ioctl( getHandle(), KTL_CANWRITENOTIFY, keyName_, - &writeNot_ ) ); - INVOKE( ktl_ioctl( getHandle(), KTL_CANREADCONTINUOUS, keyName_, - &readCont_ ) ); - - // monitor the keyword (won't result in any user callbacks being called - // because no callback object has yet been allocated; is done to force - // a connection request to be sent to the control system) - INVOKE( keyword_->monitorOn( this ) ); - - // add variable to keyword object's list; this enables the connection - // handler (interpret error as meaning that KTL_KEYCONNREG is not - // supported, so mark connected and invoke function, if supplied) - INVOKE( keyword_->add( this ) ); - if ( getStat() != pvStatOK ) { - connected_ = TRUE; - if ( func != NULL ) - ( *func ) ( ( void * ) this, connected_ ); - } -} - -/*+ - * Routine: ktlVariable::~ktlVariable - * - * Purpose: ktlVariable destructor - * - * Description: - */ -ktlVariable::~ktlVariable() -{ - if ( getDebug() > 0 ) - printf( "%8p: ktlVariable::~ktlVariable( %s )\n", this, keyName_ ); - - // remove variable from keyword object's list - keyword_->remove( this ); - - // ### if this is last variable for this keyword, destroy keyword - - // ### if this is last variable for this service, destroy service - - // free keyword name - if ( keyName_ != NULL ) - free( ( void * ) keyName_ ); -} - -/*+ - * Routine: ktlVariable::get - * - * Purpose: ktlVariable blocking get routine - * - * Description: - */ -pvStat ktlVariable::get( pvType type, int count, pvValue *value ) -{ - if ( getDebug() > 0 ) - printf( "%8p: ktlVariable::get( %d, %d )\n", this, type, count ); - - KTL_ANYPOLY ktlValue; - - LOCK; - INVOKE( ktl_read( getHandle(), KTL_WAIT | getFlags() , keyName_, NULL, - &ktlValue, NULL ) ); - UNLOCK; - - if ( getStat() == pvStatOK ) { - INVOKE( copyFromKTL( getFlags(), type_, count_, &ktlValue, - type, count, value ) ); - freeKTL( type_, KTL_POLYDATA( getFlags(), &ktlValue ) ); - } - - return getStat(); -} - -/*+ - * Routine: ktlVariable::getNoBlock - * - * Purpose: ktlVariable non-blocking get routine - * - * Description: - */ -pvStat ktlVariable::getNoBlock( pvType type, int count, pvValue *value ) -{ - if ( getDebug() > 0 ) - printf( "%8p: ktlVariable::getNoBlock( %d, %d )\n", this, - type, count ); - - KTL_ANYPOLY ktlValue; - - LOCK; - INVOKE( ktl_read( getHandle(), KTL_NOWAIT | getFlags(), keyName_, NULL, - &ktlValue, NULL ) ); - UNLOCK; - - if ( getStat() == pvStatOK ) { - INVOKE( copyFromKTL( getFlags(), type_, count_, &ktlValue, - type, count, value ) ); - freeKTL( type_, KTL_POLYDATA( getFlags(), &ktlValue ) ); - } - - return getStat(); -} - -/*+ - * Routine: ktlVariable::getCallback - * - * Purpose: ktlVariable get with callback routine - * - * Description: - */ -pvStat ktlVariable::getCallback( pvType type, int count, - pvEventFunc func, void *arg ) -{ - if ( getDebug() > 0 ) - printf( "%8p: ktlVariable::getCallback( %d, %d, %p, %p )\n", - this, type, count, func, arg ); - - if ( !readNot_ ) { - // ### larger than needed (status not checked) - pvValue *value = new pvValue[count]; - pvStat stat = get( type, count, value ); - ( *func ) ( ( void * ) this, type, count, value, arg, stat ); - delete [] value; - - } else { - pvCallback *callback = new pvCallback( this, type, count, func, arg, - getDebug() ); - - KTL_CONTEXT *context; - INVOKE( ktl_context_create( getHandle(), ( int(*)() ) accessHandler, - NULL, NULL, &context ) ); - if ( getStat() == pvStatOK ) { - LOCK; - INVOKE( ktl_read( getHandle(), KTL_NOTIFY | getFlags(), keyName_, - ( void * ) callback, NULL, context ) ); - context->state = KTL_MESSAGE_STATE; - UNLOCK; - } - } - - return getStat(); -} - -/*+ - * Routine: ktlVariable::put - * - * Purpose: ktlVariable blocking put routine - * - * Description: - */ -pvStat ktlVariable::put( pvType type, int count, pvValue *value ) -{ - if ( getDebug() > 0 ) - printf( "%8p: ktlVariable::put( %d, %d )\n", this, type, count ); - - KTL_POLYMORPH ktlValue; - - INVOKE( copyToKTL( type, count, value, type_, count_, &ktlValue ) ); - if ( getStat() == pvStatOK ) { - LOCK; - INVOKE( ktl_write( getHandle(), KTL_WAIT, keyName_, NULL, &ktlValue, - NULL ) ); - UNLOCK; - freeKTL( type_, &ktlValue ); - } - - return getStat(); -} - -/*+ - * Routine: ktlVariable::putNoBlock - * - * Purpose: ktlVariable non-blocking put routine - * - * Description: - */ -pvStat ktlVariable::putNoBlock( pvType type, int count, pvValue *value ) -{ - if ( getDebug() > 0 ) - printf( "%8p: ktlVariable::putNoBlock( %d, %d )\n", this, - type, count ); - - KTL_POLYMORPH ktlValue; - - INVOKE( copyToKTL( type, count, value, type_, count_, &ktlValue ) ); - if ( getStat() == pvStatOK ) { - LOCK; - INVOKE( ktl_write( getHandle(), KTL_NOWAIT, keyName_, NULL, &ktlValue, - NULL ) ); - UNLOCK; - freeKTL( type_, &ktlValue ); - } - - return getStat(); -} - -/*+ - * Routine: ktlVariable::putCallback - * - * Purpose: ktlVariable put with callback routine - * - * Description: - */ -pvStat ktlVariable::putCallback( pvType type, int count, pvValue *value, - pvEventFunc func, void *arg ) -{ - if ( getDebug() > 0 ) - printf( "%8p: ktlVariable::putCallback( %d, %d )\n", - this, type, count ); - - if ( !writeNot_ ) { - pvStat stat = put( type, count, value ); - ( *func ) ( ( void * ) this, type, count, value, arg, stat ); - - } else { - pvCallback *callback = new pvCallback( this, type, count, func, arg, - getDebug() ); - - KTL_POLYMORPH ktlValue; - - INVOKE( copyToKTL( type, count, value, type_, count_, &ktlValue ) ); - if ( getStat() == pvStatOK ) { - KTL_CONTEXT *context; - INVOKE( ktl_context_create( getHandle(), ( int(*)() ) accessHandler, - NULL, NULL, &context ) ); - if ( getStat() == pvStatOK ) { - LOCK; - INVOKE( ktl_write( getHandle(), KTL_NOTIFY, keyName_, - ( void * ) callback, &ktlValue, context ) ); - context->state = KTL_MESSAGE_STATE; - UNLOCK; - } - } - freeKTL( type_, &ktlValue ); - } - - return getStat(); -} - -/*+ - * Routine: ktlVariable::monitorOn - * - * Purpose: ktlVariable monitor enable routine - * - * Description: - */ -pvStat ktlVariable::monitorOn( pvType type, int count, pvEventFunc func, - void *arg, pvCallback **pCallback ) -{ - if ( getDebug() > 0 ) - printf( "%8p: ktlVariable::monitorOn( %s, %d, %d )\n", - this, keyName_, type, count ); - - if ( !readCont_ ) { - setError( -1, pvSevrMAJOR, pvStatERROR, "monitoring not supported" ); - if ( pCallback != NULL ) - *pCallback = NULL; - - // ### can only have single monitor enabled per variable (can have - // multiple variables per keyword though) - } else if ( monitor_ != NULL ) { - setError( -1, pvSevrMAJOR, pvStatERROR, "monitor already enabled" ); - if ( pCallback != NULL ) - *pCallback = NULL; - } else { - monitor_ = new pvCallback( this, type, count, func, arg, getDebug() ); - LOCK; - INVOKE( keyword_->monitorOn( this ) ); - UNLOCK; - if ( pCallback != NULL ) - *pCallback = monitor_; - } - - return getStat(); -} - -/*+ - * Routine: ktlVariable::monitorOff - * - * Purpose: ktlVariable monitor disable routine - * - * Description: - */ -pvStat ktlVariable::monitorOff( pvCallback *callback ) -{ - if ( getDebug() > 0 ) - printf( "%8p: ktlVariable::monitorOff()\n", this ); - - LOCK; - keyword_->monitorOff( this ); - UNLOCK; - - // ### are we sure that no further monitors can be delivered? - if ( monitor_ != NULL ) { - delete monitor_; - monitor_ = NULL; - } - - return getStat(); -} - -/*+ - * Routine: ktlVariable::getType - * - * Purpose: ktlVariable "what type are we?" routine - * - * Description: - */ -pvType ktlVariable::getType() const -{ - if ( getDebug() > 1 ) - printf( "%8p: ktlVariable::getType()\n", this ); - - return typeFromKTL( type_ ); -} - -//////////////////////////////////////////////////////////////////////////////// -/*+ - * Routine: connectionHandler - * - * Purpose: KTL connection handler - * - * Description: - */ -static void connectionHandler( ktlKeyword *keyword, char *, int connected ) -{ - if ( keyword->getDebug() > 0 ) - printf( "%8p: ktlKeyword::connectionHandler( %d )\n", keyword, - connected ); - - for ( ktlVariable *variable = keyword->first(); variable != NULL; - variable = keyword->next( variable ) ) { - - if ( variable->getDebug() > 0 ) - printf( "%8p: ktlVariable::connectionHandler( %s, %d )\n", variable, - variable->getKeyName(), connected ); - - variable->setConnected( connected ); - - pvConnFunc func = variable->getFunc(); - if ( func != NULL ) - ( *func ) ( ( void * ) variable, connected ); - } -} - -/*+ - * Routine: accessHandler - * - * Purpose: KTL get/put completion event handler - * - * Description: - */ -static void accessHandler( char *keyName, pvCallback *callback, - KTL_ANYPOLY *ktlValue, KTL_CONTEXT *context ) -{ - ktlVariable *variable = ( ktlVariable * ) callback->getVariable(); - int ktlFlags = variable->getFlags(); - - if ( variable->getDebug() > 0 ) - printf( "%8p: ktlVariable::accessHandler( %s, %d )\n", variable, - variable->getKeyName(), KTL_POLYDATA(ktlFlags,ktlValue)->i ); - - commonHandler( keyName, callback, ktlValue, context ); - delete callback; -} - -/*+ - * Routine: monitorHandler - * - * Purpose: KTL monitor event handler - * - * Description: - */ -static void monitorHandler( char *keyName, ktlKeyword *keyword, - KTL_ANYPOLY *ktlValue, KTL_CONTEXT *context ) -{ - int ktlFlags = keyword->getFlags(); - - if ( keyword->getDebug() > 0 ) - printf( "%8p: ktlKeyword::monitorHandler( %d )\n", keyword, - KTL_POLYDATA(ktlFlags,ktlValue)->i ); - - for ( ktlVariable *variable = keyword->first(); variable != NULL; - variable = keyword->next( variable ) ) { - - if ( variable->getDebug() > 0 ) - printf( "%8p: ktlVariable::monitorHandler( %s )\n", variable, - variable->getKeyName() ); - - pvCallback *monitor = variable->getMonitor(); - if ( monitor != NULL ) - commonHandler( keyName, monitor, ktlValue, context ); - } -} - -/*+ - * Routine: commonHandler - * - * Purpose: KTL completion/monitor event handler (work routine) - * - * Description: - */ -static void commonHandler( char *, pvCallback *callback, - KTL_ANYPOLY *ktlValue, KTL_CONTEXT *context ) -{ - pvEventFunc func = callback->getFunc(); - ktlVariable *variable = ( ktlVariable * ) callback->getVariable(); - int ktlFlags = variable->getFlags(); - KTL_DATATYPE ktlType = variable->getKtlType(); - int ktlCount = variable->getCount(); - pvType type = callback->getType(); - int count = callback->getCount(); - void *arg = callback->getArg(); - - // ### larger than needed (status not checked) - pvValue *value = new pvValue[count]; - // ### function not called if copy from KTL failed - if ( copyFromKTL( ktlFlags, ktlType, ktlCount, ktlValue, - type, count, value ) >= 0 ) { - ( *func ) ( ( void * ) variable, type, count, value, arg, - statFromKTL( context->status ) ); - } - delete [] value; -} - -//////////////////////////////////////////////////////////////////////////////// -/*+ - * Routine: serviceName() - * - * Purpose: service name from "srv.key" name - * - * Description: - */ -static char *serviceName( const char *name ) -{ - static char temp[256]; - size_t len = strcspn( name, "." ); - strncpy( temp, name, len ); - temp[255] = '\0'; - - return temp; -} - -/*+ - * Routine: keywordName - * - * Purpose: keyword name from "srv.key" name - * - * Description: - */ -static char *keywordName( const char *name ) -{ - static char temp[256]; - size_t len = strcspn( name, "." ); - strncpy( temp, name + len + 1, 256 - len - 1 ); - temp[255] = '\0'; - - return temp; -} - -/*+ - * Routine: sevrFromKTL - * - * Purpose: extract pvSevr from KTL status - * - * Description: - */ -static pvSevr sevrFromKTL( int status ) -{ - return ( status < 0 ) ? pvSevrERROR : pvSevrNONE; -} - -/*+ - * Routine: statFromKTL - * - * Purpose: extract pvStat from KTL status - * - * Description: - */ -static pvStat statFromKTL( int status ) -{ - pvSevr sevr = sevrFromKTL( status ); - return ( sevr == pvSevrNONE || sevr == pvSevrMINOR ) ? - pvStatOK : pvStatERROR; -} - -/*+ - * Routine: typeFromKTL - * - * Purpose: extract pvType from KTL type - * - * Description: - */ -static pvType typeFromKTL( int type ) -{ - switch ( type ) { - case KTL_INT: return pvTypeLONG; - case KTL_BOOLEAN: return pvTypeLONG; - case KTL_ENUM: return pvTypeLONG; - case KTL_ENUMM: return pvTypeLONG; - case KTL_MASK: return pvTypeLONG; - case KTL_FLOAT: return pvTypeFLOAT; - case KTL_DOUBLE: return pvTypeDOUBLE; - case KTL_STRING: return pvTypeSTRING; - case KTL_INT_ARRAY: return pvTypeLONG; - case KTL_FLOAT_ARRAY: return pvTypeFLOAT; - case KTL_DOUBLE_ARRAY: return pvTypeDOUBLE; - default: return pvTypeERROR; - } -} - -/*+ - * Routine: copyFromKTL - * - * Purpose: copy KTL value to pvValue - * - * Description: - */ -static int copyFromKTL( int ktlFlags, KTL_DATATYPE ktlType, int ktlCount, - const KTL_ANYPOLY *ktlValue, pvType type, int count, - pvValue *value ) -{ - // map types to ktlCnv's types (indices into conversion table) - ktlCnv::type inpType = ktlCnv::getType( ktlType ); - ktlCnv::type outType = ktlCnv::getType( type ); - - // if type is not simple, copy status, severity and time stamp - // (note assumption that STAT and SEVR can be cast; this is in fact true) - if ( !PV_SIMPLE( type ) ) { - epicsTimeStamp stamp; - if ( ktlFlags & KTL_SUPER ) { - value->timeCharVal.status = ( pvStat ) ktlValue->super.stat; - value->timeCharVal.severity = ( pvSevr ) ktlValue->super.sevr; - if ( ktlFlags & KTL_STAMP ) { - epicsTimeFromTimeval( &value->timeCharVal.stamp, - &ktlValue->super.stamp ); - } - else { - ( void ) epicsTimeGetCurrent( &stamp ); - value->timeCharVal.stamp = stamp; - } - } else { - ( void ) epicsTimeGetCurrent( &stamp ); - value->timeCharVal.status = pvStatOK; - value->timeCharVal.severity = pvSevrNONE; - value->timeCharVal.stamp = stamp; - } - } - - // convert data - const KTL_POLYMORPH *ktlData = KTL_POLYDATA( ktlFlags, ktlValue ); - return ktlCnv::convert( inpType, ktlCount, KTL_VALPTR( ktlType, ktlData ), - outType, count, PV_VALPTR( type, value ) ); -} - -/*+ - * Routine: copyToKTL - * - * Purpose: copy pvValue to KTL value - * - * Description: - */ -static int copyToKTL( pvType type, int count, const pvValue *value, - KTL_DATATYPE ktlType, int ktlCount, KTL_POLYMORPH *ktlValue ) -{ - // map types to ktlCnv's types (indices into conversion table) - ktlCnv::type inpType = ktlCnv::getType( type ); - ktlCnv::type outType = ktlCnv::getType( ktlType ); - - // allocate memory for KTL array or string - if ( mallocKTL( ktlType, ktlCount, ktlValue ) < 0 ) - return -1; - - // convert data - return ktlCnv::convert( inpType, count, PV_VALPTR( type, value ), - outType, ktlCount, KTL_VALPTR( ktlType, ktlValue )); -} - -/*+ - * Routine: mallocKTL - * - * Purpose: allocate dynamic data referenced from a polymorph - * - * Description: - */ -static int mallocKTL( KTL_DATATYPE ktlType, int ktlCount, - KTL_POLYMORPH *ktlValue ) -{ - switch ( ktlType ) { - case KTL_STRING: - ktlValue->s = new char[sizeof(pvString)]; - if ( ktlValue->s == NULL ) goto error; - break; - case KTL_INT_ARRAY: - ktlValue->ia = new int[ktlCount]; - if ( ktlValue->ia == NULL ) goto error; - break; - case KTL_FLOAT_ARRAY: - ktlValue->fa = new float[ktlCount]; - if ( ktlValue->fa == NULL ) goto error; - break; - case KTL_DOUBLE_ARRAY: - ktlValue->da = new double[ktlCount]; - if ( ktlValue->da == NULL ) goto error; - break; - default: - break; - } - return 0; -error: - ktl_set_errtxt( "memory allocation failure" ); - return -1; -} - -/*+ - * Routine: freeKTL - * - * Purpose: free data referenced from a polymorph - * - * Description: - */ -static void freeKTL( KTL_DATATYPE ktlType, KTL_POLYMORPH *ktlValue ) -{ - // do nothing if pointer (this is also ia, fa and da) is NULL - if ( ktlValue->s == NULL ) - return; - - switch ( ktlType ) { - case KTL_STRING: - delete [] ktlValue->s; - break; - case KTL_INT_ARRAY: - delete [] ktlValue->ia; - break; - case KTL_FLOAT_ARRAY: - delete [] ktlValue->fa; - break; - case KTL_DOUBLE_ARRAY: - delete [] ktlValue->da; - break; - default: - break; - } -} - -/* - * pvKtl.cc,v - * Revision 1.2 2001/02/16 18:45:39 mrk - * changes for latest version of 3.14 - * - * Revision 1.1.1.1 2000/04/04 03:22:14 wlupton - * first commit of seq-2-0-0 - * - * Revision 1.19 2000/03/31 23:01:41 wlupton - * supported setStatus - * - * Revision 1.18 2000/03/29 23:28:05 wlupton - * corrected comment typo - * - * Revision 1.17 2000/03/29 02:00:45 wlupton - * monitor all keywords (forces connect request to be sent) - * - * Revision 1.16 2000/03/18 04:00:25 wlupton - * converted to use new configure scheme - * - * Revision 1.15 2000/03/16 02:11:29 wlupton - * supported KTL_ANYPOLY (plus misc other mods) - * - * Revision 1.14 2000/03/08 01:32:29 wlupton - * cut out some early error exits in constructors (to avoid crashes in destructors) - * - * Revision 1.13 2000/03/07 19:55:32 wlupton - * nearly sufficient tidying up - * - * Revision 1.12 2000/03/07 09:27:39 wlupton - * drastically reduced use of references - * - * Revision 1.11 2000/03/07 08:46:29 wlupton - * created ktlKeyword class (works but a bit messy) - * - * Revision 1.10 2000/03/06 19:21:04 wlupton - * misc error reporting and type conversion mods - * - * Revision 1.9 2000/03/01 02:07:14 wlupton - * converted to use new OSI library - * - * Revision 1.8 2000/02/19 01:12:22 wlupton - * misc tidy-up and bug fixes - * - * Revision 1.7 2000/02/14 21:33:07 wlupton - * fixed workshop 5.0 compilation error - * - * Revision 1.6 1999/10/12 02:53:13 wlupton - * fixed KTL_NOTIFY support (cannot have been tested) - * - * Revision 1.5 1999/09/07 20:43:21 epics - * increased debug level for pend() call - * - * Revision 1.4 1999/07/01 20:50:20 wlupton - * Working under VxWorks - * - * Revision 1.3 1999/06/29 01:56:25 wlupton - * always use 0.1s select() timeout because of startup problem seeing fds open - * - * Revision 1.2 1999/06/15 10:11:03 wlupton - * demo sequence mostly working with KTL - * - * Revision 1.1 1999/06/11 02:20:32 wlupton - * nearly working with KTL - * - */ diff --git a/src/pv/pvKtl.h b/src/pv/pvKtl.h deleted file mode 100644 index 0a589b52..00000000 --- a/src/pv/pvKtl.h +++ /dev/null @@ -1,273 +0,0 @@ -/*************************************************************************\ -This file is distributed subject to a Software License Agreement found -in the file LICENSE that is included with this distribution. -\*************************************************************************/ -/* Definitions for EPICS sequencer KTL library (pvKtl) - * - * William Lupton, W. M. Keck Observatory - */ - -#ifndef INCLpvKtlh -#define INCLpvKtlh - -#include <sys/types.h> - -#include "pv.h" - -#include "ellLib.h" - -#include "ktl.h" -#include "ktl_keyword.h" - -/* - * Pointer to value - */ -#define KTL_SIMPLE(_type) \ - ( (_type) != KTL_STRING && (_type) != KTL_INT_ARRAY && \ - (_type) != KTL_FLOAT_ARRAY && (_type) != KTL_DOUBLE_ARRAY ) -#define KTL_VALPTR(_type,_poly) \ - ( ( KTL_SIMPLE(_type) ? ( void * ) (_poly) : ( void * ) (_poly)->s ) ) - -/* - * Forward references - */ -class ktlKeyword; -class ktlVariable; - -/* - * Linked list node (is cast to and from an ELLNODE) - */ -// ### is this portable/standard? definitely better to use an STL class -class ktlNode { - -public: - inline void setData( const void * data ) { data_ = data; } - inline const void *getData() const { return data_; } - -private: - ELLNODE node_; - const void *data_; -}; - -/* - * System - */ -class ktlSystem : public pvSystem { - -public: - ktlSystem( int debug = 0 ); - ~ktlSystem(); - - virtual pvStat attach(); - virtual pvStat flush(); - virtual pvStat pend( double seconds = 0.0, int wait = FALSE ); - - virtual pvVariable *newVariable( const char *name, pvConnFunc func = NULL, - void *priv = NULL, int debug = 0 ); - - int getAttach() const { return attach_; } - -private: - int attach_; /* whether to attach on open */ -}; - -/* - * Service - */ -class ktlService { - -public: - ktlService( ktlSystem *system, const char *name, int debug = 0 ); - ~ktlService(); - - static ktlService *getService( ktlSystem *system, char *name, - int debug = 0 ); - - inline void setDebug( int debug ) { debug_ = debug; } - inline int getDebug() const { return debug_; } - - inline char *getName() const { return name_; } - inline KTL_HANDLE *getHandle() const { return handle_; } - inline int getFlags() const { return flags_; } - - void add( const ktlKeyword *keyword ); - void remove( const ktlKeyword *keyword ); - ktlKeyword *find( const char *keyName ); - - static ktlService *first(); - ktlService *next() const; - - static fd_set *getFdsetsAll(); - static pvStat dispatchAll(); - - // provide same error-handling interface as system and variable - void setError( int status, pvSevr sevr, pvStat stat, const char *mess ); - inline int getStatus() const { return status_; } - inline pvSevr getSevr() const { return sevr_; } - inline pvStat getStat() const { return stat_; } - inline void setStatus( int status ) { status_ = status; } - inline void setStat( pvStat stat ) { stat_ = stat; } - inline char *getMess() const { return mess_?mess_:(char *)""; } - -private: - int debug_; /* debugging level (inherited from varaible) */ - - static ELLLIST list_; /* list of ktlService objects */ - ktlNode node_; /* linked list node */ - char *name_; /* service name */ - KTL_HANDLE *handle_; /* KTL handle */ - int flags_; /* KTL_SUPER | KTL_STAMP ...or 0 */ - void *keys_; /* hash table of ktlKeyword objects */ - - int status_; /* message system-specific status code */ - pvSevr sevr_; /* severity */ - pvStat stat_; /* status */ - char *mess_; /* error message */ -}; - -/* - * Keyword (distributes connection and monitor events to process variables) - */ -// ### some duplicate info between keyword and variable; should move cached -// k/w info to keyword (and maybe do all KTL calls from keyword) -class ktlKeyword { - -public: - ktlKeyword( ktlService *service, const char *keyName, int debug = 0 ); - ~ktlKeyword(); - - static ktlKeyword *getKeyword( ktlService *service, const char *keyName, - int debug = 0 ); - - inline void setDebug( int debug ) { debug_ = debug; } - inline int getDebug() { return debug_; } - - inline const ktlService *getService() const { return service_; } - inline int getFlags() const { return getService()->getFlags(); } - inline const char *getKeyName() const { return keyName_; } - inline int getMonitored() { return monitored_; } - - int add( ktlVariable *variable ); - void remove( ktlVariable *variable ); - int monitorOn( ktlVariable *variable ); - int monitorOff( ktlVariable *variable ); - ktlVariable *first(); - ktlVariable *next( ktlVariable *variable ); - - // provide same error-handling interface as system and variable - void setError( int status, pvSevr sevr, pvStat stat, const char *mess ); - inline int getStatus() const { return status_; } - inline pvSevr getSevr() const { return sevr_; } - inline pvStat getStat() const { return stat_; } - inline void setStatus( int status ) { status_ = status; } - inline void setStat( pvStat stat ) { stat_ = stat; } - inline char *getMess() const { return mess_?mess_:(char *)""; } - -private: - int debug_; /* debugging level (inherited from variable) */ - - ktlService *service_; /* associated KTL service */ - const char *keyName_; /* keyword name (not including service name) */ - ELLLIST list_; /* list of associated variables */ - int monitored_; /* whether currently monitored */ - - int status_; /* message system-specific status code */ - pvSevr sevr_; /* severity */ - pvStat stat_; /* status */ - char *mess_; /* error message */ -}; - -/* - * Process variable (several process variables may map to the same keyword) - */ -class ktlVariable : public pvVariable { - -public: - ktlVariable( ktlSystem *system, const char *name, pvConnFunc func = NULL, - void *priv = NULL, int debug = 0 ); - ~ktlVariable(); - - virtual pvStat get( pvType type, int count, pvValue *value ); - virtual pvStat getNoBlock( pvType type, int count, pvValue *value ); - virtual pvStat getCallback( pvType type, int count, - pvEventFunc func, void *arg = NULL ); - virtual pvStat put( pvType type, int count, pvValue *value ); - virtual pvStat putNoBlock( pvType type, int count, pvValue *value ); - virtual pvStat putCallback( pvType type, int count, pvValue *value, - pvEventFunc func, void *arg = NULL ); - virtual pvStat monitorOn( pvType type, int count, - pvEventFunc func, void *arg = NULL, - pvCallback **pCallback = NULL ); - virtual pvStat monitorOff( pvCallback *callback = NULL ); - - inline void setConnected( int connected ) { connected_ = connected; } - inline virtual int getConnected() const { return connected_; } - virtual pvType getType() const; - inline KTL_DATATYPE getKtlType() const { return type_; } - inline virtual int getCount() const { return count_; } - - inline ktlNode *getNode() { return &node_; } - inline const ktlService *getService() const { return service_; } - inline KTL_HANDLE *getHandle() const { return getService()->getHandle(); } - inline int getFlags() const { return getService()->getFlags(); } - inline const char *getKeyName() const { return keyName_; } - inline pvCallback *getMonitor() { return monitor_; } - -private: - ktlNode node_; /* linked list node */ - ktlService *service_; /* associated KTL service */ - const char *keyName_; /* keyword name (not including service name) */ - ktlKeyword *keyword_; /* associated KTL keyword */ - KTL_DATATYPE type_; /* native KTL type */ - int count_; /* native KTL number of elements (fixed) */ - int readNot_; /* can read with notify */ - int writeNot_; /* can write with notify */ - int readCont_; /* can read continuously (monitor) */ - int connected_; /* whether keyword is connected */ - pvCallback *monitor_; /* monitor callback object */ -}; - -#endif /* INCLpvKtlh */ - -/* - * pvKtl.h,v - * Revision 1.2 2000/04/14 21:53:29 jba - * Changes for win32 build. - * - * Revision 1.1.1.1 2000/04/04 03:22:15 wlupton - * first commit of seq-2-0-0 - * - * Revision 1.11 2000/03/31 23:01:29 wlupton - * supported setStatus - * - * Revision 1.10 2000/03/18 04:00:25 wlupton - * converted to use new configure scheme - * - * Revision 1.9 2000/03/16 02:11:29 wlupton - * supported KTL_ANYPOLY (plus misc other mods) - * - * Revision 1.8 2000/03/07 19:55:32 wlupton - * nearly sufficient tidying up - * - * Revision 1.7 2000/03/07 09:27:39 wlupton - * drastically reduced use of references - * - * Revision 1.6 2000/03/07 08:46:30 wlupton - * created ktlKeyword class (works but a bit messy) - * - * Revision 1.5 2000/03/06 19:21:04 wlupton - * misc error reporting and type conversion mods - * - * Revision 1.4 2000/03/01 02:07:15 wlupton - * converted to use new OSI library - * - * Revision 1.3 1999/07/01 20:50:20 wlupton - * Working under VxWorks - * - * Revision 1.2 1999/06/15 10:11:04 wlupton - * demo sequence mostly working with KTL - * - * Revision 1.1 1999/06/11 02:20:33 wlupton - * nearly working with KTL - * - */ diff --git a/src/pv/pvKtlCnv.cc b/src/pv/pvKtlCnv.cc deleted file mode 100644 index 8f9bbd1e..00000000 --- a/src/pv/pvKtlCnv.cc +++ /dev/null @@ -1,295 +0,0 @@ -/* Implementation of EPICS sequencer KTL type conversion (pvKtlCnv) - * - * Uses large amounts of code from the cdevData class - * - * William Lupton, W. M. Keck Observatory - */ - -#include <assert.h> - -#include "pvKtlCnv.h" - -/* - * typedef for all conversion functions (pointers to the functions are - * in the conversion matrix - see below; the functions should be - * only via the "get" methods) - */ -typedef int ( *converter ) ( int inpCount, const void *inpValue, - int outCount, void *outValue ); - -/* - * conversion matrix (elements are filled in at the bottom of the file, after - * all the conversion functions have been defined) - */ -extern converter ktlCnvMatrix[ktlCnv::NUMBER][ktlCnv::NUMBER]; - -/* - * map pvType and KTL_DATATYPE types to "type" enumeration for use in indexing - * the conversion matrix - */ -ktlCnv::type ktlCnv::getType( pvType t ) -{ - switch ( t ) { - case pvTypeCHAR: return CHAR; - case pvTypeSHORT: return SHORT; - case pvTypeLONG: return LONG; - case pvTypeFLOAT: return FLOAT; - case pvTypeDOUBLE: return DOUBLE; - case pvTypeSTRING: return STRING; - case pvTypeTIME_CHAR: return CHAR; - case pvTypeTIME_SHORT: return SHORT; - case pvTypeTIME_LONG: return LONG; - case pvTypeTIME_FLOAT: return FLOAT; - case pvTypeTIME_DOUBLE: return DOUBLE; - case pvTypeTIME_STRING: return STRING; - default: return INVALID; - } -} - -ktlCnv::type ktlCnv::getType( KTL_DATATYPE t ) -{ - // KTL doesn't support a "long" type; handle ints and longs the same, but - // check that they are indeed the same size - assert( sizeof( int ) == sizeof( long ) ); - - switch ( t ) { - case KTL_INT: return LONG; - case KTL_BOOLEAN: return LONG; - case KTL_ENUM: return LONG; - case KTL_ENUMM: return LONG; - case KTL_MASK: return LONG; - case KTL_FLOAT: return FLOAT; - case KTL_DOUBLE: return DOUBLE; - case KTL_STRING: return STRING; - case KTL_INT_ARRAY: return LONG; - case KTL_FLOAT_ARRAY: return FLOAT; - case KTL_DOUBLE_ARRAY: return DOUBLE; - default: return INVALID; - } -} - -/* - * convert method - */ -int ktlCnv::convert( ktlCnv::type inpType, int inpCount, const void *inpValue, - ktlCnv::type outType, int outCount, void *outValue ) -{ - return ktlCnvMatrix[(int)inpType][(int)outType] - ( inpCount, inpValue, outCount, outValue ); -} - -// ********************************************************************* - -// the remainder of this file implements the various conversion functions; -// functions can assume that the to/from variables _do_ contain values of -// the expected types - -// typedefs so "type" names can be used in declarations -typedef char ktlCnvCHAR; -typedef short ktlCnvSHORT; -typedef long ktlCnvLONG; -typedef float ktlCnvFLOAT; -typedef double ktlCnvDOUBLE; -typedef char ktlCnvSTRING; /* stet */ - -// macro for generating a conversion involving an invalid type - -#define invfunc(INP,OUT) \ -static int convert_##INP##_to_##OUT( int, const void *, \ - int, void *) \ -{ \ - return -1; \ -} - -// macro for generating a numeric -> numeric conversion function - -#define numfunc(INP,OUT) \ -static int convert_##INP##_to_##OUT( int inpCount, const void *inpValue, \ - int outCount, void *outValue ) \ -{ \ - ktlCnv##INP *inp = ( ktlCnv##INP * ) inpValue; \ - ktlCnv##OUT *out = ( ktlCnv##OUT * ) outValue; \ - int cpyCount = ( inpCount < outCount ) ? inpCount : outCount; \ - int i; \ - for ( i = 0; i < cpyCount; i++ ) \ - out[i] = ( ktlCnv##OUT ) inp[i]; \ - for ( ; i < outCount; i++ ) \ - out[i] = ( ktlCnv##OUT ) 0; \ - return 0; \ -} - -// macro for generating a numeric -> string conversion function -// (only works if inpCount and outCount are both 1 (checked via assert()) -// (can assume string is of size sizeof( pvString )) - -#define strfunc(INP,OUT,set) \ -static int convert_##INP##_to_##OUT( int inpCount, const void *inpValue, \ - int outCount, void *outValue ) \ -{ \ - ktlCnv##INP *inp = ( ktlCnv##INP * ) inpValue; \ - char *out = ( char * ) outValue; \ - assert( inpCount == 1 && outCount == 1 ); \ - return ( set ); \ -} - -// macro for generating a string -> numeric conversion function -// (only works if inpCount and outCount are both 1 (checked via assert()) - -#define funcstr(INP,OUT,set) \ -static int convert_##INP##_to_##OUT( int inpCount, const void *inpValue, \ - int outCount, void *outValue ) \ -{ \ - char *inp = ( char * ) inpValue; \ - ktlCnv##OUT *out = ( ktlCnv##OUT * ) outValue; \ - assert( inpCount == 1 && outCount == 1 ); \ - return ( set ); \ -} - -// INVALID conversions - -invfunc( INVALID, INVALID ) -invfunc( INVALID, CHAR ) -invfunc( INVALID, SHORT ) -invfunc( INVALID, LONG ) -invfunc( INVALID, FLOAT ) -invfunc( INVALID, DOUBLE ) -invfunc( INVALID, STRING ) - -// CHAR conversions - -invfunc( CHAR, INVALID ) -numfunc( CHAR, CHAR ) -numfunc( CHAR, SHORT ) -numfunc( CHAR, LONG ) -numfunc( CHAR, FLOAT ) -numfunc( CHAR, DOUBLE ) -strfunc( CHAR, STRING , sprintf( out, "%c", *inp ) > 0 ? 0 : -1 ) - -// SHORT conversions - -invfunc( SHORT, INVALID ) -numfunc( SHORT, CHAR ) -numfunc( SHORT, SHORT ) -numfunc( SHORT, LONG ) -numfunc( SHORT, FLOAT ) -numfunc( SHORT, DOUBLE ) -strfunc( SHORT, STRING , sprintf( out, "%hd", *inp ) > 0 ? 0 : -1 ) - -// LONG conversions - -invfunc( LONG, INVALID ) -numfunc( LONG, CHAR ) -numfunc( LONG, SHORT ) -numfunc( LONG, LONG ) -numfunc( LONG, FLOAT ) -numfunc( LONG, DOUBLE ) -strfunc( LONG, STRING , sprintf( out, "%ld", *inp ) > 0 ? 0 : -1 ) - -// FLOAT conversions - -invfunc( FLOAT, INVALID ) -numfunc( FLOAT, CHAR ) -numfunc( FLOAT, SHORT ) -numfunc( FLOAT, LONG ) -numfunc( FLOAT, FLOAT ) -numfunc( FLOAT, DOUBLE ) -strfunc( FLOAT, STRING , sprintf( out, "%g", *inp ) > 0 ? 0 : -1 ) - -// DOUBLE conversions - -invfunc( DOUBLE, INVALID ) -numfunc( DOUBLE, CHAR ) -numfunc( DOUBLE, SHORT ) -numfunc( DOUBLE, LONG ) -numfunc( DOUBLE, FLOAT ) -numfunc( DOUBLE, DOUBLE ) -strfunc( DOUBLE, STRING , sprintf( out, "%g", *inp ) > 0 ? 0 : -1 ) - -// STRING conversions - -invfunc( STRING, INVALID ) -funcstr( STRING, CHAR , sscanf( inp, "%c", out ) == 1 ? 0 : -1 ) -funcstr( STRING, SHORT , sscanf( inp, "%hd", out ) == 1 ? 0 : -1 ) -funcstr( STRING, LONG , sscanf( inp, "%ld", out ) == 1 ? 0 : -1 ) -funcstr( STRING, FLOAT , sscanf( inp, "%f", out ) == 1 ? 0 : -1 ) -funcstr( STRING, DOUBLE , sscanf( inp, "%lf", out ) == 1 ? 0 : -1 ) -funcstr( STRING, STRING , ( strcpy( out, inp ), 0 ) ) - -// contents of conversion matrix defined earlier -converter ktlCnvMatrix[ktlCnv::NUMBER][ktlCnv::NUMBER] = -{ - { - convert_INVALID_to_INVALID, - convert_INVALID_to_CHAR, - convert_INVALID_to_SHORT, - convert_INVALID_to_LONG, - convert_INVALID_to_FLOAT, - convert_INVALID_to_DOUBLE, - convert_INVALID_to_STRING, - }, - { - convert_CHAR_to_INVALID, - convert_CHAR_to_CHAR, - convert_CHAR_to_SHORT, - convert_CHAR_to_LONG, - convert_CHAR_to_FLOAT, - convert_CHAR_to_DOUBLE, - convert_CHAR_to_STRING, - }, - { - convert_SHORT_to_INVALID, - convert_SHORT_to_CHAR, - convert_SHORT_to_SHORT, - convert_SHORT_to_LONG, - convert_SHORT_to_FLOAT, - convert_SHORT_to_DOUBLE, - convert_SHORT_to_STRING, - }, - { - convert_LONG_to_INVALID, - convert_LONG_to_CHAR, - convert_LONG_to_SHORT, - convert_LONG_to_LONG, - convert_LONG_to_FLOAT, - convert_LONG_to_DOUBLE, - convert_LONG_to_STRING, - }, - { - convert_FLOAT_to_INVALID, - convert_FLOAT_to_CHAR, - convert_FLOAT_to_SHORT, - convert_FLOAT_to_LONG, - convert_FLOAT_to_FLOAT, - convert_FLOAT_to_DOUBLE, - convert_FLOAT_to_STRING, - }, - { - convert_DOUBLE_to_INVALID, - convert_DOUBLE_to_CHAR, - convert_DOUBLE_to_SHORT, - convert_DOUBLE_to_LONG, - convert_DOUBLE_to_FLOAT, - convert_DOUBLE_to_DOUBLE, - convert_DOUBLE_to_STRING, - }, - { - convert_STRING_to_INVALID, - convert_STRING_to_CHAR, - convert_STRING_to_SHORT, - convert_STRING_to_LONG, - convert_STRING_to_FLOAT, - convert_STRING_to_DOUBLE, - convert_STRING_to_STRING, - } -}; - -/* - * pvKtlCnv.cc,v - * Revision 1.1.1.1 2000/04/04 03:22:15 wlupton - * first commit of seq-2-0-0 - * - * Revision 1.1 2000/03/06 19:21:04 wlupton - * misc error reporting and type conversion mods - * - */ - diff --git a/src/pv/pvKtlCnv.h b/src/pv/pvKtlCnv.h deleted file mode 100644 index 3b71484d..00000000 --- a/src/pv/pvKtlCnv.h +++ /dev/null @@ -1,55 +0,0 @@ -/*************************************************************************\ -This file is distributed subject to a Software License Agreement found -in the file LICENSE that is included with this distribution. -\*************************************************************************/ -/* Definitions for EPICS sequencer KTL type conversion (pvKtlCnv) - * - * Uses large amounts of code from the cdevData class - * - * William Lupton, W. M. Keck Observatory - */ - -#ifndef INCLpvKtlCnvh -#define INCLpvKtlCnvh - -#include <sys/types.h> - -#include "pv.h" - -#include "ktl.h" -#include "ktl_keyword.h" - -// ktlCnv class (static members/methods only) -class ktlCnv -{ -public: - - // type (index into conversion table */ - enum type { INVALID, CHAR, SHORT, LONG, FLOAT, DOUBLE, STRING, NUMBER }; - - // map types to ktlCnv types (indices into conversion table) - static type getType( pvType t ); - static type getType( KTL_DATATYPE t ); - - // conversion method - static int convert( type inpType, int inpCount, const void *inpValue, - type outType, int outCount, void *outValue ); - -private: - - // constructors - ktlCnv() {} -}; - -/* - * pvKtlCnv.h,v - * Revision 1.1.1.1 2000/04/04 03:22:15 wlupton - * first commit of seq-2-0-0 - * - * Revision 1.1 2000/03/06 19:21:04 wlupton - * misc error reporting and type conversion mods - * - */ - -#endif /* INCLpvKtlCnvh */ - diff --git a/src/pv/pvNew.cc b/src/pv/pvNew.cc deleted file mode 100644 index d020b49d..00000000 --- a/src/pv/pvNew.cc +++ /dev/null @@ -1,49 +0,0 @@ -/* Routine to create a system object for a named message system - * (will eventually load dynamically) - */ - -#include <stdio.h> -#include <string.h> - -#define epicsExportSharedSymbols -#include "pv.h" - -#if defined( PVCA ) -#include "pvCa.h" -#endif - -#if defined( PVFILE ) -#include "pvFile.h" -#endif - -#if defined( PVKTL ) && !defined( vxWorks ) -#include "pvKtl.h" -#endif - -/*+ - * Routine: newPvSystem - * - * Purpose: return pointer to appropriate pvSystem sub-class - * - * Description: - */ -epicsShareFunc pvSystem * epicsShareAPI newPvSystem( const char *name, int debug ) { - -#if defined( PVCA ) - if ( strcmp( name, "ca" ) == 0 ) - return new caSystem( debug ); -#endif - -#if defined( PVFILE ) - if ( strcmp( name, "file" ) == 0 ) - return new fileSystem( debug ); -#endif - -#if defined( PVKTL ) && !defined( vxWorks ) - if ( strcmp( name, "ktl" ) == 0 ) - return new ktlSystem( debug ); -#endif - - return NULL; -} - diff --git a/src/pv/pvType.h b/src/pv/pvType.h index 8fc0d570..8524db77 100644 --- a/src/pv/pvType.h +++ b/src/pv/pvType.h @@ -12,6 +12,7 @@ in the file LICENSE that is included with this distribution. #define INCLpvTypeh #include "epicsTime.h" /* for time stamps */ +#include "epicsTypes.h" #include "pvAlarm.h" /* status and severity definitions */ @@ -34,55 +35,15 @@ typedef enum { pvTypeTIME_STRING = 11 } pvType; -#define PV_SIMPLE(type) ((type)<=pvTypeSTRING) +/* these must correspond to corresponding types in db_access.h */ +typedef epicsUInt8 pvChar; /* dbr_char_t */ +typedef epicsInt16 pvShort; /* dbr_short_t */ +typedef epicsInt32 pvLong; /* dbr_long_t */ +typedef epicsFloat32 pvFloat; /* dbr_float_t */ +typedef epicsFloat64 pvDouble; /* dbr_double_t */ +typedef epicsOldString pvString; /* dbr_string_t */ -#define pv_type_is_valid(type) ((type)>=0&&(type)<=pvTypeTIME_STRING) -#define pv_type_is_plain(type) ((type)>=0&&(type)<=pvTypeSTRING) - -/* - * Value-related types (c.f. db_access.h) - */ -typedef epicsInt8 pvChar; -typedef epicsInt16 pvShort; -typedef epicsInt32 pvLong; -typedef epicsFloat32 pvFloat; -typedef epicsFloat64 pvDouble; -typedef char pvString[40]; /* use sizeof( pvString ) */ - -#define PV_TIME_XXX(type) \ - typedef struct { \ - pvStat status; \ - pvSevr severity; \ - epicsTimeStamp stamp; \ - pv##type value[1]; \ - } pvTime##type - -PV_TIME_XXX( Char ); -PV_TIME_XXX( Short ); -PV_TIME_XXX( Long ); -PV_TIME_XXX( Float ); -PV_TIME_XXX( Double ); -PV_TIME_XXX( String ); - -typedef union { - pvChar charVal[1]; - pvShort shortVal[1]; - pvLong longVal[1]; - pvFloat floatVal[1]; - pvDouble doubleVal[1]; - pvString stringVal[1]; - pvTimeChar timeCharVal; - pvTimeShort timeShortVal; - pvTimeLong timeLongVal; - pvTimeFloat timeFloatVal; - pvTimeDouble timeDoubleVal; - pvTimeString timeStringVal; -} pvValue; - -/* deprecated, use pv_value_ptr */ -#define PV_VALPTR(type,value)\ - ((PV_SIMPLE(type)?(void*)(value):\ - (void*)(&value->timeCharVal.value))) +typedef void pvValue; /* abstract */ #define pv_is_simple_type(type)\ ((type)>=pvTypeCHAR&&(type)<=pvTypeSTRING) @@ -91,15 +52,15 @@ typedef union { #define pv_is_valid_type(type)\ ((type)>=pvTypeCHAR&&(type)<=pvTypeTIME_STRING) -#define pv_status_ptr(pv,type)\ +#define pv_status(pv,type)\ (assert(pv_is_time_type(type)),\ - (pvStat *)(((char *)pv)+pv_status_offsets[(type)-pvTypeTIME_CHAR])) -#define pv_severity_ptr(pv,type)\ + (pvStat)*(epicsInt16 *)(((char *)pv)+pv_status_offsets[(type)-pvTypeTIME_CHAR])) +#define pv_severity(pv,type)\ (assert(pv_is_time_type(type)),\ - (pvSevr *)(((char *)pv)+pv_severity_offsets[(type)-pvTypeTIME_CHAR])) -#define pv_stamp_ptr(pv,type)\ + (pvSevr)*(epicsInt16 *)(((char *)pv)+pv_severity_offsets[(type)-pvTypeTIME_CHAR])) +#define pv_stamp(pv,type)\ (assert(pv_is_time_type(type)),\ - (epicsTimeStamp *)(((char *)pv)+pv_stamp_offsets[(type)-pvTypeTIME_CHAR])) + *(epicsTimeStamp *)(((char *)pv)+pv_stamp_offsets[(type)-pvTypeTIME_CHAR])) #define pv_value_ptr(pv,type)\ (assert(pv_is_valid_type(type)),(void *)(((char *)pv)+pv_value_offsets[type])) diff --git a/src/seq/seqCom.h b/src/seq/seqCom.h index bcb627fe..49e84965 100644 --- a/src/seq/seqCom.h +++ b/src/seq/seqCom.h @@ -29,7 +29,6 @@ in the file LICENSE that is included with this distribution. #include "shareLib.h" #include "pvAlarm.h" -#include "pvType.h" #include "epicsThread.h" #include "epicsTime.h" diff --git a/src/seq/seqPvt.h b/src/seq/seqPvt.h index 6f2cead9..b52b9ffa 100644 --- a/src/seq/seqPvt.h +++ b/src/seq/seqPvt.h @@ -124,10 +124,9 @@ struct pv_meta_data struct db_channel { char *dbName; /* channel name after macro expansion */ - void *pvid; /* PV (process variable) id */ + pvVar pvid; /* PV (process variable) id */ unsigned dbCount; /* actual count for db access */ boolean connected; /* whether channel is connected */ - void *monid; /* monitor id (supplied by PV lib) */ boolean gotOneMonitor; /* whether got at least one monitor */ PVMETA metaData; /* meta data (shared buffer) */ PVMETA *ssMetaData; /* array of meta data, @@ -172,9 +171,7 @@ struct program_instance int instance; /* program instance number */ unsigned threadPriority; /* thread priority (all threads) */ unsigned stackSize; /* stack size (all threads) */ - void *pvSys; /* pv system handle */ - char *pvSysName; /* pv system name ("ca", "ktl", ...) */ - int debug; /* pv system debug level */ + pvSystem pvSys; /* pv system handle */ CHAN *chan; /* table of channels */ unsigned numChans; /* number of channels */ QUEUE *queues; /* array of syncQ queues */ @@ -224,28 +221,25 @@ struct pvreq /* Internal procedures */ /* seq_task.c */ -void sequencer (void *arg); +void sequencer(void *arg); void ss_write_buffer(CHAN *ch, void *val, PVMETA *meta, boolean dirtify); void ss_read_buffer(SSCB *ss, CHAN *ch, boolean dirty_only); void ss_read_buffer_selective(SPROG *sp, SSCB *ss, EV_ID ev_flag); void ss_wakeup(SPROG *sp, unsigned eventNum); -void seqCreatePvSys(SPROG *sp); + /* seq_mac.c */ void seqMacParse(SPROG *sp, const char *macStr); char *seqMacValGet(SPROG *sp, const char *name); void seqMacEval(SPROG *sp, const char *inStr, char *outStr, size_t maxChar); void seqMacFree(SPROG *sp); + /* seq_ca.c */ -void seq_get_handler(void *var, pvType type, unsigned count, - pvValue *value, void *arg, pvStat status); -void seq_put_handler(void *var, pvType type, unsigned count, - pvValue *value, void *arg, pvStat status); -void seq_mon_handler(void *var, pvType type, unsigned count, - pvValue *value, void *arg, pvStat status); -void seq_conn_handler(void *var,int connected); +pvConnFunc seq_conn_handler; +pvEventFunc seq_event_handler; pvStat seq_connect(SPROG *sp, boolean wait); void seq_disconnect(SPROG *sp); pvStat seq_camonitor(CHAN *ch, boolean on); + /* seq_prog.c */ typedef int seqTraversee(SPROG *prog, void *param); void seqTraverseProg(seqTraversee *func, void *param); @@ -253,11 +247,14 @@ SSCB *seqFindStateSet(epicsThreadId threadId); SPROG *seqFindProg(epicsThreadId threadId); void seqDelProg(SPROG *sp); void seqAddProg(SPROG *sp); + /* seqCommands.c */ typedef int sequencerProgramTraversee(SPROG **sprog, seqProgram *pseq, void *param); int traverseSequencerPrograms(sequencerProgramTraversee *traversee, void *param); + /* seq_main.c */ void seq_free(SPROG *sp); + /* debug/query support */ typedef int pr_fun(const char *format,...); void print_channel_value(pr_fun *, CHAN *ch, void *val); diff --git a/src/seq/seq_ca.c b/src/seq/seq_ca.c index 676d0d9d..a593b685 100644 --- a/src/seq/seq_ca.c +++ b/src/seq/seq_ca.c @@ -33,23 +33,8 @@ in the file LICENSE that is included with this distribution. #include "seq.h" #include "seq_debug.h" -/* - * Event type (extra argument passed to proc_db_events(). - */ -enum event_type { - GET_COMPLETE, - PUT_COMPLETE, - MON_COMPLETE -}; - -static const char *event_type_name[] = { - "get", - "put", - "mon" -}; - static void proc_db_events(pvValue *value, pvType type, - CHAN *ch, SSCB *ss, enum event_type evtype, pvStat status); + CHAN *ch, SSCB *ss, pvEventType evtype, pvStat status); static void proc_db_events_queued(SPROG *sp, CHAN *ch, pvValue *value); /* @@ -76,13 +61,12 @@ pvStat seq_connect(SPROG *sp, boolean wait) DEBUG("seq_connect: connect %s to %s\n", ch->varName, dbch->dbName); /* Connect to it */ - dbch->pvid = NULL; status = pvVarCreate( sp->pvSys, /* PV system context */ ch->dbch->dbName, /* PV name */ seq_conn_handler, /* connection handler routine */ + seq_event_handler, /* event handler routine */ ch, /* private data is CHAN struc */ - sp->debug, /* debug level (inherited) */ &dbch->pvid); /* ptr to PV id */ if (status != pvStatOK) { @@ -154,8 +138,8 @@ pvStat seq_connect(SPROG *sp, boolean wait) * seq_get_handler() - Sequencer callback handler. * Called when a "get" completes. */ -void seq_get_handler( - void *var, pvType type, unsigned count, pvValue *value, void *arg, pvStat status) +static void seq_get_handler( + pvType type, unsigned count, pvValue *value, void *arg, pvStat status) { PVREQ *rq = (PVREQ *)arg; CHAN *ch = rq->ch; @@ -166,15 +150,15 @@ void seq_get_handler( freeListFree(sp->pvReqPool, arg); /* ignore callback if not expected, e.g. already timed out */ if (ss->getReq[chNum(ch)] == rq) - proc_db_events(value, type, ch, ss, GET_COMPLETE, status); + proc_db_events(value, type, ch, ss, pvEventGet, status); } /* * seq_put_handler() - Sequencer callback handler. * Called when a "put" completes. */ -void seq_put_handler( - void *var, pvType type, unsigned count, pvValue *value, void *arg, pvStat status) +static void seq_put_handler( + pvType type, unsigned count, pvValue *value, void *arg, pvStat status) { PVREQ *rq = (PVREQ *)arg; CHAN *ch = rq->ch; @@ -185,14 +169,14 @@ void seq_put_handler( freeListFree(sp->pvReqPool, arg); /* ignore callback if not expected, e.g. already timed out */ if (ss->putReq[chNum(ch)] == rq) - proc_db_events(value, type, ch, ss, PUT_COMPLETE, status); + proc_db_events(value, type, ch, ss, pvEventPut, status); } /* * seq_mon_handler() - PV events (monitors) come here. */ -void seq_mon_handler( - void *var, pvType type, unsigned count, pvValue *value, void *arg, pvStat status) +static void seq_mon_handler( + pvType type, unsigned count, pvValue *value, void *arg, pvStat status) { CHAN *ch = (CHAN *)arg; SPROG *sp = ch->sprog; @@ -200,7 +184,7 @@ void seq_mon_handler( assert(dbch != NULL); /* Process event handling in each state set */ - proc_db_events(value, type, ch, sp->ss, MON_COMPLETE, status); + proc_db_events(value, type, ch, sp->ss, pvEventMonitor, status); if (!dbch->gotOneMonitor) { dbch->gotOneMonitor = TRUE; @@ -215,17 +199,39 @@ void seq_mon_handler( } } +/* + * seq_get_handler() - Sequencer callback handler. + * Called when a "get" completes. + */ +void seq_event_handler( + pvEventType evt, void *arg, pvType type, unsigned count, pvValue *value, pvStat status) +{ + switch (evt) + { + case pvEventGet: + seq_get_handler(type, count, value, arg, status); + break; + case pvEventPut: + seq_put_handler(type, count, value, arg, status); + break; + case pvEventMonitor: + seq_mon_handler(type, count, value, arg, status); + break; + } +} + /* Common code for completion and monitor handling */ static void proc_db_events( - pvValue *value, - pvType type, - CHAN *ch, - SSCB *ss, /* originator, for put and get */ - enum event_type evtype, - pvStat status) + pvValue *value, + pvType type, + CHAN *ch, + SSCB *ss, /* originator, for put and get */ + pvEventType evtype, + pvStat status) { SPROG *sp = ch->sprog; DBCHAN *dbch = ch->dbch; + static const char *event_type_name[] = {"get","put","mon"}; assert(dbch != NULL); @@ -233,7 +239,7 @@ static void proc_db_events( dbch->dbName, event_type_name[evtype], status); /* If monitor on var queued via syncQ, branch to alternative routine */ - if (ch->queue && evtype == MON_COMPLETE) + if (ch->queue && evtype == pvEventMonitor) { proc_db_events_queued(sp, ch, value); return; @@ -247,9 +253,9 @@ static void proc_db_events( PVMETA meta; /* must not use an initializer here, the MS C compiler chokes on it */ - meta.timeStamp = *pv_stamp_ptr(value,type); - meta.status = *pv_status_ptr(value,type); - meta.severity = *pv_severity_ptr(value,type); + meta.timeStamp = pv_stamp(value,type); + meta.status = pv_status(value,type); + meta.severity = pv_severity(value,type); meta.message = NULL; /* Set error message only when severity indicates error */ @@ -262,16 +268,16 @@ static void proc_db_events( /* Write value and meta data to shared buffers. Set the dirty flag only if this was a monitor event. */ - ss_write_buffer(ch, val, &meta, evtype == MON_COMPLETE); + ss_write_buffer(ch, val, &meta, evtype == pvEventMonitor); } /* Signal completion */ switch (evtype) { - case GET_COMPLETE: + case pvEventGet: epicsEventSignal(ss->getSemId[chNum(ch)]); break; - case PUT_COMPLETE: + case pvEventPut: epicsEventSignal(ss->putSemId[chNum(ch)]); break; default: @@ -346,8 +352,7 @@ void seq_disconnect(SPROG *sp) DEBUG("seq_disconnect: disconnect %s from %s\n", ch->varName, dbch->dbName); /* Disconnect this PV */ - status = pvVarDestroy(dbch->pvid); - dbch->pvid = NULL; + status = pvVarDestroy(&dbch->pvid); if (status != pvStatOK) errlogSevPrintf(errlogFatal, "seq_disconnect: var %s, pv %s: pvVarDestroy() failure: " "%s\n", ch->varName, dbch->dbName, pvVarGetMess(dbch->pvid)); @@ -368,25 +373,21 @@ pvStat seq_camonitor(CHAN *ch, boolean on) assert(ch); assert(dbch); - if (on == (dbch->monid != NULL)) /* already done */ + if (on == pvMonIsDefined(dbch->pvid)) /* already done */ return pvStatOK; DEBUG("calling pvVarMonitor%s(%p)\n", on?"On":"Off", dbch->pvid); dbch->gotOneMonitor = FALSE; if (on) status = pvVarMonitorOn( - dbch->pvid, /* pvid */ + &dbch->pvid, /* pvid */ ch->type->getType, /* requested type */ ch->count, /* element count */ - seq_mon_handler, /* function to call */ - ch, /* user arg (channel struct) */ - &dbch->monid); /* where to put event id */ + ch); /* user arg (channel struct) */ else - status = pvVarMonitorOff(dbch->pvid, dbch->monid); + status = pvVarMonitorOff(&dbch->pvid); if (status != pvStatOK) errlogSevPrintf(errlogFatal, "seq_camonitor: pvVarMonitor%s(var %s, pv %s) failure: %s\n", on?"On":"Off", ch->varName, dbch->dbName, pvVarGetMess(dbch->pvid)); - else if (!on) - dbch->monid = NULL; return status; } @@ -394,9 +395,9 @@ pvStat seq_camonitor(CHAN *ch, boolean on) * seq_conn_handler() - Sequencer connection handler. * Called each time a connection is established or broken. */ -void seq_conn_handler(void *var, int connected) +void seq_conn_handler(int connected, void *arg) { - CHAN *ch = (CHAN *)pvVarGetPrivate(var); + CHAN *ch = (CHAN *)arg; SPROG *sp = ch->sprog; DBCHAN *dbch = ch->dbch; @@ -404,13 +405,6 @@ void seq_conn_handler(void *var, int connected) assert(dbch != NULL); - /* Note that CA may call this while pvVarCreate is still running, - so dbch->pvid may not yet be initialized. */ - if (!dbch->pvid) - dbch->pvid = var; - - DEBUG("seq_conn_handler(%p,%d), dbch->pvid=%p\n", var, connected, dbch->pvid); - assert(dbch->pvid == var); if (!connected) { DEBUG("%s disconnected from %s\n", ch->varName, dbch->dbName); @@ -453,7 +447,8 @@ void seq_conn_handler(void *var, int connected) { epicsEventSignal(sp->ready); } - dbCount = pvVarGetCount(var); + assert(pvVarIsDefined(dbch->pvid)); + dbCount = pvVarGetCount(&dbch->pvid); assert(dbCount >= 0); dbch->dbCount = min(ch->count, (unsigned)dbCount); diff --git a/src/seq/seq_if.c b/src/seq/seq_if.c index 35ba19aa..6df3bd65 100644 --- a/src/seq/seq_if.c +++ b/src/seq/seq_if.c @@ -160,10 +160,9 @@ epicsShareFunc pvStat epicsShareAPI seq_pvGet(SS_ID ss, VAR_ID varId, enum compT /* Perform the PV get operation with a callback routine specified. Requesting more than db channel has available is ok. */ status = pvVarGetCallback( - dbch->pvid, /* PV id */ + &dbch->pvid, /* PV id */ ch->type->getType, /* request type */ ch->count, /* element count */ - seq_get_handler, /* callback handler */ req); /* user arg */ if (status != pvStatOK) { @@ -438,7 +437,7 @@ epicsShareFunc pvStat epicsShareAPI seq_pvPut(SS_ID ss, VAR_ID varId, enum compT if (compType == DEFAULT) { status = pvVarPutNoBlock( - dbch->pvid, /* PV id */ + &dbch->pvid, /* PV id */ ch->type->putType, /* data type */ count, /* element count */ (pvValue *)var); /* data value */ @@ -460,11 +459,10 @@ epicsShareFunc pvStat epicsShareAPI seq_pvPut(SS_ID ss, VAR_ID varId, enum compT ss->putReq[varId] = req; status = pvVarPutCallback( - dbch->pvid, /* PV id */ + &dbch->pvid, /* PV id */ ch->type->putType, /* data type */ count, /* element count */ (pvValue *)var, /* data value */ - seq_put_handler, /* callback handler */ req); /* user arg */ if (status != pvStatOK) { @@ -592,8 +590,7 @@ epicsShareFunc pvStat epicsShareAPI seq_pvAssign(SS_ID ss, VAR_ID varId, const c if (dbch) /* was assigned to a named PV */ { - status = pvVarDestroy(dbch->pvid); - dbch->pvid = NULL; + status = pvVarDestroy(&dbch->pvid); sp->assignCount -= 1; @@ -658,8 +655,8 @@ epicsShareFunc pvStat epicsShareAPI seq_pvAssign(SS_ID ss, VAR_ID varId, const c sp->pvSys, /* PV system context */ dbch->dbName, /* DB channel name */ seq_conn_handler, /* connection handler routine */ + seq_event_handler, /* event handler routine */ ch, /* user ptr is CHAN structure */ - sp->debug, /* debug level (inherited) */ &dbch->pvid); /* ptr to pvid */ if (status != pvStatOK) { @@ -1010,9 +1007,9 @@ static void *getq_cp(void *dest, const void *value, size_t elemSize) { assert(pv_is_time_type(type)); /* Copy status, severity and time stamp */ - meta->status = *pv_status_ptr(value,type); - meta->severity = *pv_severity_ptr(value,type); - meta->timeStamp = *pv_stamp_ptr(value,type); + meta->status = pv_status(value,type); + meta->severity = pv_severity(value,type); + meta->timeStamp = pv_stamp(value,type); count = ch->dbch->dbCount; } return memcpy(var, pv_value_ptr(value,type), ch->type->size * count); diff --git a/src/seq/seq_main.c b/src/seq/seq_main.c index f9506d11..ae224006 100644 --- a/src/seq/seq_main.c +++ b/src/seq/seq_main.c @@ -97,20 +97,6 @@ epicsShareFunc void epicsShareAPI seq( else threadName = sp->progName; - /* Specify PV system name (defaults to CA) */ - str = seqMacValGet(sp, "pvsys"); - if (str && str[0] != '\0') - sp->pvSysName = str; - else - sp->pvSysName = "ca"; - - /* Determine debug level (currently only used for PV-level debugging) */ - str = seqMacValGet(sp, "debug"); - if (str && str[0] != '\0') - sp->debug = atoi(str); - else - sp->debug = 0; - /* Specify thread priority */ sp->threadPriority = THREAD_PRIORITY; str = seqMacValGet(sp, "priority"); diff --git a/src/seq/seq_prog.c b/src/seq/seq_prog.c index c2702731..cc0742e6 100644 --- a/src/seq/seq_prog.c +++ b/src/seq/seq_prog.c @@ -123,19 +123,18 @@ static int addProg(SPROG **ppInstances, seqProgram *pseq, void *param) SPROG *sp = (SPROG *)param; if (!ppInstances || !pseq) { - if (!sp->pvSys) { - seqCreatePvSys(sp); + if (!pvSysIsDefined(sp->pvSys)) { + pvStat status = pvSysCreate(&sp->pvSys); + if (status != pvStatOK) { + errlogPrintf("pvSysCreate() failure\n"); + } } return FALSE; } - assert(sp->pvSysName); - /* search for an instance with the same pvSysName */ - if (!sp->pvSys) { + if (!pvSysIsDefined(sp->pvSys)) { SPROG *curSP; foreach(curSP, *ppInstances) { - if (strcmp(sp->pvSysName, curSP->pvSysName) == 0) { - DEBUG("Found a program instance (%p[%d]) with pvSys=%s.\n", - curSP, curSP->instance, curSP->pvSysName); + if (pvSysIsDefined(curSP->pvSys)) { sp->pvSys = curSP->pvSys; } break; @@ -161,7 +160,7 @@ static int addProg(SPROG **ppInstances, seqProgram *pseq, void *param) } DEBUG("Added program %p, instance %d to instance list.\n", sp, sp->instance); - if (sp->pvSys) + if (pvSysIsDefined(sp->pvSys)) return TRUE; } return FALSE; diff --git a/src/seq/seq_task.c b/src/seq/seq_task.c index f996b265..afbf72f1 100644 --- a/src/seq/seq_task.c +++ b/src/seq/seq_task.c @@ -34,7 +34,7 @@ void sequencer (void *arg) /* ptr to original (global) state program table */ and if necessary create pvSys */ seqAddProg(sp); - if (!sp->pvSys) + if (!pvSysIsDefined(sp->pvSys)) { sp->die = TRUE; goto exit; @@ -485,15 +485,6 @@ void epicsShareAPI seqStop(epicsThreadId tid) seq_exit(sp->ss); } -void seqCreatePvSys(SPROG *sp) -{ - int debug = sp->debug; - pvStat status = pvSysCreate(sp->pvSysName, - max(0, debug-1), &sp->pvSys); - if (status != pvStatOK) - errlogSevPrintf(errlogFatal, "pvSysCreate(\"%s\") failure\n", sp->pvSysName); -} - /* * ss_wakeup() -- wake up each state set that is waiting on this event * based on the current event mask; eventNum = 0 means wake all state sets. diff --git a/test/Makefile b/test/Makefile index 69fa3481..1bb8d33e 100644 --- a/test/Makefile +++ b/test/Makefile @@ -2,7 +2,6 @@ TOP = .. include $(TOP)/configure/CONFIG DIRS += compiler -DIRS += pv DIRS += validate ifeq '$(EPICS_HAS_UNIT_TEST)' '1' diff --git a/test/pv/Makefile b/test/pv/Makefile deleted file mode 100644 index 4bf1326e..00000000 --- a/test/pv/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -TOP = ../.. - -include $(TOP)/configure/CONFIG -#---------------------------------------- -# ADD MACRO DEFINITIONS AFTER THIS LINE - -# purify support (uncomment to enable) -#CXX := purify $(CXX) - -# Profiling doesn't work for threaded applications? -#arrput_CXXFLAGS = -p -#arrputCA_CXXFLAGS = -p - -# Generate snc main programs -SNCFLAGS = +m - -# Products -TESTPROD_HOST += arrput -TESTPROD_HOST += arrputCA -TESTPROD_HOST += pvsimpleC -TESTPROD_HOST += pvsimpleCC -TESTPROD_HOST += pvtest - -# Libraries -PROD_LIBS += seq pv -PROD_LIBS += $(EPICS_BASE_IOC_LIBS) - -include $(TOP)/configure/RULES -#---------------------------------------- -# ADD RULES AFTER THIS LINE diff --git a/test/pv/arrput.cc b/test/pv/arrput.cc deleted file mode 100644 index c9593411..00000000 --- a/test/pv/arrput.cc +++ /dev/null @@ -1,52 +0,0 @@ -/* Loop putting simulated values to an array-valued PV */ - -#include <stdio.h> -#include <stdlib.h> -#include <time.h> - -#include "epicsThread.h" - -#include "pv.h" - -#define SYSNAME "ca" /* system name (hard-coded for CA) */ - -#define REPORT \ - if ( sys.getSevr() != pvSevrNONE ) \ - printf( "%s: %d %d %d %s\n", name, sys.getStatus(), \ - sys.getSevr(), sys.getStat(), sys.getMess() ) - - -/* main program */ -int main( int argc, char *argv[] ) { - const char *prog = ( argc > 0 ) ? argv[0] : "prog?"; - const char *name = ( argc > 1 ) ? argv[1] : "k0:ao:wc:tl:dmActVec"; - int cycle = ( argc > 2 ) ? atoi( argv[2] ) : 0; - double delay = ( argc > 3 ) ? atof( argv[3] ) : 0.05; - double scale = ( argc > 4 ) ? atof( argv[4] ) : 1.0 / ( 32767 * 10 ); - double zero = ( argc > 5 ) ? atof( argv[5] ) : 0.0; - - printf( "%s: name=%s, cycle=%d, delay=%g, scale=%g, zero=%g\n", - prog, name, cycle, delay, scale, zero ); - - pvSystem &sys = *newPvSystem( SYSNAME, 0 ); - REPORT; - pvVariable &var = *sys.newVariable( name ); - sys.pend( 1.0 ); - REPORT; - - int count = var.getCount(); - pvValue &value = * ( pvValue * ) new double[count]; - - srand( time( NULL ) ); - for ( int i = 0; i < cycle || cycle == 0; i++ ) { - - for ( int j = 0; j < count; j++ ) - value.doubleVal[j] = ( ( double ) rand() ) * scale + zero; - - var.put( pvTypeDOUBLE, count, &value ); - REPORT; - - epicsThreadSleep( delay ); - } -} - diff --git a/test/pv/arrputCA.cc b/test/pv/arrputCA.cc deleted file mode 100644 index 5f997fb6..00000000 --- a/test/pv/arrputCA.cc +++ /dev/null @@ -1,43 +0,0 @@ -/* Loop putting simulated values to an array-valued PV (CA version) */ - -#include <stdio.h> -#include <stdlib.h> -#include <time.h> - -#include "epicsThread.h" - -#include "cadef.h" - -#define REPORT SEVCHK( status, name ) - -/* main program */ -int main( int argc, char *argv[] ) { - const char *name = ( argc > 1 ) ? argv[1] : "k0:ao:wc:tl:dmActVec"; - int cycle = ( argc > 2 ) ? atoi( argv[2] ) : 0; - double delay = ( argc > 3 ) ? atof( argv[3] ) : 0.05; - double scale = ( argc > 4 ) ? atof( argv[4] ) : 1.0 / ( 32767 * 10 ); - - int status; - chid chid; - - status = ca_task_initialize(); - REPORT; - status = ca_search_and_connect( name, &chid, NULL, NULL ); - REPORT; - status = ca_pend_io( 1.0 ); - REPORT; - - int count = ca_element_count( chid ); - double *value = new double[count]; - - srand( time( NULL ) ); - for ( int i = 0; i < cycle || cycle == 0; i++ ) { - for ( int j = 0; j < count; j++ ) - value[j] = ( ( double ) rand() ) * scale; - - status = ca_array_put( DBR_DOUBLE, count, chid, value ); - REPORT; - epicsThreadSleep( delay ); - } -} - diff --git a/test/pv/pvsimpleC.c b/test/pv/pvsimpleC.c deleted file mode 100644 index bfbda6ab..00000000 --- a/test/pv/pvsimpleC.c +++ /dev/null @@ -1,59 +0,0 @@ -/*************************************************************************\ -This file is distributed subject to a Software License Agreement found -in the file LICENSE that is included with this distribution. -\*************************************************************************/ -/* Very simple C program to demonstrate pv classes */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "pv.h" - -/* event handler (get/put completion; monitors) */ -static void event( void *var, pvType type, unsigned count, - pvValue *val, void *arg, pvStat stat ) { - printf( "event: %s=%g\n", pvVarGetName( var ), val->doubleVal[0] ); -} - -/* main program */ -int main( int argc, char *argv[] ) { - /* system and variable names */ - const char *sysNam = ( argc > 1 ) ? argv[1] : "ca"; - const char *varNam = ( argc > 2 ) ? argv[2] : "demo:voltage"; - void *sys; - void *var; - int status; - - /* create system */ - status = pvSysCreate( sysNam, 0, &sys ); - if ( status ) { - printf( "pvSysCreate( %s ) failure\n", sysNam ); - return -1; - } - - /* create variable */ - status = pvVarCreate( sys, varNam, NULL, NULL, 0, &var ); - if ( status ) { - printf( "pvVarCreate( %s, %s ) failure\n", sysNam, varNam ); - return -1; - } - - /* monitor variable as double (assume scalar) */ - status = pvVarMonitorOn( var, pvTypeDOUBLE, 1, event, NULL, NULL ); - if ( status ) { - printf( "pvVarMonitorOn( %s ) failure\n", varNam ); - } - - /* shouldn't need this! */ - pvSysPend( sys, 1, FALSE ); - - /* block for 10 seconds */ - pvSysPend( sys, 10, TRUE ); - - /* tidy up */ - pvVarDestroy( var ); - pvSysDestroy( sys ); - return 0; -} - diff --git a/test/pv/pvsimpleCC.cc b/test/pv/pvsimpleCC.cc deleted file mode 100644 index 97d4abe0..00000000 --- a/test/pv/pvsimpleCC.cc +++ /dev/null @@ -1,56 +0,0 @@ -// Very simple C++ program to demonstrate pv classes - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "pv.h" - -// event handler (get/put completion; monitors) -static void event( void *obj, pvType type, unsigned count, - pvValue *val, void *arg, pvStat stat ) { - pvVariable *var = ( pvVariable * ) obj; - printf( "event: %s=%g\n", var->getName(), val->doubleVal[0] ); -} - -// main program -int main( int argc, char *argv[] ) { - // system and variable names - const char *sysNam = ( argc > 1 ) ? argv[1] : "ca"; - const char *varNam = ( argc > 2 ) ? argv[2] : "demo:voltage"; - - // create system - pvSystem *sys = newPvSystem( sysNam ); - if ( sys == NULL ) { - printf( "newPvSystem( %s ) failure\n", sysNam ); - return -1; - } - - // create variable - pvVariable *var = sys->newVariable( varNam ); - if ( var == NULL ) { - printf( "%s->newVariable( %s ) failure\n", sysNam, varNam ); - return -1; - } - - // monitor variable as double (assume scalar) - int status = var->monitorOn( pvTypeDOUBLE, 1, event ); - if ( status ) { - printf( "%s->monitorOn() failure\n", varNam ); - } - - // shouldn't need this! - sys->pend( 1, FALSE ); - - // block for 10 seconds - sys->pend( 10, TRUE ); -printf( "after pend\n" ); -//threadExitMain(); -printf( "after exit\n" ); - - // tidy up -// delete var; -// delete sys; - return 0; -} - diff --git a/test/pv/pvtest.cc b/test/pv/pvtest.cc deleted file mode 100644 index 24765647..00000000 --- a/test/pv/pvtest.cc +++ /dev/null @@ -1,108 +0,0 @@ -/* Test pv classes */ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include "pv.h" - -#define TYPE(_type) \ - ( _type[0] == 'c' ? pvTypeTIME_CHAR : \ - _type[0] == 'h' ? pvTypeTIME_SHORT : \ - _type[0] == 'l' ? pvTypeTIME_LONG : \ - _type[0] == 'f' ? pvTypeTIME_FLOAT : \ - _type[0] == 's' ? pvTypeTIME_STRING : \ - pvTypeTIME_DOUBLE ) - -#define OUTPUT(_type,_val,_ind) \ - ( _type == pvTypeTIME_CHAR ? \ - printf( "%d", _val->timeCharVal.value[_ind] & 0xff ) : \ - _type == pvTypeTIME_SHORT ? \ - printf( "%hd", _val->timeShortVal.value[_ind] ) : \ - _type == pvTypeTIME_LONG ? \ - printf( "%d", _val->timeLongVal.value[_ind] ) : \ - _type == pvTypeTIME_FLOAT ? \ - printf( "%g", _val->timeFloatVal.value[_ind] ) : \ - _type == pvTypeTIME_STRING ? \ - printf( "\"%s\"", _val->timeStringVal.value[_ind] ) : \ - printf( "%g", _val->timeDoubleVal.value[_ind] ) ) - -void conn( void *, int connected ) { - printf( "conn: connected=%d\n", connected ); -} - -void event( void *, pvType type, unsigned count, pvValue *val, void *arg, - pvStat stat) { - if ( stat != pvStatOK ) { - printf( "event%p: stat=%d\n", arg, stat ); - } - else { - printf( "event%p: tim=%d, val=", arg, val->timeDoubleVal.stamp. - secPastEpoch ); - OUTPUT( type, val, 0 ); - if ( count > 1 ) { - printf( " ... " ); - OUTPUT( type, val, count - 1 ); - } - printf( "\n" ); - } -} - -int main( int argc, char *argv[] ) { - char *snm = ( argc < 2 ) ? ( char * ) "ca" : argv[1]; - int deb = ( argc < 3 ) ? 1 : atoi( argv[2] ); - pvSystem *sys = newPvSystem( snm, deb ); - if ( sys == NULL ) { - printf( "newPvSystem( %s ) failure\n", snm ); - return -1; - } - printf( "%s: %d %d %d %s\n", snm, sys->getStatus(), sys->getSevr(), - sys->getStat(), sys->getMess() ); - - char *nam = ( argc < 4 ) ? ( strcmp( snm, "ca" ) == 0 ? \ - ( char * ) "k1:ao:sc:cpu" : ( char * ) "ao1.aosccpu" ) : argv[3]; - pvVariable *var = sys->newVariable( nam, conn, NULL, deb ); - if ( var == NULL ) { - printf( "%s->newVariable( %s ) failure\n", snm, nam ); - return -1; - } - printf( "%s: %d %d %d %s\n", nam, var->getStatus(), var->getSevr(), - var->getStat(), var->getMess() ); - - char *typ = ( argc < 5 ) ? ( char * ) "d" : argv[4]; - int cnt = var->getCount(); - var->monitorOn( TYPE( typ ), cnt, event, ( void * ) 0 ); - sys->pend( 1, FALSE ); - - if ( var->getStat() == pvStatOK ) - printf( "%s: connected=%d, type=%d, count=%d, private=%p\n", nam, - var->getConnected(), var->getType(), cnt, var->getPrivate() ); - - pvValue *val = new pvValue[cnt]; - var->get( TYPE( typ ), cnt, val ); - sys->pend( 1, FALSE ); - - printf( "%s: %d %d %d %s\n", nam, var->getStatus(), var->getSevr(), - var->getStat(), var->getMess() ); - if ( var->getStat() == pvStatOK ) { - OUTPUT( TYPE( typ ), val, 0 ); - printf( "\n" ); - } - - var->getCallback( TYPE( typ ), cnt, event, ( void * ) 1 ); - sys->pend( 1, TRUE ); - - printf( "%s: %d %d %d %s\n", nam, var->getStatus(), var->getSevr(), - var->getStat(), var->getMess() ); - - sys->pend( 10, TRUE ); - - printf( "%s: %d %d %d %s\n", nam, var->getStatus(), var->getSevr(), - var->getStat(), var->getMess() ); - - delete var; - delete sys; - - return 0; -} - -- GitLab