EPICS Controls Argonne National Laboratory

Experimental Physics and
Industrial Control System

1994  <19951996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024  Index 1994  <19951996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
<== Date ==> <== Thread ==>

Subject: Re: Re[2]: Portable CA Server
From: [email protected] (Jeff Hill)
Date: Fri, 19 May 95 16:47:24 MDT
----------
X-Sun-Data-Type: text
X-Sun-Data-Description: text
X-Sun-Data-Name: text
X-Sun-Content-Lines: 18


Hello,

Attached are the header files for the new CA server API. All comments 
are appreciated.

casdef.h		- new ca server API
exampleCaServer.c 	- simple application of the new ca server library
epicsTypes.h		- new core architecture independent types for EPICS
alarm.h			- def of alarm codes (new enum added)
tsDefs.h		- def of time stamp structure (unchanged)

Jeff

______________________________________________________________________
Jeffrey O. Hill			Internet	[email protected]
LANL MS H820			Voice		505 665 1831
Los Alamos, NM 87545 USA 	FAX		505 665 5107
----------
X-Sun-Data-Type: h-file
X-Sun-Data-Description: h-file
X-Sun-Data-Name: epicsTypes.h
X-Sun-Content-Lines: 230

/* $Id  */

/*
 *      Author: 	Jeff Hill  
 *      Date:          	5-95 
 *
 *      Experimental Physics and Industrial Control System (EPICS)
 *
 *      Copyright 1991, the Regents of the University of California,
 *      and the University of Chicago Board of Governors.
 *
 *      This software was produced under  U.S. Government contracts:
 *      (W-7405-ENG-36) at the Los Alamos National Laboratory,
 *      and (W-31-109-ENG-38) at Argonne National Laboratory.
 *
 *      Initial development by:
 *              The Controls and Automation Group (AT-8)
 *              Ground Test Accelerator
 *              Accelerator Technology Division
 *              Los Alamos National Laboratory
 *
 *      Co-developed with
 *              The Controls and Computing Group
 *              Accelerator Systems Division
 *              Advanced Photon Source
 *              Argonne National Laboratory
 *
 * Modification Log:
 * -----------------
 * .00  mm-dd-yy        iii     Comment
 */

#ifndef INCepicsTypesh
#define INCepicsTypesh 1

#define stringOf(TOKEN) #TOKEN

typedef enum {
	epicsFalse=0, 
	epicsTrue=1 } 	epicsBoolean;

/*
 * Architecture Independent Data Types
 * (so far this is sufficient for all archs we have ported to)
 */
typedef char		epicsInt8;
typedef unsigned char   epicsUInt8;
typedef short           epicsInt16;
typedef unsigned short  epicsUInt16;
typedef epicsUInt16	epicsEnum16;
typedef int             epicsInt32;
typedef unsigned 	epicsUInt32;
typedef float           epicsFloat32;
typedef double          epicsFloat64;
typedef struct {
	unsigned	length;
	char		*pString;
}epicsString;



/*
 * !! Dont use this - it may vanish in the future !!
 *
 * Provided only for backwards compatibility with
 * db_access.h 
 *
 * The dimension of this must match MAX_STRING_SIZE
 * in db_access.h (if it doesnt the CA server will 
 * refuse to init)
 */
typedef char            epicsWeirdString[40]; 

/*
 * union of all types
 *
 * Strings included here as pointers only so that we support
 * large string types.
 */
typedef union {
        epicsInt8       int8;
        epicsUInt8      uInt8;
        epicsInt16      int16;
        epicsUInt16     uInt16;
        epicsEnum16     enum16;
        epicsInt32      int32;
        epicsUInt32     uInt32;
        epicsFloat32    float32;
        epicsFloat64    float64;
	epicsString	string;
}epicsAny;
	
/*
 * Corresponding Type Codes
 * (this enum must start at zero)
 *
 * !! Update epicsTypeToDBR_XXXX[] and DBR_XXXXToEpicsType
 * 	in db_access.h if you edit this enum !!
 */
typedef enum {
                epicsInt8T,
                epicsUInt8T,
                epicsInt16T,
                epicsUInt16T,
                epicsEnum16T,
                epicsInt32T,
                epicsUInt32T,
                epicsFloat32T,
                epicsFloat64T,
                epicsStringT,
                epicsWeirdStringT
}epicsType;
#define firstEpicsType epicsInt8T
#define lastEpicsType epicsWeirdStringT 
#define validEpicsType(x) 	((x>=firstEpicsType) && (x<=lastEpicsType))
#define invalidEpicsType(x)	((x<firstEpicsType) || (x>lastEpicsType))


/*
 * The enumeration "epicsType" is an index to this array
 * of type name strings.
 */
#ifdef epicsTypesGLOBAL
const char *epicsTypeNames [lastEpicsType+1] = {
		stringOf (epicsInt8),
		stringOf (epicsUInt8),
		stringOf (epicsInt16),
		stringOf (epicsUInt16),
		stringOf (epicsEnum16),
		stringOf (epicsInt32),
		stringOf (epicsUInt32),
		stringOf (epicsFloat32),
		stringOf (epicsFloat64),
		stringOf (epicsString),
		stringOf (epicsWeirdString),
};
#else /* epicsTypesGLOBAL */
extern const char *epicsTypeNames [lastEpicsType+1];
#endif /* epicsTypesGLOBAL */

/*
 * The enumeration "epicsType" is an index to this array
 * of type code name strings.
 */
#ifdef epicsTypesGLOBAL
const char *epicsTypeCodeNames [lastEpicsType+1] = {
		stringOf (epicsInt8T),
		stringOf (epicsUInt8T),
		stringOf (epicsInt16T),
		stringOf (epicsUInt16T),
		stringOf (epicsEnum16T),
		stringOf (epicsInt32T),
		stringOf (epicsUInt32T),
		stringOf (epicsFloat32T),
		stringOf (epicsFloat64T),
		stringOf (epicsStringT),
		stringOf (epicsWeirdStringT),
};
#else /* epicsTypesGLOBAL */
extern const char *epicsTypeCodeNames [lastEpicsType+1];
#endif /* epicsTypesGLOBAL */

#ifdef epicsTypesGLOBAL
const unsigned epicsTypeSizes [lastEpicsType+1] = {
		sizeof (epicsInt8),
		sizeof (epicsUInt8),
		sizeof (epicsInt16),
		sizeof (epicsUInt16),
		sizeof (epicsEnum16),
		sizeof (epicsInt32),
		sizeof (epicsUInt32),
		sizeof (epicsFloat32),
		sizeof (epicsFloat64),
		sizeof (epicsString),
		sizeof (epicsWeirdString),
};
#else /* epicsTypesGLOBAL */
extern const unsigned epicsTypeSizes [lastEpicsType+1];
#endif /* epicsTypesGLOBAL */

/*
 * The enumeration "epicsType" is an index to this array
 * of type class identifiers.
 */
typedef enum {
	epicsIntC, 
	epicsUIntC, 
	epicsEnumC,
	epicsFloatC, 
	epicsStringC,
	epicsWeirdStringC} epicsTypeClass;
#ifdef epicsTypesGLOBAL
const epicsTypeClass epicsTypeClasses [lastEpicsType+1] = {
		epicsIntC,
		epicsUIntC,
		epicsIntC,
		epicsUIntC,
		epicsEnumC,
		epicsIntC,
		epicsUIntC,
		epicsFloatC,
		epicsFloatC,
		epicsStringC,
		epicsWeirdStringC
	};
#else /* epicsTypesGLOBAL */
extern const epicsTypeClass epicsTypeClasses [lastEpicsType+1];
#endif /* epicsTypesGLOBAL */


#ifdef epicsTypesGLOBAL
const char *epicsTypeAnyFieldName [lastEpicsType+1] = {
			stringOf (int8),
			stringOf (uInt8),
			stringOf (int16),
			stringOf (uInt16),
			stringOf (enum16),
			stringOf (int32),
			stringOf (uInt32),
			stringOf (float32),
			stringOf (float64),
			stringOf (string),
			"", /* Weird Strings will not be in epicsAny type */
	};
#else /* epicsTypesGLOBAL */
extern const char *epicsTypeAnyFieldName [lastEpicsType+1];
#endif /* epicsTypesGLOBAL */

#endif /* INCepicsTypesh */

----------
X-Sun-Data-Type: h-file
X-Sun-Data-Description: h-file
X-Sun-Data-Name: alarm.h
X-Sun-Content-Lines: 107

/* Alarm definitions (Must Match choiceGbl.ascii) */
/* $Id: alarm.h,v 1.9 1994/07/13 02:24:04 bordua Exp $ */

/*
 *      Original Author: Bob Dalesio
 *      Current Author:  Marty Kraimer
 *      Date:            11-7-90
 *
 *      Experimental Physics and Industrial Control System (EPICS)
 *
 *      Copyright 1991, the Regents of the University of California,
 *      and the University of Chicago Board of Governors.
 *
 *      This software was produced under  U.S. Government contracts:
 *      (W-7405-ENG-36) at the Los Alamos National Laboratory,
 *      and (W-31-109-ENG-38) at Argonne National Laboratory.
 *
 *      Initial development by:
 *              The Controls and Automation Group (AT-8)
 *              Ground Test Accelerator
 *              Accelerator Technology Division
 *              Los Alamos National Laboratory
 *
 *      Co-developed with
 *              The Controls and Computing Group
 *              Accelerator Systems Division
 *              Advanced Photon Source
 *              Argonne National Laboratory
 *
 * Modification Log:
 * -----------------
 * .00  mm-dd-yy        iii     Comment
 * .01  07-16-92        jba     changed VALID_ALARM to INVALID_ALARM
 * .02  08-11-92        jba     added new status DISABLE_ALARM, SIMM_ALARM
 * .03  05-11-94        jba     added new status READ_ACCESS_ALARM, WRITE_ACCESS_ALARM
 */

#ifndef INCalarmh
#define INCalarmh 1

/* defines for the choice fields */
/* ALARM SEVERITIES - NOTE: must match defs in choiceGbl.ascii GBL_ALARM_SEV */
#define NO_ALARM		0x0
#define	MINOR_ALARM		0x1
#define	MAJOR_ALARM		0x2
#define INVALID_ALARM		0x3
#define ALARM_NSEV		INVALID_ALARM+1

typedef enum {
	epicsSevNone = NO_ALARM, 
	epicsSevMajor = MINOR_ALARM, 
	epicsSevInvalid = MAJOR_ALARM
}epicsAlarmSeverity;

/* ALARM STATUS  -NOTE: must match defs in choiceGbl.ascii GBL_ALARM_STAT */
/* NO_ALARM = 0 as above */
#define	READ_ALARM		1
#define	WRITE_ALARM		2
/* ANALOG ALARMS */
#define	HIHI_ALARM		3
#define	HIGH_ALARM		4
#define	LOLO_ALARM		5
#define	LOW_ALARM		6
/* BINARY ALARMS */
#define	STATE_ALARM		7
#define	COS_ALARM		8
/* other alarms */
#define COMM_ALARM		9
#define	TIMEOUT_ALARM		10
#define	HW_LIMIT_ALARM		11
#define	CALC_ALARM		12
#define	SCAN_ALARM		13
#define	LINK_ALARM		14
#define	SOFT_ALARM		15
#define	BAD_SUB_ALARM		16
#define	UDF_ALARM		17
#define	DISABLE_ALARM		18
#define	SIMM_ALARM		19
#define	READ_ACCESS_ALARM	20
#define	WRITE_ACCESS_ALARM	21
#define ALARM_NSTATUS		WRITE_ACCESS_ALARM + 1

typedef enum {
	epicsAlarmRead = READ_ALARM, 
	epicsAlarmWrite = WRITE_ALARM, 
	epicsAlarmHiHi = HIHI_ALARM,
	epicsAlarmHigh = HIGH_ALARM,
	epicsAlarmLoLo = LOLO_ALARM,
	epicsAlarmLow = LOW_ALARM,
	epicsAlarmState = STATE_ALARM,
	epicsAlarmCos = COS_ALARM,
	epicsAlarmComm = COMM_ALARM,
	epicsAlarmTimeout = TIMEOUT_ALARM,
	epicsAlarmHwLimit = HW_LIMIT_ALARM,
	epicsAlarmCalc = CALC_ALARM,
	epicsAlarmScan = SCAN_ALARM,
	epicsAlarmLink = LINK_ALARM,
	epicsAlarmSoft = SOFT_ALARM,
	epicsAlarmBadSub = BAD_SUB_ALARM,
	epicsAlarmUDF = UDF_ALARM,
	epicsAlarmDisable = DISABLE_ALARM,
	epicsAlarmSimm = SIMM_ALARM,
	epicsAlarmReadAccess = READ_ACCESS_ALARM,
	epicsAlarmWriteAccess = WRITE_ACCESS_ALARM
}epicsAlarmCondition;
#endif

----------
X-Sun-Data-Type: h-file
X-Sun-Data-Description: h-file
X-Sun-Data-Name: tsDefs.h
X-Sun-Content-Lines: 286

#ifndef INC_tsDefs_h
#define INC_tsDefs_h
/*	$Id: tsDefs.h,v 1.12 1994/11/17 19:08:49 jhill Exp $	
 *	Author:	Roger A. Cole
 *	Date:	08-09-90
 *
 *	Experimental Physics and Industrial Control System (EPICS)
 *
 *	Copyright 1991-92, the Regents of the University of California,
 *	and the University of Chicago Board of Governors.
 *
 *	This software was produced under  U.S. Government contracts:
 *	(W-7405-ENG-36) at the Los Alamos National Laboratory,
 *	and (W-31-109-ENG-38) at Argonne National Laboratory.
 *
 *	Initial development by:
 *		The Controls and Automation Group (AT-8)
 *		Ground Test Accelerator
 *		Accelerator Technology Division
 *		Los Alamos National Laboratory
 *
 *	Co-developed with
 *		The Controls and Computing Group
 *		Accelerator Systems Division
 *		Advanced Photon Source
 *		Argonne National Laboratory
 *
 * Modification Log:
 * -----------------
 *  .01 08-09-90 rac	initial version
 *  .02 06-18-91 rac	installed in SCCS
 *  .03 08-03-92 rac	added tsRound routines
 *
 */
/*+/mod***********************************************************************
* TITLE	tsDefs.h - time-stamp related definitions
*
* DESCRIPTION
*
* BUGS
* o	only a single, manually configured, conversion between local
*	time and GMT is supported.  Thus, if a new `rule' for daylight
*	savings time were invented, then this code would be `broken'
*	until this file were configured for the new rule.  BUT, then
*	this code is `broken' for the period prior to the new rule's
*	effect.
* o	only dates following Jan 1, 1990 are handled; stamps on Jan 1,
*	1990 are treated as `dateless' times.
*
*-***************************************************************************/

#include <errMdef.h>	/* get M_ts for this subsystem's `number' */

/*---------------------------------------------------------------------------
-
* TS_STAMP
*
*    This is the form taken by time stamps in GTACS, and is the form used
*    by the various tools used for dealing with time stamps.
*
*    The time stamp represents the number of nanoseconds past 0000 Jan 1, 199
0,
*    GMT (or UTC, if you prefer).
*
*----------------------------------------------------------------------------
*/
typedef struct {
    unsigned    secPastEpoch;   /* seconds since 0000 Jan 1, 1990 */
    unsigned    nsec;           /* nanoseconds within second */
} TS_STAMP;

/*----------------------------------------------------------------------------
* TS_TEXT_xxx text type codes for converting between text and time stamp
*
*    TS_TEXT_MONDDYYYY	Mon dd, yyyy hh:mm:ss.nano-secs
*    TS_TEXT_MMDDYY	mm/dd/yy hh:mm:ss.nano-secs
*			123456789012345678901234567890123456789
*			0        1         2         3
*----------------------------------------------------------------------------*/
enum tsTextType{
    TS_TEXT_MONDDYYYY,
    TS_TEXT_MMDDYY
};

/*/subhead configuration------------------------------------------------------
*		C O N F I G U R A T I O N   D E F I N I T I O N S
*
* TS_DST_BEGIN	the day number for starting DST
* TS_DST_END	the day number for ending DST
* TS_MIN_WEST	the number of minutes west of GMT for time zone (zones east
*		will have negative values)
* TS_DST_HOUR_ON the hour (standard time) when DST turns on
* TS_DST_HOUR_OFF the hour (standard time) when DST turns off
* TS_DST_HRS_ADD hours to add when DST is on
*
* day numbers start with 0 for Jan 1; day numbers in these defines are
* based on a NON-leap year.  The start and end days for DST are assumed to be
* Sundays.  A negative day indicates that the following Sunday is to be used;
* a positive day indicates the prior Sunday.  If the begin date is larger than
* the end date, then DST overlaps the change of the year (e.g., for southern
* hemisphere).
*
* Note well that TS_DST_HOUR_ON and TS_DST_HOUR_OFF are both STANDARD time.
* So, if dst begins at 2 a.m. (standard time) and ends at 2 a.m. (daylight
* time), the two values would be 2 and 1, respectively (assuming
* TS_DST_HRS_ADD is 1).
*----------------------------------------------------------------------------*/
#define TS_DST_BEGIN -90	/* first Sun in Apr (Apr 1 = 90) */
#define TS_DST_END 303		/* last Sun in Oct (Oct 31 = 303) */
#define TS_DST_HOUR_ON 2	/* 2 a.m. (standard time) */
#define TS_DST_HOUR_OFF 1	/* 2 a.m. (1 a.m. standard time) */
#define TS_DST_HRS_ADD 1	/* add one hour */
#define TS_MIN_WEST 7 * 60	/* USA mountain time zone */
#if 0		/* first set is for testing only */
#define TS_EPOCH_YEAR 1989
#define TS_EPOCH_SEC_PAST_1970 6940*86400 /* 1/1/89 19 yr (5 leap) of seconds */
#define TS_EPOCH_WDAY_NUM 0	/* Jan 1 1989 was Sun (wkday num = 0) */
#else
#define TS_EPOCH_YEAR 1990
#define TS_EPOCH_SEC_PAST_1970 7305*86400 /* 1/1/90 20 yr (5 leap) of seconds */
#define TS_EPOCH_WDAY_NUM 1	/* Jan 1 1990 was Mon (wkday num = 1) */
#endif
#define TS_MAX_YEAR TS_EPOCH_YEAR+134	/* ULONG can handle 135 years */
#define TS_TRUNC 1000000	/* truncate to milli-second significance */

/*/subhead struct tsDetail----------------------------------------------------
*    breakdown structure for working with secPastEpoch
*----------------------------------------------------------------------------*/

struct tsDetail {
    int         year;           /* 4 digit year */
    int         dayYear;        /* day number in year; 0 = Jan 1 */
    int         monthNum;       /* month number; 0 = Jan */
    int         dayMonth;       /* day number; 0 = 1st of month */
    int         hours;          /* hours within day */
    int         minutes;        /* minutes within hour */
    int         seconds;        /* seconds within minute */
    int         dayOfWeek;      /* weekday number; 0 = Sun */
    int         leapYear;       /* (0, 1) for year (isn't, is) a leap year */
    char	dstOverlapChar;	/* indicator for distinguishing duplicate
				times in the `switch to standard' time period:
				':'--time isn't ambiguous;
				's'--time is standard time
				'd'--time is daylight time */
};

/*/subhead status codes-------------------------------------------------------
*		S T A T U S   C O D E S
*
*	
*    Status codes for time stamp routines have the form S_ts_briefMessage  .
*
*    The macro TsStatusToText(stat) can be used to obtain a text string
*    corresponding to a status code.
*
*----------------------------------------------------------------------------*/
#define S_ts_OK		     (M_ts|0| 0<<1) /* success */
#define S_ts_sysTimeError    (M_ts|1| 1<<1) /* error getting system time */
#define S_ts_badTextCode     (M_ts|1| 2<<1) /* invalid TS_TEXT_xxx code */
#define S_ts_inputTextError  (M_ts|1| 3<<1) /* error in text date or time */
#define S_ts_timeSkippedDST  (M_ts|1| 4<<1) /* time skipped on switch to DST */
#define S_ts_badRoundInterval (M_ts|1| 5<<1) /* invalid rounding interval */

#define TS_S_PAST		 6	/* one past last legal code */

#define TsStatusToIndex(status) \
	(  ((status&0xffff0000)!=M_ts)  \
		? TS_S_PAST  \
		: (  (((status&0xffff)>>1)>=TS_S_PAST)  \
		     ? TS_S_PAST  \
		     : ((status&0xffff)>>1)  \
		  )  \
	)

#define TsStatusToText(status) \
	(glTsStatText[TsStatusToIndex(status)])

#ifndef TS_PRIVATE_DATA
    extern char *glTsStatText[];
#else
    char *glTsStatText[] = {
	/* S_ts_OK                */ "success",
	/* S_ts_sysTimeError      */ "error getting system time",
	/* S_ts_badTextCode       */ "invalid TS_TEXT_xxx code",
	/* S_ts_inputTextError    */ "error in text date or time",
	/* S_ts_timeSkippedDST    */ "time skipped on switch to DST",
	/* S_ts_badRoundInterval  */ "rounding interval is invalid",

	/* TS_S_PAST              */ "illegal TS status code",
    };
#endif

/*/subhead macros-------------------------------------------------------------
*    arithmetic macros
*
*	care has been taken in writing these macros that the result can
*	be stored back into either operand time stamp.  For example,
*	both of the following (as well as other variations) are legal:
*		TsAddStamps(pS1, pS1, pS2);
*		TsDiffAsStamp(pS2, pS1, pS2);
*----------------------------------------------------------------------------*/
#define TsAddDouble(pSum, pS1, dbl) \
  (void)( \
    dbl >= 0. \
      ? ((*pSum).secPastEpoch = (*pS1).secPastEpoch + (unsigned long)dbl, \
        ( ((*pSum).nsec = (*pS1).nsec + (unsigned long)(1000000000. * \
	    			(dbl - (double)((unsigned long)dbl))) ) ) \
		>= 1000000000 \
	    ?((*pSum).secPastEpoch += (*pSum).nsec/1000000000, \
	      (*pSum).nsec %= 1000000000) \
	    :0)  \
      : ((*pSum).secPastEpoch = (*pS1).secPastEpoch - (unsigned long)(-dbl), \
	(*pS1).nsec >= (unsigned long)(1000000000. * \
			((-dbl) - (double)((unsigned long)(-dbl)))) \
	  ?( (*pSum).nsec = (*pS1).nsec - (unsigned long)(1000000000.* \
			((-dbl) - (double)((unsigned long)(-dbl))))) \
	  :( (*pSum).nsec = (*pS1).nsec + 1000000000 - \
			(unsigned long)(1000000000.* \
			((-dbl) - (double)((unsigned long)(-dbl)))), \
	     (*pSum).secPastEpoch -= 1) )  )
#define TsAddStamps(pSum, pS1, pS2) \
    (void)( \
	((*pSum).secPastEpoch = (*pS1).secPastEpoch + (*pS2).secPastEpoch) , \
	( ((*pSum).nsec = (*pS1).nsec + (*pS2).nsec) >= 1000000000 \
	    ?((*pSum).secPastEpoch += (*pSum).nsec/1000000000, \
	      (*pSum).nsec %= 1000000000) \
	    :0)  )
#define TsDiffAsDouble(pDbl, pS1, pS2) \
  (void)( \
    *pDbl = ((double)(*pS1).nsec - (double)(*pS2).nsec)/1000000000., \
    *pDbl += (double)(*pS1).secPastEpoch - (double)(*pS2).secPastEpoch )
/* TsDiffAsStamp() assumes that stamp1 >= stamp2 */
#define TsDiffAsStamp(pDiff, pS1, pS2) \
  (void)( \
    (*pDiff).secPastEpoch = (*pS1).secPastEpoch - (*pS2).secPastEpoch , \
    (*pS1).nsec >= (*pS2).nsec \
      ?( (*pDiff).nsec = (*pS1).nsec - (*pS2).nsec ) \
      :( (*pDiff).nsec = ((*pS1).nsec + 1000000000) - (*pS2).nsec, \
	 (*pDiff).secPastEpoch -= 1 )  )
/*----------------------------------------------------------------------------
*    comparison macros
*----------------------------------------------------------------------------*/
#define TsCmpStampsEQ(pS1, pS2) \
	(((*pS1).secPastEpoch) == ((*pS2).secPastEpoch) && \
	 ((*pS1).nsec) == ((*pS2).nsec))
#define TsCmpStampsNE(pS1, pS2) \
	(((*pS1).secPastEpoch) != ((*pS2).secPastEpoch) || \
	 ((*pS1).nsec) != ((*pS2).nsec))
#define TsCmpStampsGT(pS1, pS2) \
	((((*pS1).secPastEpoch) > ((*pS2).secPastEpoch)) \
	    ?1 \
	    :((((*pS1).secPastEpoch) == ((*pS2).secPastEpoch)) \
		?((((*pS1).nsec) > ((*pS2).nsec)) ? 1 : 0) \
		:0  ))
#define TsCmpStampsGE(pS1, pS2) \
	((((*pS1).secPastEpoch) > ((*pS2).secPastEpoch)) \
	    ?1 \
	    :((((*pS1).secPastEpoch) == ((*pS2).secPastEpoch)) \
		?((((*pS1).nsec) >= ((*pS2).nsec)) ? 1 : 0) \
		:0  ))
#define TsCmpStampsLT(pS1, pS2) \
	((((*pS1).secPastEpoch) < ((*pS2).secPastEpoch)) \
	    ?1 \
	    :((((*pS1).secPastEpoch) == ((*pS2).secPastEpoch)) \
		?((((*pS1).nsec) < ((*pS2).nsec)) ? 1 : 0) \
		:0  ))
#define TsCmpStampsLE(pS1, pS2) \
	((((*pS1).secPastEpoch) < ((*pS2).secPastEpoch)) \
	    ?1 \
	    :((((*pS1).secPastEpoch) == ((*pS2).secPastEpoch)) \
		?((((*pS1).nsec) <= ((*pS2).nsec)) ? 1 : 0) \
		:0  ))
/*----------------------------------------------------------------------------
*    `prototypes'
*----------------------------------------------------------------------------*/
long tsLocalTime (TS_STAMP *pStamp);
void tsAddDouble();
int tsCmpStamps();
void tsDiffAsDouble();
long tsRoundDownLocal();
long tsRoundUpLocal();
char *tsStampToText();
long tsTextToStamp();
long tsTimeTextToStamp();

#endif
----------
X-Sun-Data-Type: h-file
X-Sun-Data-Description: h-file
X-Sun-Data-Name: errMdef.h
X-Sun-Content-Lines: 114

/* errMdef.h  err.h - Error Handling definitions */
/* share/epicsH $Id: errMdef.h,v 1.20 1995/02/18 01:44:05 jhill Exp $ */
/*
 *      Author:          Marty Kraimer
 *      Date:            6-1-90
 *
 *      Experimental Physics and Industrial Control System (EPICS)
 *
 *      Copyright 1991, the Regents of the University of California,
 *      and the University of Chicago Board of Governors.
 *
 *      This software was produced under  U.S. Government contracts:
 *      (W-7405-ENG-36) at the Los Alamos National Laboratory,
 *      and (W-31-109-ENG-38) at Argonne National Laboratory.
 *
 *      Initial development by:
 *              The Controls and Automation Group (AT-8)
 *              Ground Test Accelerator
 *              Accelerator Technology Division
 *              Los Alamos National Laboratory
 *
 *      Co-developed with
 *              The Controls and Computing Group
 *              Accelerator Systems Division
 *              Advanced Photon Source
 *              Argonne National Laboratory
 *
 * Modification Log:
 * -----------------
 * .01  mm-dd-yy        iii     Comment
 * .02	12-02-91	jrw	added GPIB and BB message codes
 * .03  03-11-93        joh     added __FILE__ and __LINE__ to errMessage()
 * .04  04-01-93        joh     added vxi
 * .05  04-29-93        joh     added errPrintStatus() func proto
 * .06  09-04-93        rcz     added functions ... for errSymLib.c merge
 * .07  02-03-94	mrk	RTN_SUCCESS is true only if status=0
 * .08  02-03-94	mrk	Add access security library
 */

#ifndef INCerrMdefh
#define INCerrMdefh

#ifdef __STDC__ 
#       include <stdarg.h>
#else
#       include <varargs.h>
#endif
#include <ellLib.h>

#define RTN_SUCCESS(STATUS) ((STATUS)==0)

#define M_dbAccess	(501 <<16) /*Database Access Routines */
#define M_sdr		(502 <<16) /*Self Defining Records */
#define M_drvSup	(503 <<16) /*Driver Support*/
#define M_devSup	(504 <<16) /*Device Support*/
#define M_recSup	(505 <<16) /*Record Support*/
#define M_recType	(506 <<16) /*Record Type*/
#define M_record	(507 <<16) /*Database Records*/
#define M_ar		(508 <<16) /*Archiver; see arDefs.h*/
#define M_ts            (509 <<16) /*Time Stamp Routines; see tsDefs.h*/
#define M_arAcc         (510 <<16) /*Archive Access Library Routines*/
#define M_bf            (511 <<16) /*Block File Routines; see bfDefs.h*/
#define M_syd           (512 <<16) /*Sync Data Routines; see sydDefs.h*/
#define M_ppr           (513 <<16) /*Portable Plot Routines; see pprPlotDefs.h*/
#define M_env           (514 <<16) /*Environment Routines; see envDefs.h*/
#define M_gen           (515 <<16) /*General Purpose Routines; see genDefs.h*/
#define	M_gpib		(516 <<16) /*Gpib driver & device support; see drvGpibInterface.h*/
#define	M_bitbus	(517 <<16) /*Bitbus driver & device support; see drvBitBusInterface.h*/
#define M_dbCa          (518 <<16) /*CA_LINKs; see calink.h*/
#define M_dbLib         (519 <<16) /*Static Database Access */
#define M_epvxi		(520 <<16) /*VXI Driver*/
#define M_devLib	(521 <<16) /*Device Resource Registration*/
#define M_asLib		(522 <<16) /*Access Security		*/
#define M_cas		(523 <<16) /*CA server*/
#define M_casApp	(524 <<16) /*CA server application*/


/*
 * redefine errMessage with a macro so we can print 
 * the file and line number
 */
#define errMessage(S, PM) \
         errPrintf(S, __FILE__, __LINE__, PM)

#ifdef __STDC__
int errSymFind(long status, char *name);
int UnixSymFind(long status, char *name, long *value);
int ModSymFind(long status, char *name, long *value);
void errSymTest(unsigned short modnum, unsigned short begErrNum, unsigned short endErrNum);
void errSymTestPrint(long errNum);
int errSymBld();
int errSymbolAdd (long errNum,char *name);
void errPrintf(long status, const char *pFileName, 
	int lineno, const char *pformat, ...);
void errSymDump();
void tstErrSymFind();

#else /*__STDC__*/

void errSymTest();
int errSymFind();
int UnixSymFind();
int ModSymFind();
void errSymTestPrint();
int errSymBld();
int errSymbolAdd();
void errPrintf();
void errSymDump();
void tstErrSymFind();
#endif /*__STDC__*/

extern int errVerbose;

#endif /*INCerrMdefh*/
----------
X-Sun-Data-Type: h-file
X-Sun-Data-Description: h-file
X-Sun-Data-Name: casdef.h
X-Sun-Content-Lines: 359

/*
 *      Author: Jeffrey O. Hill
 *              [email protected]
 *              (505) 665 1831
 *      Date:   1-95
 *
 *      Experimental Physics and Industrial Control System (EPICS)
 *
 *      Copyright 1991, the Regents of the University of California,
 *      and the University of Chicago Board of Governors.
 *
 *      This software was produced under  U.S. Government contracts:
 *      (W-7405-ENG-36) at the Los Alamos National Laboratory,
 *      and (W-31-109-ENG-38) at Argonne National Laboratory.
 *
 *      Initial development by:
 *              The Controls and Automation Group (AT-8)
 *              Ground Test Accelerator
 *              Accelerator Technology Division
 *              Los Alamos National Laboratory
 *
 *      Co-developed with
 *              The Controls and Computing Group
 *              Accelerator Systems Division
 *              Advanced Photon Source
 *              Argonne National Laboratory
 *
 *      Modification Log:
 *      -----------------
 */

/*
 * to do
 *
 * 1) how do they delete a pv out from under CA
 *
 */

#include <epicsTypes.h>	/* EPICS arch independent types */
#include <tsDefs.h>	/* EPICS time stamp */
#include <alarm.h>	/* EPICS alarm severity and alarm condition */
#include <errMdef.h>	/* EPICS error codes */

typedef int		caStatus;

typedef unsigned	caid;
typedef caid		chId;
typedef caid		pvId;

typedef struct{
	unsigned long	sec;	/* seconds */
	unsigned long	nsec;	/* nano - seconds */
}caTime;


/*
 * ===========================================================
 * provided by the application (and called by the server via 
 * a jump table)
 *
 * All of these operations need to return without delay
 * if we are to avoid hanging a single threaded server.
 * ===========================================================
 */

/*
 * return true if the named PV exists and false if it does not
 *
 * Canonical name is copied by the application into the buf pointed to by 
 * officialPVNameBuf. Copy no more than officialPVNameBufSize
 * characters and null terminate. 
 *
 * This is intended to support PV name aliases.
 */
typedef epicsBoolean pvExistTest(const char *pPVName, char *officialPVNameBuf, 
			unsigned officialPVNameBufSize);

/* 
 * The application supplied entry point pvAddrCreate() will
 * be called by the server library each time that
 * CA attaches a channel to a process varible for 
 * the first time.
 *
 * The application typically will allocate an application specific 
 * address structure with caMalloc() and return a pointer to it 
 * in *ppPVAddr. 
 */
typedef caStatus pvAddrCreate (const char *pvNameString, 
				pvId id, void **ppPVAddr);

/* 
 * The application supplied entry point pvAddrDelete() will
 * be called by the server library each time that
 * the number of CA attachments to a particular PV
 * decrements to zero. This routine provide an opportunity 
 * for the application to delete any resources allocated 
 * during pvAddrCreate(). Typically caFree() will be called
 * to free memmory allocated inside of pvAddrCreate() above.
 */
typedef caStatus pvAddrDelete (void *pPVAddr);



/* 
 * The application supplied entry point pvInterestRegister ()
 * will be called each time that the server wishes to 
 * subscripe for PV value change events via caServerPostEvents() 
 */
typedef caStatus pvInterestRegister (void *pPVAddr, unsigned select);

/* 
 * The application supplied entry point pvInterestDelete ()
 * will be called each time that the server wishes to
 * remove its subscription for PV value change events 
 * via caServerPostEvents() 
 */
typedef caStatus pvInterestDelete (void *pPVAddr);




/*
 * No changes to a PV while the lock is applied
 *
 * allows updates to a record to be postponed while
 * options are being read so that the value and options 
 * are consistent.
 */
typedef caStatus pvLock (void *pPVAddr);
typedef caStatus pvUnlock (void *pPVAddr);


/* 
 * Always called just after any write to the native 
 * address (with the lock on) 
 *
 * If this operation will not complete immediately
 * then the application is required to return
 * S_casApp_asyncCompletion and then call 
 * caServerPostPVIOCompletion ()
 * when the operation actually completes.
 * The server will allow only one asynchronous IO
 * operation at a time to be pending on a PV.
 */
typedef caStatus pvWriteAction (void *pPVAddr);

/* 
 * always called just prior to a read from the native 
 * address (with the lock on) 
 *
 * If this operation will not complete immediately
 * then the application is required to return
 * S_casApp_asyncCompletion and then call 
 * caServerPostPVIOCompletion ()
 * when the operation actually completes.
 * The server will allow only one asynchronous IO
 * operation at a time to be pending on a PV.
 */
typedef caStatus pvReadAction (void *pPVAddr);

/* 
 * allowed to change during an id's lifetime ??
 */
typedef caStatus pvNativeType (void *pPVAddr, epicsType *pType);
typedef	caStatus pvBestExternalType (void *pPVAddr, epicsType *pType);	
typedef caStatus pvNativeElementCount (void *pPVAddr, unsigned long *pCount);
typedef caStatus pvNativeAddress (void *pPVAddr, void **pPointer);
/* ring index certainly will chnage during the PV's lifespan) */
typedef caStatus pvNativeRingIndex (void *pPVAddr, unsigned long *pIndex);

/*
 * frequently change during an id's lifetime
 */
typedef caStatus pvAlarmStatus (void *pPVAddr, epicsAlarmSeverity *pSeverity,
				epicsAlarmCondition *pStatus);
typedef caStatus pvTimeStamp (void *pPVAddr, TS_STAMP *pTimeStamp);

/*
 * Will cause operational problems for existing clients coded to the
 * current interface if these change during an id's lifetime. Future 
 * client interface will provide for change notification. Perhaps
 * we should just disconnect the client if these parameters change.
 */
typedef caStatus pvUnits (void *pPVAddr, unsigned bufByteSize, 
				char *pStringBuf);
typedef caStatus pvPrecision (void *pPVAddr, unsigned *pPrecision);
typedef caStatus pvEnumStateCount (void *pPVAddr, unsigned nStatesMax,
					unsigned *nStates);
typedef caStatus pvEnumStateString (void *pPVAddr, unsigned stateNumber,
				unsigned bufByteSize, char *pStringBuf);
typedef caStatus pvGraphLimits (void *pPVAddr, double *pUpperLimit, 
			double *pLowerLimit);
typedef caStatus pvControlLimits (void *pPVAddr, double *pUpperLimit, 
			double *pLowerLimit);
typedef caStatus pvAlarmLimits (void *pPVAddr, double *pUpperAlarmLimit, 
			double *pUpperWarningLimit, double *pLowerWarningLimit, 
			double *pLowerAlarmLimit);

/* 
 * Optional per channel interface
 * 
 * Per channel state required if the application
 * implements access control
 */
typedef caStatus chAddrCreate (void *pPVAddr, chId id, void **ppChanAddr);
typedef caStatus chAddrDelete (void *pChAddr);
typedef caStatus chSetOwner (void *pChAddr, const char *pUser, const char *pHost);
#define channelInterest_AccessRights (1<<0)
typedef caStatus chInterestRegister (void *pChAddr, unsigned select);
typedef caStatus chInterestDelete (void *pChAddr);
typedef epicsBoolean chReadAccess (void *pChAddr);
typedef epicsBoolean chWriteAccess (void *pChAddr);

/*
 * If an entry point isnt supplied by the application
 * (set to NULL) then the server lib will fill in 
 * a default action
 */
typedef struct cas_application_entry_table{
	pvExistTest		*pPVExistTest;
	pvAddrCreate		*pPVAddrCreate;
	pvAddrDelete		*pPVAddrDelete;

	pvInterestRegister	*pPVInterestRegister;
	pvInterestDelete	*pPVInterestDelete;

	pvLock			*pPVLock;
	pvUnlock		*pPVUnlock;

	pvWriteAction		*pPVWriteAction;
	pvReadAction		*pPVReadAction;

	pvAlarmStatus		*pPVAlarmStatus;
	pvTimeStamp		*pPVTimeStamp;

	pvNativeType		*pPVNativeType;
	pvBestExternalType	*pPVBestExternalType;
	pvNativeElementCount	*pPVNativeElementCount;
	pvNativeAddress		*pPVNativeAddress;
	pvNativeRingIndex	*pPVNativeRingIndex;
	pvUnits			*pPVUnits;
	pvPrecision		*pPVPrecision;
	pvEnumStateCount	*pPVEnumStateCount;
	pvEnumStateString	*pPVEnumStateString;
	pvGraphLimits		*pPVGraphLimits;
	pvControlLimits		*pPVControlLimits;
	pvAlarmLimits		*pPVAlarmLimits;

	chAddrCreate		*pChAddrCreate;
	chAddrDelete		*pChAddrDelete;
	chSetOwner		*pChSetOwner;
	chInterestRegister	*pChInterestRegister;
	chInterestDelete	*pChInterestDelete;
	chReadAccess		*pChReadAccess;
	chWriteAccess		*pChWriteAccess;
}casAppEntryTable;

/*
 * ===========================================================
 * called by the application
 * ===========================================================
 */

/*
 * Context used when creating a server.
 * Set appropriate flag in the "flags"
 * field for each parameter that does
 * not default.
 */
#define casCreateCtx_pvCountEstimate	(1<<1)
#define casCreateCtx_pvMaxNameLength	(2<<1) 	/* required */

typedef struct {
	unsigned 	flags;
	unsigned	pvCountEstimate; /* estimated max PV's in this server*/
	unsigned	pvMaxNameLength; /* ma char in PV name - required */
}casCreateCtx;

void 		*caMalloc (size_t size);
void 		*caCalloc (size_t count, size_t size);
void 		caFree (void *pBlock);

/*
 * NOTE: Always force casAppEntryTable to zero prior to initializatiion
 * so that if new entries are added to the bottom of the structure 
 * existing code will specify nill entries for any new entry points
 * and therefore take the default.
 */
typedef void 		*caServerId;
caStatus 	caServerCreate (const casAppEntryTable *pTable, 
			const casCreateCtx *pCtx, caServerId *pId);
caStatus 	caServerDelete (caServerId id);
caStatus	caServerProcess (caServerId id, const caTime *pDelay);
typedef unsigned 	caServerTimerId;
caStatus	caServerAddTimeout (caServerId id, const caTime *pDelay,
			void (*pFunc)(void *pParam), void *pParam, 
			caServerTimerId *pAlarmId);
caStatus	caServerDeleteTimeout (caServerId id, caServerTimerId alarmId);

caStatus 	caServerSetDebugLevel (caServerId id, unsigned level);
caStatus	caServerShow (caServerId id, unsigned level);	

/*
 * Application calls this function if a PV's state is modified.
 */
caStatus 	caServerPostPVEvent (caServerId casid, pvId id, 
			unsigned eventSelect);

/*
 * Application calls this function when an asynchronous IO operation
 * completes.  
 */
caStatus 	caServerPostPVIOCompletion (caServerId casid, 
			pvId id, caStatus status);

/*
 * Application calls this function if a channel's state is modified.
 * For example, the access rights change for a particular client attached 
 * to a particular PV may change.
 */
caStatus	caServerPostChEvent (caServerId casid, chId id, 
			unsigned eventSelect);

/*
 * ===========================================================
 * for internal use by the server library 
 * (and potentially returned to the server application)
 * ===========================================================
 */
#define S_cas_success 0
#define S_cas_internal (M_cas| 1) /*Internal failure*/
#define S_cas_noMemory (M_cas| 2) /*Memory allocation failed*/
#define S_cas_portInUse (M_cas| 3) /*IP port already in use*/
#define S_cas_hugeRequest (M_cas | 4) /*Requested op does not fit*/
#define S_cas_sendBlocked (M_cas | 5) /*Blocked for send q space*/
#define S_cas_badElementCount (M_cas | 6) /*Bad element count*/
#define S_cas_noConvert (M_cas | 7) /*No conversion between src & dest types*/
#define S_cas_badWriteType (M_cas | 8) /*Src type inappropriate for write*/
#define S_cas_ioBlocked (M_cas | 9) /*Blocked for io completion*/
#define S_cas_partialMessage (M_cas | 10) /*Partial message*/
#define S_cas_noContext (M_cas | 11) /*Context parameter is required*/
#define S_cas_disconnect (M_cas | 12) /*Lost connection to server*/
#define S_cas_recvBlocked (M_cas | 13) /*Recv blocked*/
#define S_cas_badType (M_cas | 14) /*Bad data type*/
#define S_cas_timerDoesNotExist (M_cas | 15) /*Timer does not exist*/


/*
 * ===========================================================
 * returned by the application (to the server library)
 * ===========================================================
 */
#define S_casApp_success 0 
#define S_casApp_noMemory (M_casApp | 1) /*Memory allocation failed*/
#define S_casApp_pvNotFound (M_casApp | 2) /*PV not found*/
#define S_casApp_badPVId (M_casApp | 3) /*Unknown PV identifier*/
#define S_casApp_noSupport (M_casApp | 4) /*No application support for op*/
#define S_casApp_asyncCompletion (M_casApp | 5) /*Operation will complete asynchronously*/

----------
X-Sun-Data-Type: c-file
X-Sun-Data-Description: c-file
X-Sun-Data-Name: exampleCaServer.c
X-Sun-Content-Lines: 812

/*
 *
 * Example CA server
 *
 * This is intended to run in a single threaded Process
 */

/*
 * ANSI
 */
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

/*
 * EPICS
 */
#include <casdef.h>

#ifndef max
#define max(A,B) ((A)<(B)?(B):(A))
#endif

#ifndef min
#define min(A,B) ((A)>(B)?(B):(A))
#endif

#ifndef NELEMENTS
#	define NELEMENTS(A) (sizeof(A)/sizeof(A[0]))
#endif

#define LOCAL static

LOCAL pvExistTest	      excasPVExistTest;
LOCAL pvAddrCreate	      excasPVAddrCreate;
LOCAL pvAddrDelete	      excasPVAddrDelete;
LOCAL pvInterestRegister      excasPVInterestRegister;
LOCAL pvInterestDelete        excasPVInterestDelete;
LOCAL pvLock                  excasPVLock;
LOCAL pvUnlock                excasPVUnlock;
LOCAL pvWriteAction           excasPVWriteAction;
LOCAL pvReadAction            excasPVReadAction;
LOCAL pvAlarmStatus	      excasPVAlarmStatus;
LOCAL pvTimeStamp             excasPVTimeStamp;
LOCAL pvNativeType            excasPVNativeType;
LOCAL pvBestExternalType      excasPVBestExternalType;
LOCAL pvNativeElementCount    excasPVNativeElementCount;
LOCAL pvNativeAddress         excasPVNativeAddress;
LOCAL pvNativeRingIndex       excasPVNativeRingIndex;
LOCAL pvUnits                 excasPVUnits;
LOCAL pvPrecision             excasPVPrecision;
LOCAL pvEnumStateCount        excasPVEnumStateCount;
LOCAL pvEnumStateString	      excasPVEnumStateString;
LOCAL pvGraphLimits           excasPVGraphLimits;
LOCAL pvControlLimits         excasPVControlLimits;
LOCAL pvAlarmLimits           excasPVAlarmLimits;
LOCAL chAddrCreate	      excasChAddrCreate;
LOCAL chAddrDelete	      excasChAddrDelete;
LOCAL chSetOwner	      excasChSetOwner;
LOCAL chInterestRegister      excasChInterestRegister;
LOCAL chInterestDelete	      excasChInterestDelete;
LOCAL chReadAccess	      excasChReadAccess;
LOCAL chWriteAccess	      excasChWriteAccess;

casAppEntryTable excasAET = {
			excasPVExistTest,
                        excasPVAddrCreate,
                        excasPVAddrDelete,
                        excasPVInterestRegister,
                        excasPVInterestDelete,
                        excasPVLock,
                        excasPVUnlock,
                        excasPVWriteAction,
                        excasPVReadAction,
                        excasPVAlarmStatus,
                        excasPVTimeStamp,
                        excasPVNativeType,
			excasPVBestExternalType,
                        excasPVNativeElementCount,
                        excasPVNativeAddress,
                        excasPVNativeRingIndex,
                        excasPVUnits,
                        excasPVPrecision,
			excasPVEnumStateCount,
			excasPVEnumStateString,
                        excasPVGraphLimits,
                        excasPVControlLimits,
                        excasPVAlarmLimits,
			excasChAddrCreate,
			excasChAddrDelete,
			excasChSetOwner,
			excasChInterestRegister,
			excasChInterestDelete,
			excasChReadAccess,
			excasChWriteAccess
};

LOCAL void scanPV (void *pParam);
LOCAL void asyncWriteDone (void *pParam);
LOCAL void asyncReadDone (void *pParam);

typedef enum {excasIoSync, excasIoAsync} excasIoType;

typedef struct {
	ELLNODE		node;
	caTime		scanRate;
	char		*pName;
	epicsFloat32	value;
	epicsFloat32	hopr;
	epicsFloat32	lopr;
	excasIoType	ioType;
	caServerTimerId	scanTimerId;
	caServerTimerId	asyncIoTimerId;
	epicsBoolean	scanPending;
	epicsBoolean	ioPending;
	epicsBoolean	interest;
	pvId		id;
}excasPV;

typedef struct{
	excasPV		*pPV;
	chId		id;
}excasCh;

LOCAL caServerId	excas;
LOCAL excasPV		pvList[] = { 
	{{0,0}, {1,0}, "jane", 8.0, 10.0, -10.0, excasIoAsync},
	{{0,0}, {1,0}, "fred", 0.8, 1.0, -1.0, excasIoSync}
	};

#define myPI    3.14159265358979323846


/*
 * main ()
 */
int main (int argc, char **argv)
{
	caTime		delay;
	casCreateCtx	ctx;
	int		status;

	ctx.flags = 	casCreateCtx_pvCountEstimate |
			casCreateCtx_pvMaxNameLength;
	ctx.pvCountEstimate = 1;
	ctx.pvMaxNameLength = 32;

	status = caServerCreate (&excasAET, &ctx, &excas);
	if (status != S_casApp_success) {
		errMessage (status, "Unable to start the server");
		return status;
	}

	if (argc > 1) {
		status = caServerSetDebugLevel (excas, 10);
		assert (status == S_casApp_success);
	}

	while (epicsTrue) {
		delay.sec = 1;
		delay.nsec = 0;

		status = caServerProcess (excas, &delay);
		if (status) {
			errMessage (status, "Server processing failed");
			return status;	
		}

	}
}


/*
 * scanPV ()
 */
LOCAL void scanPV (void *pParam)
{
	excasPV		*pPV = pParam; 
	double		radians;
	caStatus	status;

	pPV->scanPending = epicsFalse;

	radians = (rand () * 2.0 * myPI)/RAND_MAX;
	pPV->value += sin (radians) / 10.0;
	pPV->value = min (pPV->value, pPV->hopr);
	pPV->value = max (pPV->value, pPV->lopr);

	if (pPV->interest==epicsTrue) {
		status = caServerPostPVEvent (excas, pPV->id, ~0);
		if (status) {
			errMessage (status, "Server event post failed");
		}

		status = caServerAddTimeout (excas, &pPV->scanRate, 
				scanPV, pParam, &pPV->scanTimerId);
		if (status) {
			errPrintf (status, __FILE__, __LINE__,
				"Scan init for %s failed\n", pPV->pName);
		}
		else {
			pPV->scanPending = epicsTrue;
		}
	}
}


/*
 * excasPVExistTest()
 */
LOCAL epicsBoolean excasPVExistTest(
const char 	*pvName, 
char 		*pOfficialNameBuf,
unsigned	bufSize)
{
	caStatus	status;
	unsigned	size;
	epicsBoolean	match = epicsFalse;
	excasPV		*pPV;
	excasPV		*pPVAfter = &pvList[NELEMENTS(pvList)];

	size = strlen(pvName);
	if (size>bufSize-1) {
		return epicsFalse;
	}
	
	pPV = pvList;
	for (pPV = pvList; pPV < pPVAfter; pPV++) {
		if (strcmp (pvName, pPV->pName) == '\0') {
			match = epicsTrue;
			break;
		}
	}

	if (match==epicsTrue) {
		/*
		 * there are no name aliases in this
		 * server's PV name syntax
		 */
		strncpy (pOfficialNameBuf, pvName, bufSize);
	}

	return match;
}


/*
 * excasPVAddrCreate()
 */
LOCAL caStatus excasPVAddrCreate(
const char 	*pvNameString, 
chId		id,
void		**ppPVAddr)
{
	caStatus	status;
	epicsBoolean	match = epicsFalse;
	excasPV		*pPV; /* per PV */
	excasPV		*pNewPV; /* per PV */
	excasPV		*pPVAfter = &pvList[NELEMENTS(pvList)];

	pPV = pvList;
	for (pPV = pvList; pPV < pPVAfter; pPV++) {
		if (strcmp (pvNameString, pPV->pName) == '\0') {
			match = epicsTrue;
			break;
		}
	}

	if (match == epicsFalse) {
		return S_casApp_pvNotFound;
	}

	pNewPV = caMalloc (sizeof (*pNewPV));
	if (!pNewPV) {
		return S_casApp_noMemory;
	}

	*pNewPV = *pPV;
	pNewPV->id = id;
	*ppPVAddr = pNewPV;

	return S_casApp_success;
}




/*
 * excasPVAddrDelete()
 */
LOCAL caStatus excasPVAddrDelete(void *pPVAddr)
{
	caStatus	status;
	excasPV		*pPV = pPVAddr;

	if (pPV->ioPending == epicsTrue) {
		status = caServerDeleteTimeout (excas, pPV->asyncIoTimerId);
		if (status) {
			errPrintf (status, __FILE__, __LINE__,
				"Async IO delete for %s failed\n", 
				pPV->pName);
		}
	}

	if (pPV->scanPending == epicsTrue) {
		status = caServerDeleteTimeout (excas, pPV->scanTimerId);
		if (status) {
			errPrintf (status, __FILE__, __LINE__,
				"Scan delete for %s failed\n", 
				pPV->pName);
		}
	}

	caFree (pPV);

	return S_casApp_success;
}


/*
 * excasPVInterestRegister ()
 */
LOCAL caStatus excasPVInterestRegister (void *pPVAddr, unsigned select)
{
	caStatus	status;
	excasPV		*pPV = pPVAddr;

	if (!pPV->scanPending) {
		status = caServerAddTimeout (excas, &pPV->scanRate, 
				scanPV, pPV, &pPV->scanTimerId);
		if (status) {
			errPrintf (status, __FILE__, __LINE__,
				"Scan init for %s failed\n", pPV->pName);
		}
		else {
			pPV->scanPending = epicsTrue;
		}
	}

	pPV->interest = epicsTrue;

	return S_casApp_success;
}


/*
 * excasPVInterestDelete ()
 */
LOCAL caStatus excasPVInterestDelete (void *pPVAddr)
{
	caStatus	status;
	excasPV		*pPV = pPVAddr;

	if (pPV->scanPending==epicsTrue) {
		status = caServerDeleteTimeout (excas, pPV->scanTimerId);
		if (status) {
			errPrintf (status, __FILE__, __LINE__,
				"Scan delete for %s failed\n", 
				pPV->pName);
		}
		pPV->scanPending = epicsFalse;
	}
	pPV->interest = epicsFalse;

	return S_casApp_success;
}


/*
 * excasPVLock ()
 */
LOCAL caStatus excasPVLock (void *pPVAddr)
{
	excasPV         *pPV = pPVAddr;

	return S_casApp_success;
}


/*
 * excasPVUnlock ()
 */
LOCAL caStatus excasPVUnlock (void *pPVAddr)
{
	excasPV         *pPV = pPVAddr;

	return S_casApp_success;
}


/*
 * excasPVWriteAction ()
 */
LOCAL caStatus excasPVWriteAction (void *pPVAddr)
{
	excasPV        	*pPV = pPVAddr;
        long    	status;

	if (pPV->ioType == excasIoAsync) {
		caTime		asyncDelay = {1,0};

		status = caServerAddTimeout (excas, &asyncDelay, 
					asyncWriteDone, pPVAddr,
					&pPV->asyncIoTimerId);
		if (status) {
			errPrintf (
				status, 
				__FILE__,
				__LINE__,
				"Async IO init for %s failed\n",
				pPV->pName);
			return status;
		}
		else {
			pPV->ioPending = epicsTrue;
		}
		return S_casApp_asyncCompletion;
	}
	else if (pPV->interest==epicsTrue) {
		status = caServerPostPVEvent (excas, pPV->id, ~0);
		if (status) {
			errMessage (status, "Server event post failed");
		}
	}

        return status;
}


/*
 * asyncWriteDone ()
 */
LOCAL void asyncWriteDone (void *pParam)
{
	excasPV         *pPV = pParam;
	caStatus	status;

	pPV->ioPending = epicsFalse;

	status = caServerPostPVIOCompletion (
			excas, pPV->id, S_casApp_success);
	if (status) { 
		errMessage (status, "Server io done post failed");
	}
	if (pPV->interest==epicsTrue) {
		status = caServerPostPVEvent (excas, pPV->id, ~0);
		if (status) { 
			errMessage (status, 
				"Server io done event post failed");
		}
	}
}


/*
 * excasPVReadAction ()
 */
LOCAL caStatus excasPVReadAction (void *pPVAddr)
{
	excasPV         	*pPV = pPVAddr;
	caStatus	status;

	if (pPV->ioType == excasIoAsync) {
		caTime		asyncDelay = {1,0};

		status = caServerAddTimeout (excas, &asyncDelay, 
				asyncReadDone, pPVAddr, 
				&pPV->asyncIoTimerId);
		if (status) {
			errPrintf (
				status, 
				__FILE__,
				__LINE__,
				"Async Read IO init for %s failed\n",
				pPV->pName);
			return status;
		}
		else {
			pPV->ioPending = epicsTrue;
		}
		return S_casApp_asyncCompletion;
	}

	return S_casApp_success;
}


/*
 * asyncReadDone ()
 */
LOCAL void asyncReadDone (void *pParam)
{
	excasPV         *pPV = pParam;
	caStatus	status;

	pPV->ioPending = epicsFalse;

	status = caServerPostPVIOCompletion (
			excas, pPV->id, S_casApp_success);
	if (status) { 
		errMessage (status, "Server io done post failed");
	}
	if (pPV->interest==epicsTrue) {
		status = caServerPostPVEvent (excas, pPV->id, ~0);
		if (status) { 
			errMessage (status, 
				"Server io done event post failed");
		}
	}
}


/*
 * excasPVAlarmStatus ()
 */
LOCAL caStatus excasPVAlarmStatus (void *pPVAddr, 
	epicsAlarmSeverity *pSeverity, epicsAlarmCondition *pCondition)
{
	excasPV *pPV = pPVAddr;

	*pSeverity = epicsSevNone;
	*pCondition = epicsAlarmRead; /* dont care */

	return S_casApp_success;
}


/*
 * excasPVTimeStamp ()
 */
LOCAL caStatus excasPVTimeStamp (void *pPVAddr, TS_STAMP *pTimeStamp)
{
	long	tsStatus;
	excasPV *pPV = pPVAddr;

	/*
	 * tsLocalTime () does not return zero on success
	 */
	tsStatus = tsLocalTime (pTimeStamp);
	if (tsStatus == S_ts_OK) {
		return S_casApp_success;
	}
	else {
		return tsStatus;
	}
}


/*
 * excasPVNativeType ()
 */
LOCAL caStatus excasPVNativeType (void *pPVAddr, epicsType *pType)
{
        excasPV *pPV = pPVAddr;

	*pType = epicsFloat32T;

	return S_casApp_success;
}


/*
 * excasPVBestExternalType()
 */
LOCAL caStatus excasPVBestExternalType (void *pPVAddr, epicsType *pType)
{
        excasPV *pPV = pPVAddr;

	*pType = epicsFloat32T;

	return S_casApp_success;
}


/*
 * excasPVNativeElementCount()
 */
LOCAL caStatus excasPVNativeElementCount (void *pPVAddr, unsigned long *pCount)
{
        excasPV *pPV = pPVAddr;

	*pCount = 1;

	return S_casApp_success;
}


/*
 * excasPVNativeAddress()
 */
LOCAL caStatus excasPVNativeAddress (void *pPVAddr, void **pPointer)
{
	excasPV *pPV = pPVAddr;

	*pPointer = &pPV->value;

	return S_casApp_success;
}


/*
 * excasPVNativeRingIndex()
 */
LOCAL caStatus excasPVNativeRingIndex (void *pPVAddr, unsigned long *pIndex)
{
	excasPV 	*pPV = pPVAddr;

	*pIndex = 0;

	return S_casApp_success;
}


/*
 * excasPVUnits()
 */
LOCAL caStatus excasPVUnits (void *pPVAddr, unsigned bufByteSize, 
		char *pStringBuf)
{
	excasPV 		*pPV = pPVAddr;
	unsigned	newsize = bufByteSize-1;

	strncpy (pStringBuf, "@#$%", newsize);
	pStringBuf[newsize] = '\0';	

	return S_casApp_success;
}


/*
 * excasPVPrecision()
 */
LOCAL caStatus excasPVPrecision (void *pPVAddr, unsigned *pPrecision)
{
	excasPV 		*pPV = pPVAddr;
	
	*pPrecision = 4U;

	return S_casApp_success;
}



/*
 * excasPVEnumStateCount ()
 */
LOCAL caStatus excasPVEnumStateCount (void *pPVAddr, 
		unsigned nStatesMax, unsigned *nStates)
{
        excasPV                 *pPV = pPVAddr;

	*nStates = 0;
	return S_casApp_success;
}


/*
 * excasPVEnumStateString ()
 */
LOCAL caStatus excasPVEnumStateString (void *pPVAddr, unsigned stateNumber, 
			unsigned bufByteSize, char *pStringBuf)
{
        excasPV                 *pPV = pPVAddr;

	return S_casApp_noSupport;
}


/*
 * excasPVGraphLimits()
 */
LOCAL caStatus excasPVGraphLimits (void *pPVAddr, double *pUpperLimit, 
		double *pLowerLimit)
{
	excasPV 		*pPV = pPVAddr;
	
	*pUpperLimit = pPV->hopr;
	*pLowerLimit = pPV->lopr;

	return S_casApp_success;
}


/*
 * excasPVControlLimits()
 */
LOCAL caStatus excasPVControlLimits (
void 	*pPVAddr, 
double 	*pUpperLimit, 
double 	*pLowerLimit)
{
        excasPV                 *pPV = pPVAddr;

	*pUpperLimit = pPV->hopr;
	*pLowerLimit = pPV->lopr;

	return S_casApp_success;
}


/*
 * excasPVAlarmLimits()
 */
LOCAL caStatus excasPVAlarmLimits (
void *pPVAddr, 
double *pUpperAlarmLimit, 
double *pUpperWarningLimit, 
double *pLowerWarningLimit,
double *pLowerAlarmLimit)
{
        excasPV		*pPV = pPVAddr;
	epicsFloat32	diff;

	diff = pPV->hopr-pPV->lopr;
        *pUpperAlarmLimit = diff * 0.8 + pPV->lopr;
        *pUpperWarningLimit = diff * 0.7 + pPV->lopr;
	*pLowerWarningLimit = diff * 0.3 + pPV->lopr;
	*pLowerAlarmLimit = diff * 0.2 + pPV->lopr;

        return S_casApp_success;
}




/*
 * excasChAddrCreate ()
 */
LOCAL caStatus excasChAddrCreate (void *pPVAddr, chId id, void **ppChanAddr)
{
	excasCh 	*pCh;

	pCh = caCalloc(sizeof(*pCh), 1);	
	if(!pCh){
		return S_casApp_noMemory;
	}

	pCh->id = id;
	pCh->pPV = pPVAddr;
	*ppChanAddr = pCh;

	return S_casApp_success;
}


/*
 * excasChAddrDelete ()
 */
LOCAL caStatus excasChAddrDelete (void *pChAddr)
{
	excasCh *pCh = pChAddr;
	int	status;

	caFree(pCh);

	return S_casApp_success;
}


/*
 * excasChSetOwner ()
 */
LOCAL caStatus excasChSetOwner (void *pChAddr, const char *pUser, 
		const char *pHost)
{
	return S_casApp_success;
}


/*
 * excasChInterestRegister ()
 */
LOCAL caStatus excasChInterestRegister (void *pPVAddr, unsigned select)
{
	return S_casApp_success;
}


/*
 * excasChInterestDelete()
 */
LOCAL caStatus excasChInterestDelete (void *pPVAddr)
{
	return S_casApp_success;
}


/*
 * excasChReadAccess ()
 */
LOCAL epicsBoolean excasChReadAccess (void *pChAddr)
{
	excasCh *pCh = pChAddr;

	return epicsTrue;
}


/*
 * excasChWriteAccess ()
 */
LOCAL epicsBoolean excasChWriteAccess (void *pChAddr)
{
	excasCh *pCh = pChAddr;

	return epicsTrue;
}



Navigate by Date:
Prev: Re: Anyone using fast ethernet in their IOCs? Mark Rivers
Next: Re[4]: Portable CA Server Rick McGonegal
Index: 1994  <19951996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
Navigate by Thread:
Prev: Re: Anyone using fast ethernet in their IOCs? Mark Rivers
Next: Re[4]: Portable CA Server Rick McGonegal
Index: 1994  <19951996  1997  1998  1999  2000  2001  2002  2003  2004  2005  2006  2007  2008  2009  2010  2011  2012  2013  2014  2015  2016  2017  2018  2019  2020  2021  2022  2023  2024 
ANJ, 10 Aug 2010 Valid HTML 4.01! · Home · News · About · Base · Modules · Extensions · Distributions · Download ·
· Search · EPICS V4 · IRMIS · Talk · Bugs · Documents · Links · Licensing ·