Merge changes from 3.15 branch into 7.0

This commit is contained in:
Andrew Johnson
2020-04-15 21:39:54 -05:00
57 changed files with 4118 additions and 1470 deletions

View File

@@ -42,14 +42,18 @@ environment:
matrix:
- TOOLCHAIN: mingw
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
TOOLCHAIN: 2019
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
TOOLCHAIN: 2017
- TOOLCHAIN: 2019
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
- TOOLCHAIN: 2017
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
- TOOLCHAIN: 14.0
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
- TOOLCHAIN: 12.0
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
- TOOLCHAIN: 11.0
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
- TOOLCHAIN: 10.0
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
# Platform: architecture
platform:
@@ -62,19 +66,21 @@ matrix:
# VS Express installs don't have the 64 bit compiler
- platform: x64
TOOLCHAIN: 10.0
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
# Exclude to reduce total job runtime
# skip 64-bit for older and 32-bit for newer
- platform: x64
TOOLCHAIN: 11.0
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
- platform: x86
TOOLCHAIN: mingw
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
- platform: x86
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
TOOLCHAIN: 2019
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
- platform: x86
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
TOOLCHAIN: 2017
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
#---------------------------------#

View File

@@ -30,7 +30,7 @@ ARCH_DEP_LDFLAGS += -m32
# Compiler does not define __unix __unix__ unix
# Override for -DUNIX from CONFIG.Common.UnixCommon
OP_SYS_CPPFLAGS = -D_MINGW -Wno-format
OP_SYS_CPPFLAGS = -D_MINGW -D__USE_MINGW_ANSI_STDIO
EXE = .exe
RES = .coff

View File

@@ -36,7 +36,7 @@ and can be adjusted locally if necessary.
### caRepeater /dev/null
On *NIX targets caRepeater will now partially daemonize by redirecting
On \*NIX targets caRepeater will now partially daemonize by redirecting
stdin/out/err to /dev/null. This prevents caRepeater from inheriting
the stdin/out of a process, like caget, which has spawned it in the
background. This has been known to cause problems in some cases when
@@ -195,7 +195,7 @@ set to their default values.
void startitup(void) {
epicsThreadOpts opts = EPICS_THREAD_OPTS_INIT;
epicsThreadId tid;
opts.priority = epicsThreadPriorityMedium;
tid = epicsThreadCreateOpt("my thread", &threadMain, NULL, &opts);
}
@@ -662,14 +662,14 @@ number instead, like this:
```
#include <epicsVersion.h>
#ifndef VERSION_INT
# define VERSION_INT(V,R,M,P) ( ((V)<<24) | ((R)<<16) | ((M)<<8) | (P))
#endif
#ifndef EPICS_VERSION_INT
# define EPICS_VERSION_INT VERSION_INT(EPICS_VERSION, EPICS_REVISION, EPICS_MODIFICATION, EPICS_PATCH_LEVEL)
#endif
#if EPICS_VERSION_INT >= VERSION_INT(3,16,1,0)
/* Code where Base has INT64 support */
#else
@@ -995,7 +995,7 @@ excerpts from a database file:
record(ai, math:pi) {
field(INP, {const: 3.14159265358979}) # Correct
field(SIOL, "{const: 3.142857}") # Wrong
info(autosave, { # White-space and comments are allowed
fields:[DESC, SIMM],
pass0:[VAL]
@@ -1143,7 +1143,7 @@ this:
```
#include "epicsTime.h"
#ifndef M_time
/* S_time_... status values were not provided before Base 3.16 */
#define S_time_unsynchronized epicsTimeERROR
@@ -1168,9 +1168,49 @@ Added a new macro `callbackGetPriority(prio, callback)` to the callback.h
header and removed the need for dbScan.c to reach into the internals of its
`CALLBACK` objects.
## Changes from the 3.15 branch since 3.15.7
> None.
### epicsThread: Main thread defaults to allow blocking I/O
VxWorks IOCs (and potentially RTEMS IOCs running GeSys) have had problems with
garbled error messages from dbStaticLib routines for some time &mdash; messages
printed before `iocInit` were being queued through the errlog thread instead of
being output immediately. This has been fixed by initializing the main thread
with its `OkToBlock` flag set instead of cleared. IOCs running on other
operating systems that use iocsh to execute the startup script previously had
that set anyway in iocsh so were not affected, but this change might cause other
programs that don't use iocsh to change their behavior slightly if they use
`errlogPrintf()`, `epicsPrintf()` or `errPrintf()`.
### catools: Handle data type changes in camonitor
The camonitor program didn't properly cope if subscribed to a channel whose data
type changed when its IOC was rebooted without restarting the camonitor program.
This has now been fixed.
### More Record Reference Documentation
The remaining record types have had their reference pages moved from the Wiki,
and some new reference pages have been written to cover the analog array and
long string input and output record types plus the printf recor type, none of
which were previously documented. The wiki reference pages covering the fields
common to all, input, and output record types have also been added, thanks to
Rolf Keitel. The POD conversion scripts have also been improved and they now
properly support linking to subsections in a different document, although the
POD changes to add the cross-links that appeared in the original wiki pages
still needs to be done in most cases.
### Fix build issues with newer MinGW versions
The `clock_gettime()` routine is no longer used under MinGW since newer versions
don't provide it any more.
### Fix race for port in RSRV when multiple IOCs start simultaneously
If multiple IOCs were started at the same time, by systemd say, they could race
to obtain the Channel Access TCP port number 5064. This issue has been fixed.
## Changes made between 3.15.6 and 3.15.7
@@ -1887,4 +1927,3 @@ Simpler versions of the `epicsTime_gmtime()` and `epicsTime_localtime()`
routines have been included in the Windows implementations, and a new test
program added. The original versions do not report DST status properly. Fixes
[Launchpad bug 1528284](https://bugs.launchpad.net/bugs/1528284).

View File

@@ -1,9 +1,17 @@
# Record Reference Documentation
The following documentation for the record types and menus include with Base was converted from the old EPICS Wiki pages and updated. This list does not include all of the available record types as some have not been documented yet.
The following documentation for the record types and menus include with Base was
converted from the old EPICS Wiki pages and updated. This list only includes the
record types supplied with Base.
* [Fields Common to All Record Types](dbCommonRecord.html)
* [Fields Common to Input Record Types](dbCommonInputs.html)
* [Fields Common to Output Record Types](dbCommonOutputs.html)
## Record Types
* [Analog Array Input Record (aai)](aaiRecord.html)
* [Analog Array Output Record (aao)](aaoRecord.html)
* [Analog Input Record (ai)](aiRecord.html)
* [Analog Output Record (ao)](aoRecord.html)
* [Array Subroutine Record (aSub)](aSubRecord.html)
@@ -15,15 +23,19 @@ The following documentation for the record types and menus include with Base was
* [Data Fanout Record (dfanout)](dfanoutRecord.html)
* [Event Record (event)](eventRecord.html)
* [Fanout Record (fanout)](fanoutRecord.html)
* [Histogram Record (histogram)](histogramRecord.html)
* [64bit Integer Input Record (int64in)](int64inRecord.html)
* [64bit Integer Output Record (int64out)](int64outRecord.html)
* [Long Input Record (longin)](longinRecord.html)
* [Long Output Record (longout)](longoutRecord.html)
* [Long String Input Record (lsi)](lsiRecord.html)
* [Long String Output Record (lso)](lsoRecord.html)
* [Multi-Bit Binary Input Direct Record (mbbiDirect)](mbbiDirectRecord.html)
* [Multi-Bit Binary Input Record (mbbi)](mbbiRecord.html)
* [Multi-Bit Binary Output Direct Record (mbboDirect)](mbboDirectRecord.html)
* [Multi-Bit Binary Output Record (mbbo)](mbboRecord.html)
* [Permissive Record (permissive)](permissiveRecord.html)
* [Printf Record (prinf)](printfRecord.html)
* [Select Record (sel)](selRecord.html)
* [Sequence Record (seq)](seqRecord.html)
* [State Record (state)](stateRecord.html)
@@ -47,4 +59,10 @@ The following documentation for the record types and menus include with Base was
## Corrections and Updates
Corrections to these documents can be submitted as patch files to the EPICS core developers, or as merge requests or pull requests to the 7.0 branch of epics-base. The document sources can be found in the `modules/database/src/std/rec` and `modules/database/src/ioc/db` directories in files with extension `.dbd.pod`. The documentation format is an extended version of Perl POD, run `perldoc pod` for details.
Corrections to these documents can be submitted as patch files to the EPICS core
developers, or as merge requests or pull requests to the 7.0 branch of Base.
The document sources can be found in the `modules/database/src/std/rec` and
`modules/database/src/ioc/db` directories in files with extension `.dbd.pod`.
The documentation source format is a combination of the EPICS DBD file format
with an extended version of Perl's POD (plain old documentation); run `perldoc
pod` for details of POD.

View File

@@ -138,7 +138,14 @@ static void connection_handler ( struct connection_handler_args args )
pv *ppv = ( pv * ) ca_puser ( args.chid );
if ( args.op == CA_OP_CONN_UP ) {
nConn++;
if (!ppv->onceConnected) {
if (ppv->onceConnected && ppv->dbfType != ca_field_type(ppv->chid)) {
/* Data type has changed. Rebuild connection with new type. */
ca_clear_subscription(ppv->evid);
ppv->evid = NULL;
}
if (!ppv->evid) {
ppv->onceConnected = 1;
/* Set up pv structure */
/* ------------------- */
@@ -169,7 +176,7 @@ static void connection_handler ( struct connection_handler_args args )
eventMask,
event_handler,
(void*)ppv,
NULL);
&ppv->evid);
}
}
else if ( args.op == CA_OP_CONN_DOWN ) {

View File

@@ -78,6 +78,7 @@ typedef struct
epicsTimeStamp tsPreviousS;
char firstStampPrinted;
char onceConnected;
evid evid;
} pv;

View File

@@ -4,7 +4,7 @@
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
# in file LICENSE that is included with this distribution.
#*************************************************************************
# This is a Makefile fragment, see src/ioc/Makefile.
@@ -62,6 +62,9 @@ DBDINC += dbCommon
dbMenusPod = $(notdir $(wildcard ../db/menu*.dbd.pod))
HTMLS += $(patsubst %.dbd.pod,%.html,$(dbMenusPod))
HTMLS += dbCommonRecord.html
HTMLS += dbCommonInput.html
HTMLS += dbCommonOutput.html
dbCore_SRCS += dbLock.c
dbCore_SRCS += dbAccess.c
@@ -96,4 +99,3 @@ dbCore_SRCS += chfPlugin.c
dbCore_SRCS += dbState.c
dbCore_SRCS += dbUnitTest.c
dbCore_SRCS += dbServer.c

View File

@@ -6,21 +6,25 @@
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
# in file LICENSE that is included with this distribution.
#*************************************************************************
# This is a Makefile fragment, see src/ioc/Makefile.
dbCommon.h$(DEP): $(IOCDIR)/db/dbCommonRecord.dbd $(IOCDIR)/db/RULES
@$(RM) $@
@$(DBTORECORDTYPEH) -D -I ../db -o $(COMMONDEP_TARGET) $< > $@
THESE_RULES := $(IOCDIR)/db/RULES
$(COMMON_DIR)/dbCommon.h: $(IOCDIR)/db/dbCommonRecord.dbd $(IOCDIR)/db/RULES
dbCommon.h$(DEP): $(COMMON_DIR)/dbCommonRecord.dbd $(THESE_RULES)
@$(RM) $@
@$(DBTORECORDTYPEH) -D -I ../db -I $(COMMON_DIR) -o $(COMMONDEP_TARGET) $< > $@
$(COMMON_DIR)/dbCommonRecord.html: ../db/dbCommon.dbd.pod
$(COMMON_DIR)/dbCommon.h: $(COMMON_DIR)/dbCommonRecord.dbd $(THESE_RULES)
@$(RM) $(notdir $@)
$(DBTORECORDTYPEH) -I ../db -o $(notdir $@) $<
$(DBTORECORDTYPEH) -I ../db -I $(COMMON_DIR) -o $(notdir $@) $<
@$(MV) $(notdir $@) $@
$(COMMON_DIR)/menuGlobal.dbd: $(IOCDIR)/db/Makefile $(IOCDIR)/db/RULES
$(COMMON_DIR)/menuGlobal.dbd: $(IOCDIR)/db/Makefile $(THESE_RULES)
# This is a target-specific variable
$(COMMON_DIR)/menuGlobal.dbd: DBDCAT_COMMAND = \

View File

@@ -776,8 +776,19 @@ int dbLoadRecords(const char* file, const char* subs)
return -1;
}
status = dbReadDatabase(&pdbbase, file, 0, subs);
if (!status && dbLoadRecordsHook)
dbLoadRecordsHook(file, subs);
switch(status)
{
case 0:
if(dbLoadRecordsHook)
dbLoadRecordsHook(file, subs);
break;
case -2:
errlogPrintf("dbLoadRecords: failed to load '%s'\n"
" Records cannot be loaded after iocInit!\n", file);
break;
default:
errlogPrintf("dbLoadRecords: failed to load '%s'\n", file);
}
return status;
}
@@ -943,6 +954,11 @@ long dbGet(DBADDR *paddr, short dbrType,
} else {
DBADDR localAddr = *paddr; /* Structure copy */
if (pfl->no_elements < 1) {
status = S_db_badField;
goto done;
}
localAddr.field_type = pfl->field_type;
localAddr.field_size = pfl->field_size;
localAddr.no_elements = pfl->no_elements;

View File

@@ -1,268 +0,0 @@
#*************************************************************************
# Copyright (c) 2007 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
%#include "epicsTypes.h"
%#include "link.h"
field(NAME,DBF_STRING) {
prompt("Record Name")
special(SPC_NOMOD)
size(61)
}
field(DESC,DBF_STRING) {
prompt("Descriptor")
promptgroup("10 - Common")
size(41)
}
field(ASG,DBF_STRING) {
prompt("Access Security Group")
promptgroup("10 - Common")
special(SPC_AS)
size(29)
}
field(SCAN,DBF_MENU) {
prompt("Scan Mechanism")
promptgroup("20 - Scan")
special(SPC_SCAN)
interest(1)
menu(menuScan)
}
field(PINI,DBF_MENU) {
prompt("Process at iocInit")
promptgroup("20 - Scan")
interest(1)
menu(menuPini)
}
field(PHAS,DBF_SHORT) {
prompt("Scan Phase")
promptgroup("20 - Scan")
special(SPC_SCAN)
interest(1)
}
field(EVNT,DBF_STRING) {
prompt("Event Name")
promptgroup("20 - Scan")
special(SPC_SCAN)
size(40)
interest(1)
}
field(TSE,DBF_SHORT) {
prompt("Time Stamp Event")
promptgroup("20 - Scan")
interest(1)
}
field(TSEL,DBF_INLINK) {
prompt("Time Stamp Link")
promptgroup("20 - Scan")
interest(1)
}
field(DTYP,DBF_DEVICE) {
prompt("Device Type")
promptgroup("10 - Common")
interest(1)
}
field(DISV,DBF_SHORT) {
prompt("Disable Value")
promptgroup("20 - Scan")
initial("1")
}
field(DISA,DBF_SHORT) {
prompt("Disable")
}
field(SDIS,DBF_INLINK) {
prompt("Scanning Disable")
promptgroup("20 - Scan")
interest(1)
}
%#include "epicsMutex.h"
field(MLOK,DBF_NOACCESS) {
prompt("Monitor lock")
special(SPC_NOMOD)
interest(4)
extra("epicsMutexId mlok")
}
%#include "ellLib.h"
field(MLIS,DBF_NOACCESS) {
prompt("Monitor List")
special(SPC_NOMOD)
interest(4)
extra("ELLLIST mlis")
}
field(BKLNK,DBF_NOACCESS) {
prompt("Backwards link tracking")
special(SPC_NOMOD)
interest(4)
extra("ELLLIST bklnk")
}
field(DISP,DBF_UCHAR) {
prompt("Disable putField")
}
field(PROC,DBF_UCHAR) {
prompt("Force Processing")
pp(TRUE)
interest(3)
}
field(STAT,DBF_MENU) {
prompt("Alarm Status")
special(SPC_NOMOD)
menu(menuAlarmStat)
initial("UDF")
}
field(SEVR,DBF_MENU) {
prompt("Alarm Severity")
special(SPC_NOMOD)
menu(menuAlarmSevr)
}
field(NSTA,DBF_MENU) {
prompt("New Alarm Status")
special(SPC_NOMOD)
interest(2)
menu(menuAlarmStat)
}
field(NSEV,DBF_MENU) {
prompt("New Alarm Severity")
special(SPC_NOMOD)
interest(2)
menu(menuAlarmSevr)
}
field(ACKS,DBF_MENU) {
prompt("Alarm Ack Severity")
special(SPC_NOMOD)
interest(2)
menu(menuAlarmSevr)
}
field(ACKT,DBF_MENU) {
prompt("Alarm Ack Transient")
promptgroup("70 - Alarm")
special(SPC_NOMOD)
interest(2)
menu(menuYesNo)
initial("YES")
}
field(DISS,DBF_MENU) {
prompt("Disable Alarm Sevrty")
promptgroup("70 - Alarm")
interest(1)
menu(menuAlarmSevr)
}
field(LCNT,DBF_UCHAR) {
prompt("Lock Count")
special(SPC_NOMOD)
interest(2)
}
field(PACT,DBF_UCHAR) {
prompt("Record active")
special(SPC_NOMOD)
interest(1)
}
field(PUTF,DBF_UCHAR) {
prompt("dbPutField process")
special(SPC_NOMOD)
interest(1)
}
field(RPRO,DBF_UCHAR) {
prompt("Reprocess ")
special(SPC_NOMOD)
interest(1)
}
field(ASP,DBF_NOACCESS) {
prompt("Access Security Pvt")
special(SPC_NOMOD)
interest(4)
extra("struct asgMember *asp")
}
field(PPN,DBF_NOACCESS) {
prompt("pprocessNotify")
special(SPC_NOMOD)
interest(4)
extra("struct processNotify *ppn")
}
field(PPNR,DBF_NOACCESS) {
prompt("pprocessNotifyRecord")
special(SPC_NOMOD)
interest(4)
extra("struct processNotifyRecord *ppnr")
}
field(SPVT,DBF_NOACCESS) {
prompt("Scan Private")
special(SPC_NOMOD)
interest(4)
extra("struct scan_element *spvt")
}
field(RSET,DBF_NOACCESS) {
prompt("Address of RSET")
special(SPC_NOMOD)
interest(4)
extra("struct typed_rset *rset")
}
%#include "devSup.h"
field(DSET,DBF_NOACCESS) {
prompt("DSET address")
special(SPC_NOMOD)
interest(4)
extra("unambiguous_dset *dset")
}
field(DPVT,DBF_NOACCESS) {
prompt("Device Private")
special(SPC_NOMOD)
interest(4)
extra("void *dpvt")
}
field(RDES,DBF_NOACCESS) {
prompt("Address of dbRecordType")
special(SPC_NOMOD)
interest(4)
extra("struct dbRecordType *rdes")
}
field(LSET,DBF_NOACCESS) {
prompt("Lock Set")
special(SPC_NOMOD)
interest(4)
extra("struct lockRecord *lset")
}
field(PRIO,DBF_MENU) {
prompt("Scheduling Priority")
promptgroup("20 - Scan")
special(SPC_SCAN)
interest(1)
menu(menuPriority)
}
field(TPRO,DBF_UCHAR) {
prompt("Trace Processing")
}
field(BKPT,DBF_NOACCESS) {
prompt("Break Point")
special(SPC_NOMOD)
interest(1)
extra("char bkpt")
}
field(UDF,DBF_UCHAR) {
prompt("Undefined")
promptgroup("10 - Common")
pp(TRUE)
interest(1)
initial("1")
}
field(UDFS,DBF_MENU) {
prompt("Undefined Alarm Sevrty")
promptgroup("70 - Alarm")
interest(1)
menu(menuAlarmSevr)
initial("INVALID")
}
%#include "epicsTime.h"
field(TIME,DBF_NOACCESS) {
prompt("Time")
special(SPC_NOMOD)
interest(2)
extra("epicsTimeStamp time")
}
field(FLNK,DBF_FWDLINK) {
prompt("Forward Process Link")
promptgroup("20 - Scan")
interest(1)
}

View File

@@ -0,0 +1,521 @@
#*************************************************************************
# Copyright (c) 2007 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
=head3 Operator Display Parameters
The B<NAME> field contains the record name which must be unique within an
EPICS Channel Access name space. The name is supplied by the application
developer and is the means of identifying a specific record. The name has a
maximum length of 60 characters and should use only this limited set of
characters:
a-z A-Z 0-9 _ - : [ ] < > ;
The B<DESC> field may be set to provide a meaningful description of the
record's purpose. Maximum length is 40 characters.
=fields NAME, DESC
=cut
%#include "epicsTypes.h"
%#include "link.h"
field(NAME,DBF_STRING) {
prompt("Record Name")
special(SPC_NOMOD)
size(61)
}
field(DESC,DBF_STRING) {
prompt("Descriptor")
promptgroup("10 - Common")
size(41)
}
field(ASG,DBF_STRING) {
prompt("Access Security Group")
promptgroup("10 - Common")
special(SPC_AS)
size(29)
}
=head3 Scan Fields
These fields contain information related to how and when a record processes. A
few records have unique fields that also affect how they process. These
fields, if any, will be listed and explained in the section for each record.
The B<SCAN> field specifies the scanning period for periodic record scans or the
scan type for non-periodic record scans. The default set of values for SCAN can
be found in L<menuScan.dbd|menuScan>.
The choices provided by this menu are:
=over
=item *
C<Passive> for the record scan to be triggered by other records or Channel
Access
=item *
C<Event> for event-driven scan
=item *
C<I/O Intr> for interrupt-driven scan
=item *
A set of periodic scan intervals
=back
Additional periodic scan rates may be defined for individual IOCs by making a
local copy of menuScan.dbd and adding more choices as required. Scan rates
should normally be defined in order, with the fastest rates appearing first.
Scan periods may now be specified in seconds, minutes, hours or Hertz/Hz, and
plural time units will also be accepted (seconds are used if no unit is
mentioned in the choice string). For example the rates given below are all
valid:
1 hour
0.5 hours
15 minutes
3 seconds
1 second
2 Hertz
The B<PINI> field specifies record processing at initialization. If it is set
to YES during database configuration, the record is processed once at IOC
initialization (before the normal scan tasks are started).
The B<PHAS> field orders the records within a specific SCAN group. This is not
meaningful for passive records. All records of a specified phase are processed
before those with higher phase number. Whenever possible it is better to use
linked passive records to enforce the order of processing rather than a phase
number.
The B<EVNT> field specifies an event number. This event number is used if the
SCAN field is set to C<Event>. All records with scan type C<Event> and the
same EVNT value will be processed when a call to post_event for EVNT is made.
The call to post_event is: post_event(short event_number).
The B<PRIO> field specifies the scheduling priority for processing records
with SCAN=C<I/O Event> and asynchronous record completion tasks.
The B<DISV> field specifies a "disable value". Record processing is
immediately terminated if the value of this field is equal to the value of the
DISA field, i.e. the record is disabled. Note that field values of a record
can be changed by database put or Channel Access, even if a record is
disabled.
The B<DISA> field contains the value that is compared with DISV to determine
if the record is disabled. The value of the DISA field is obtained via SDIS if
SDIS is a database or channel access link. If SDIS is not a database or
channel access link, then DISA can be set via dbPutField or dbPutLink.
If the B<PROC> field of a record is written to, the record is processed.
The B<DISS> field defines the record's "disable severity". If this field is
not NO_ALARM and the record is disabled, the record will be put into alarm
with this severity and a status of DISABLE_ALARM.
The B<LSET> field contains the lock set to which this record belongs. All
records linked in any way via input, output, or forward database links belong
to the same lock set. Lock sets are determined at IOC initialization time, and
are updated whenever a database link is added, removed or altered.
The B<LCNT> field counts the number of times dbProcess finds the record active
during successive scans, i.e. PACT is TRUE. If dbProcess finds the record
active MAX_LOCK times (currently set to 10) it raises a SCAN_ALARM.
The B<PACT> field is TRUE while the record is being processed. For
asynchronous records PACT can be TRUE from the time record processing is
started until the asynchronous completion occurs. As long as PACT is TRUE,
dbProcess will not call the record processing routine. See Application
Developers Guide for details on usage of PACT.
The B<FLNK> field is a database link to another record (the "target" record).
Processing a record with a specified FLNK field will force processing of the
target record, provided the target record's SCAN field is set to C<Passive>.
The B<SPVT> field is for internal use by the scanning system.
=fields SCAN, PINI, PHAS, EVNT, PRIO, DISV, DISA, SDIS, PROC, DISS, LCNT, PACT, FLNK, SPVT
=cut
field(SCAN,DBF_MENU) {
prompt("Scan Mechanism")
promptgroup("20 - Scan")
special(SPC_SCAN)
interest(1)
menu(menuScan)
}
field(PINI,DBF_MENU) {
prompt("Process at iocInit")
promptgroup("20 - Scan")
interest(1)
menu(menuPini)
}
field(PHAS,DBF_SHORT) {
prompt("Scan Phase")
promptgroup("20 - Scan")
special(SPC_SCAN)
interest(1)
}
field(EVNT,DBF_STRING) {
prompt("Event Name")
promptgroup("20 - Scan")
special(SPC_SCAN)
size(40)
interest(1)
}
field(TSE,DBF_SHORT) {
prompt("Time Stamp Event")
promptgroup("20 - Scan")
interest(1)
}
field(TSEL,DBF_INLINK) {
prompt("Time Stamp Link")
promptgroup("20 - Scan")
interest(1)
}
field(DTYP,DBF_DEVICE) {
prompt("Device Type")
promptgroup("10 - Common")
interest(1)
}
field(DISV,DBF_SHORT) {
prompt("Disable Value")
promptgroup("20 - Scan")
initial("1")
}
field(DISA,DBF_SHORT) {
prompt("Disable")
}
field(SDIS,DBF_INLINK) {
prompt("Scanning Disable")
promptgroup("20 - Scan")
interest(1)
}
%#include "epicsMutex.h"
field(MLOK,DBF_NOACCESS) {
prompt("Monitor lock")
special(SPC_NOMOD)
interest(4)
extra("epicsMutexId mlok")
}
%#include "ellLib.h"
field(MLIS,DBF_NOACCESS) {
prompt("Monitor List")
special(SPC_NOMOD)
interest(4)
extra("ELLLIST mlis")
}
field(BKLNK,DBF_NOACCESS) {
prompt("Backwards link tracking")
special(SPC_NOMOD)
interest(4)
extra("ELLLIST bklnk")
}
field(DISP,DBF_UCHAR) {
prompt("Disable putField")
}
field(PROC,DBF_UCHAR) {
prompt("Force Processing")
pp(TRUE)
interest(3)
}
=head3 Alarm Fields
These fields indicate the status and severity of alarms, or else determine the
how and when alarms are triggered. Of course, many records have alarm-related
fields not common to all records. These fields are listed and explained in the
appropriate section on each record.
The B<STAT> field contains the current alarm status.
The B<SEVR> field contains the current alarm severity.
These two fields are seen outside database access. The B<NSTA> and B<NSEV>
fields are used by the database access, record support, and device support
routines to set new alarm status and severity values. Whenever any software
component discovers an alarm condition, it uses the following macro function:
recGblSetSevr(precord,new_status,new_severity) This ensures that the current
alarm severity is set equal to the highest outstanding alarm. The file alarm.h
defines all allowed alarm status and severity values.
The B<ACKS> field contains the highest unacknowledged alarm severity.
The B<ACKT> field specifies if it is necessary to acknowledge transient
alarms.
The B<UDF> indicates if the record's value is B<U>nB<D>eB<F>ined. Typically
this is caused by a failure in device support, the fact that the record has
never been processed, or that the VAL field currently contains a NaN (not a
number). UDF is initialized to TRUE at IOC initialization. Record and device
support routines which write to the VAL field are responsible for setting UDF.
=fields STAT, SEVR, NSTA, NSEV, ACKS, ACKT, UDF
=cut
field(STAT,DBF_MENU) {
prompt("Alarm Status")
special(SPC_NOMOD)
menu(menuAlarmStat)
initial("UDF")
}
field(SEVR,DBF_MENU) {
prompt("Alarm Severity")
special(SPC_NOMOD)
menu(menuAlarmSevr)
}
field(NSTA,DBF_MENU) {
prompt("New Alarm Status")
special(SPC_NOMOD)
interest(2)
menu(menuAlarmStat)
}
field(NSEV,DBF_MENU) {
prompt("New Alarm Severity")
special(SPC_NOMOD)
interest(2)
menu(menuAlarmSevr)
}
field(ACKS,DBF_MENU) {
prompt("Alarm Ack Severity")
special(SPC_NOMOD)
interest(2)
menu(menuAlarmSevr)
}
field(ACKT,DBF_MENU) {
prompt("Alarm Ack Transient")
promptgroup("70 - Alarm")
special(SPC_NOMOD)
interest(2)
menu(menuYesNo)
initial("YES")
}
field(DISS,DBF_MENU) {
prompt("Disable Alarm Sevrty")
promptgroup("70 - Alarm")
interest(1)
menu(menuAlarmSevr)
}
field(LCNT,DBF_UCHAR) {
prompt("Lock Count")
special(SPC_NOMOD)
interest(2)
}
field(PACT,DBF_UCHAR) {
prompt("Record active")
special(SPC_NOMOD)
interest(1)
}
field(PUTF,DBF_UCHAR) {
prompt("dbPutField process")
special(SPC_NOMOD)
interest(1)
}
field(RPRO,DBF_UCHAR) {
prompt("Reprocess ")
special(SPC_NOMOD)
interest(1)
}
field(ASP,DBF_NOACCESS) {
prompt("Access Security Pvt")
special(SPC_NOMOD)
interest(4)
extra("struct asgMember *asp")
}
field(PPN,DBF_NOACCESS) {
prompt("pprocessNotify")
special(SPC_NOMOD)
interest(4)
extra("struct processNotify *ppn")
}
field(PPNR,DBF_NOACCESS) {
prompt("pprocessNotifyRecord")
special(SPC_NOMOD)
interest(4)
extra("struct processNotifyRecord *ppnr")
}
field(SPVT,DBF_NOACCESS) {
prompt("Scan Private")
special(SPC_NOMOD)
interest(4)
extra("struct scan_element *spvt")
}
=head3 Device Fields
The B<RSET> field contains the address of the Record Support Entry Table. See
the Application Developers Guide for details on usage.
The B<DSET> field contains the address of Device Support Entry Table. The
value of this field is determined at IOC initialization time. Record support
routines use this field to locate their device support routines.
The B<DPVT> field is is for private use of the device support modules.
=fields RSET, DSET, DPVT
=cut
field(RSET,DBF_NOACCESS) {
prompt("Address of RSET")
special(SPC_NOMOD)
interest(4)
extra("struct typed_rset *rset")
}
%#include "devSup.h"
field(DSET,DBF_NOACCESS) {
prompt("DSET address")
special(SPC_NOMOD)
interest(4)
extra("unambiguous_dset *dset")
}
field(DPVT,DBF_NOACCESS) {
prompt("Device Private")
special(SPC_NOMOD)
interest(4)
extra("void *dpvt")
}
field(RDES,DBF_NOACCESS) {
prompt("Address of dbRecordType")
special(SPC_NOMOD)
interest(4)
extra("struct dbRecordType *rdes")
}
field(LSET,DBF_NOACCESS) {
prompt("Lock Set")
special(SPC_NOMOD)
interest(4)
extra("struct lockRecord *lset")
}
field(PRIO,DBF_MENU) {
prompt("Scheduling Priority")
promptgroup("20 - Scan")
special(SPC_SCAN)
interest(1)
menu(menuPriority)
}
=head3 Debugging Fields
The B<TPRO> field is used for trace processing. If this field is non-zero a
message is printed whenever this record is processed, and when any other
record in the same lock-set is processed by a database link from this record.
The B<BKPT> field indicates if there is a breakpoint set at this record. This
supports setting a debug breakpoint in the record processing. STEP through
database processing can be supported using this.
=fields TPRO, BKPT
=head3 Miscellaneous Fields
The B<ASG> field contains a character string value defining the access
security group for this record. If left empty, the record is placed in group
DEFAULT.
The B<ASP> field is a field for private use of the access security system.
The B<DISP> field controls dbPutFields to this record which are normally
issued by channel access. If the field is set to TRUE all dbPutFields
directed to this record are ignored except to the field DISP itself.
The B<DTYP> field specifies the device type for the record. Each record type
has its own set of device support routines which are specified in
devSup.ASCII. If a record type does not have any associated device support,
DTYP and DSET are meaningless.
The B<MLOK> field contains the monitor lock. The lock used by the monitor
routines when the monitor list is being used. The list is locked whenever
monitors are being scheduled, invoked, or when monitors are being added to or
removed from the list. This field is accessed only by the dbEvent routines.
The B<MLIS> field is the head of the list of monitors connected to this
record. Each record support module is responsible for triggering monitors for
any fields that change as a result of record processing. Monitors are present
if mlis count is greater than zero. The call to trigger monitors is:
db_post_event(precord,&data,mask), where "mask" is some combination of
DBE_ALARM, DBE_VALUE, and DBE_LOG.
The B<PPN> field contains the address of a putNotify callback.
The B<PPNR> field contains the next record for PutNotify.
The B<PUTF> field is set to TRUE if dbPutField caused the current record
processing.
The B<RDES> field contains the address of dbRecordType
The B<RPRO> field specifies a reprocessing of the record when current
processing completes.
The B<TIME> field contains the time when this record was last processed in
standard format.
The B<TSE> field indicates the mechanism to use to get the time stamp. '0' -
call get time as before '-1' - call the time stamp driver and use the best
source available. '-2' - the device support provides the time stamp from the
hardware. Values between 1-255 request the time of the last occurance of a
generalTime event.
The B<TSEL> field contains an input link for obtaining the time stamp. If this
link references the .TIME field of a record then the time stamp of the
referenced record becomes the time stamp for this record as well. In this
case, an internal flag is set and ".TIME" is then overwritten by ".VAL". If
any other field is referenced, the field value is read and stored in the .TSE
field which is then used to acquire a timestamp.
=fields ASG, ASP, DISP, DTYP, MLOK, MLIS, PPN, PPNR, PUTF, RDES, RPRO, TIME, TSE, TSEL
=cut
field(TPRO,DBF_UCHAR) {
prompt("Trace Processing")
}
field(BKPT,DBF_NOACCESS) {
prompt("Break Point")
special(SPC_NOMOD)
interest(1)
extra("char bkpt")
}
field(UDF,DBF_UCHAR) {
prompt("Undefined")
promptgroup("10 - Common")
pp(TRUE)
interest(1)
initial("1")
}
field(UDFS,DBF_MENU) {
prompt("Undefined Alarm Sevrty")
promptgroup("70 - Alarm")
interest(1)
menu(menuAlarmSevr)
initial("INVALID")
}
%#include "epicsTime.h"
field(TIME,DBF_NOACCESS) {
prompt("Time")
special(SPC_NOMOD)
interest(2)
extra("epicsTimeStamp time")
}
field(FLNK,DBF_FWDLINK) {
prompt("Forward Process Link")
promptgroup("20 - Scan")
interest(1)
}

View File

@@ -0,0 +1,181 @@
#*************************************************************************
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
=head1 Fields Common to Input Record Types
This section describes fields that are found in many input record types.
These fields usually have the same meaning whenever they are used.
See also L<Fields Common to All Record Types|dbCommonRecord> and L<Fields Common
to Output Record Types|dbCommonOutput>.
=head3 Input and Value Fields
The B<INP> field specifies an input link. It is used by the device support
routines to obtain input. For soft analog records it can be a constant, a
database link, or a channel access link.
The B<DTYP> field specifies the name of the device support module that will
input values. Each record type has its own set of device support routines. If
a record type does not have any associated device support, DTYP is
meaningless.
The B<RVAL> field contains - whenever possible - the raw data value exactly as
it is obtained from the hardware or from the associated device driver and
before it undergoes any conversions. The Soft Channel device support module
reads values directly into VAL, bypassing this field.
The B<VAL> field contains the record's final value, after any needed
conversions have been performed.
=head3 Device Input
A device input routine normally returns one of the following values to its
associated record support routine:
=over
=item *
0: Success and convert. The input value is in RVAL. The record support module
will compute VAL from RVAL.
=item *
2: Success, but don't convert. The device support module can specify this
value if it does not want any conversions. It might do this for two reasons:
=over
=item *
A hardware error is detected (in this case, it should also raise an alarm
condition).
=item *
The device support routine reads values directly into the VAL field and then
sets UDF to FALSE. For some record types the device support routine may have to
do other record-specific processing as well such as applying a smoothing filter
to the engineering units value.
=back
=back
=head3 Device Support for Soft Records
In most cases, two soft output device support modules are provided: Soft Channel
and Raw Soft Channel. Both allow INP to be a constant, a database link, or a
channel access link. The Soft Channel device support module reads input directly
into the VAL field and specifies that no value conversion should be performed.
This allows the record to store values in the data type of its VAL field. Note
that for Soft Channel input, the RVAL field is not used. The Raw Soft Channel
support module reads input into RVAL and indicates that any specified unit
conversions be performed.
The device support read routine normally calls C<dbGetLink()> which
fetches a value from the link.
If a value was returned by the link the UDF field is set to FALSE. The device
support read routine normally returns the status from C<dbGetLink()>.
=head3 Input Simulation Fields
The B<SIMM> field controls simulation mode. It has either the value YES or NO.
By setting this field to YES, the record can be switched into simulation mode
of operation. While in simulation mode, input will be obtained from SIOL
instead of INP.
Ths B<SIML> specifies the simulation mode location. This field can be a
constant, a database link, or a channel access link. If SIML is a database or
channel access link, then SIMM is read from SIML. If SIML is a constant link
then SIMM is initialized with the constant value but can be changed via
dbPuts.
Ths B<SVAL> field contains the simulation value. This is the record's input
value, in engineering units, when the record is switched into simulation mode,
i.e. when SIMM is set to YES.
The B<SIOL> field is a link that can be used to fetch the simulation value. The
link can be a constant, a database link, or a channel access link. If SIOL is a
database or channel access link, then SVAL is read from SIOL. If SIOL is a
constant link then SVAL is initialized with the constant value but can be
changed via dbPuts.
The B<SIMS> field specifies the simulation mode alarm severity. When this
field is set to a value other than NO_ALARM and the record is in simulation
mode, it will be put into alarm with this severity and a status of SIMM.
=head3 Simulation Mode for Input Records
An input record can be switched into simulation mode of operation by setting
the value of SIMM to YES or RAW. During simulation, the record will be put
into alarm with a severity of SIMS and a status of SIMM_ALARM. While in
simulation mode, input values will be read from SIOL instead of INP:
-- (SIMM = NO?) INP (if supported and directed by device support, -> RVAL -- convert -> VAL), (else -> VAL)
/
SIML -> SIMM
\
-- (SIMM = YES?) SIOL -> SVAL -> VAL
\
-- (SIMM = RAW?) SIOL -> SVAL -> RVAL -- convert -> VAL
A record can be switched into simulation mode of operation by setting the
value of SIMM to YES. During simulation, the record will be put into alarm
with a severity of SIMS and a status of SIMM_ALARM. While in simulation mode,
input values, in engineering units, will be obtained from SIOL instead of INP.
Also, while the record is in simulation mode, there will be no raw value
conversion and no calls to device support when the record is processed.
Normally input records contain a private readValue() routine which performs
the following steps:
=over
=item *
If PACT is TRUE, the device support read routine is called, status is set to
its return code, and readValue returns.
=item *
Call C<dbGetLink()> to get a new value for SIMM from SIML.
=item *
Check value of SIMM.
=item *
If SIMM is NO, then call the device support read routine, set status to its
return code, and return.
=item *
If SIMM is YES, then call C<dbGetLink()> to read the input value from SIOL
into SVAL. If success, then set VAL to SVAL and UDF to FALSE and set status to
2 (don't convert) if input record supports conversion. If SIMS is greater than
zero, set alarm status to SIMM and severity to SIMS. Set status to the return
code from recGblGetLinkValue and return.
=item *
If SIMM is RAW, then call C<dbGetLink()> to read the input value from SIOL
into SVAL. If success, then set RVAL to SVAL and UDF to FALSE and set status
to 0 (convert) if input record supports conversion. If SIMS is greater than
zero, set alarm status to SIMM and severity to SIMS. Set status to the return
code from recGblGetLinkValue and return.
=item *
If SIMM is not YES, NO or RAW, a SOFT alarm with a severity of INVALID is
raised, and return status is set to -1.
=back

View File

@@ -0,0 +1,211 @@
#*************************************************************************
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
=head1 Fields Common to Output Record Types
This section describes fields that are found in many output record types.
These fields usually have the same meaning whenever they are used.
See also L<Fields Common to All Record Types|dbCommonRecord> and L<Fields Common to
Input Records|dbCommonInput>.
=head3 Output and Value Fields
The B<OUT> field specifies an output link. It is used by the device support
routines to decide where to send output. For soft records, it can be a
constant, a database link, or a channel access link. If the link is a
constant, the result is no output.
The B<DTYP> field specifies the name of the device support module that will
input values. Each record type has its own set of device support routines. If
a record type does not have any associated device support, DTYP is
meaningless.
The B<VAL> field contains the desired value before any conversions to raw
output have been performed.
The B<OVAL> field is used to decide when to invoke monitors. Archive and value
change monitors are invoked if OVAL is not equal to VAL. If a record type
needs to make adjustments, OVAL is used to enforce the maximum rate of change
limit before converting the desired value to a raw value.
The B<RVAL> field contains - whenever possible - the actual value sent to the
hardware itself or to the associated device driver.
The B<RBV> field contains - whenever possible - the actual read back value
obtained from the hardware itself or from the associated device driver.
=head3 Device Support for Soft Records
Normally two soft output device support modules are provided, Soft Channel and
and Raw Soft Channel. Both write a value through the output link OUT.
The Soft Channel module writes output from the value associated with OVAL or
VAL (if OVAL does not exist). The Raw Soft Channel support module writes the
value associated with the RVAL field after conversion has been performed.
The device support write routine normally calls C<dbPutLink()> which writes a
value through the OUT link, and returns the status from that call.
=head3 Input and Mode Select Fields
The B<DOL> field is a link from which the desired output value can be fetched.
DOL can be a constant, a database link, or a channel access link. If DOL is a
database or channel access link and OMSL is closed_loop, then VAL is obtained
from DOL.
The B<OMSL> field selects the output mode. This field has either the value
C<supervisory> or C<closed_loop>. DOL is used to fetch VAL only if OMSL has the
value C<closed_loop>. By setting this field a record can be switched between
supervisory and closed loop mode of operation. While in closed loop mode, the
VAL field cannot be set via dbPuts.
=head3 Output Mode Selection
The fields DOL and OMSL are used to allow the output record to be part of a
closed loop control algorithm. OMSL is meaningful only if DOL refers to a
database or channel access link. It can have the values C<supervisory> or
C<closed_loop>. If the mode is C<supervisory>, then nothing is done to VAL. If
the mode is C<closed_loop> and the record type does not contain an OIF field,
then each time the record is processed, VAL is set equal to the value obtained
from the location referenced by DOL. If the mode is C<closed_loop> in record
types with an OIF field and OIF is Full, VAL is set equal to the value obtained
from the location referenced by DOL; if OIF is Incremental VAL is incremented by
the value obtained from DOL.
=head3 Invalid Output Action Fields
The B<IVOA> field specifies the output action for the case that the record is
put into an INVALID alarm severity. IVOA can be one of the following actions:
=over
=item *
C<Continue normally>
=item *
C<Don't drive outputs>
=item *
C<Set output to IVOV>
=back
The B<IVOV> field contains the value for the IVOA action C<Set output to IVOV>
in engineering units. If a new severity has been set to INVALID and IVOA is
C<Set output to IVOV>, then VAL is set to IVOV and converted to RVAL before
device support is called.
=head3 Invalid Alarm Output Action
Whenever an output record is put into INVALID alarm severity, IVOA specifies
an action to take. The record support process routine for each output record
contains code which performs the following steps.
=over
=item *
If new severity is less than INVALID, then call C<writeValue()>:
=item *
Else do the following:
=over
=item *
If IVOA is C<Continue normally> then call C<writeValue()>.
=item *
If IVOA is C<Don't drive outputs> then do not write output.
=item *
If IVOA is C<Set output to IVOV> then set VAL to IVOV, call C<convert()> if
necessary, and then call C<writeValue()>.
=item *
If IVOA not one of the above, an error message is generated.
=back
=back
=head3 Simulation Fields
The B<SIMM> field controls simulation mode. It has either the value YES or NO.
By setting this field to YES, the record can be switched into simulation mode
of operation. While in simulation mode, output will be forwarded through SIOL
instead of OUT.
Ths B<SIML> specifies the simulation mode location. This field can be a
constant, a database link, or a channel access link. If SIML is a database or
channel access link, then SIMM is read from SIML. If SIML is a constant link
then SIMM is initialized with the constant value but can be changed via
dbPuts.
The B<SIOL> field is a link that the output value is written to when the record
is in simulation mode.
The B<SIMS> field specifies the simulation mode alarm severity. When this
field is set to a value other than NO_ALARM and the record is in simulation
mode, it will be put into alarm with this severity and a status of SIMM.
=head3 Simulation Mode
An output record can be switched into simulation mode of operation by setting
the value of SIMM to YES. During simulation, the record will be put into alarm
with a severity of SIMS and a status of SIMM_ALARM. While in simulation mode,
output values, in engineering units, will be written to SIOL instead of OUT.
However, the output values are never converted. Also, while the record is in
simulation mode, there will be no calls to device support during record
processing.
Normally output records contain a private C<writeValue()> routine which performs
the following steps:
=over
=item *
If PACT is TRUE, the device support write routine is called, status is set to
its return code, and readValue returns.
=item *
Call C<dbGetLink()> to get a new value for SIMM if SIML is a DB_LINK or a
CA_LINK.
=item *
Check value of SIMM.
=item *
If SIMM is NO, then call the device support write routine, set status to its
return code, and return.
=item *
If SIMM is YES, then call C<dbPutLink()> to write the output value from VAL or
OVAL to SIOL. Set alarm status to SIMM and severity to SIMS, if SIMS is
greater than zero. Set status to the return code from C<dbPutLink()> and
return.
=item *
If SIMM not one of the above, a SOFT alarm with a severity of INVALID is
raised, and return status is set to -1.
=back

View File

@@ -1,12 +0,0 @@
#*************************************************************************
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE Versions 3.13.7
# and higher are distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
recordtype(dbCommon) {
include "dbCommon.dbd"
}

View File

@@ -0,0 +1,20 @@
#*************************************************************************
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
=head1 Fields Common to All Record Types
This section contains a description of the fields that are common to all record
types. These fields are defined in dbCommon.dbd.
See also L<Fields Common to Input Record Types|dbCommonInput> and L<Fields
Common to Output Record Types|dbCommonOutput>.
=recordtype dbCommon
=cut
recordtype(dbCommon) {
include "dbCommon.dbd.pod"
}

View File

@@ -35,6 +35,7 @@
#include "epicsExport.h"
#include "link.h"
#include "special.h"
#include "iocInit.h"
@@ -216,10 +217,13 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
char *penv;
char **macPairs;
if(ellCount(&tempList)) {
if (ellCount(&tempList)) {
epicsPrintf("dbReadCOM: Parser stack dirty %d\n", ellCount(&tempList));
}
if (getIocState() != iocVoid)
return -2;
if(*ppdbbase == 0) *ppdbbase = dbAllocBase();
pdbbase = *ppdbbase;
if(path && strlen(path)>0) {

View File

@@ -70,9 +70,7 @@
#include "registryJLinks.h"
#include "registryRecordType.h"
static enum {
iocVirgin, iocBuilding, iocBuilt, iocRunning, iocPaused, iocStopped
} iocState = iocVirgin;
static enum iocStateEnum iocState = iocVoid;
static enum {
buildServers, buildIsolated
} iocBuildMode;
@@ -99,6 +97,11 @@ static void iterateRecords(recIterFunc func, void *user);
int dbThreadRealtimeLock = 1;
epicsExportAddress(int, dbThreadRealtimeLock);
enum iocStateEnum getIocState(void)
{
return iocState;
}
/*
* Initialize EPICS on the IOC.
*/
@@ -109,7 +112,7 @@ int iocInit(void)
static int iocBuild_1(void)
{
if (iocState != iocVirgin && iocState != iocStopped) {
if (iocState != iocVoid) {
errlogPrintf("iocBuild: IOC can only be initialized from uninitialized or stopped state\n");
return -1;
}
@@ -705,8 +708,7 @@ static void doFreeRecord(dbRecordType *pdbRecordType, dbCommon *precord,
int iocShutdown(void)
{
if (iocState == iocVirgin || iocState == iocStopped)
return 0;
if (iocState == iocVoid) return 0;
iterateRecords(doCloseLinks, NULL);
@@ -734,7 +736,7 @@ int iocShutdown(void)
iocshFree();
}
iocState = iocStopped;
iocState = iocVoid;
iocBuildMode = buildServers;
return 0;
}

View File

@@ -13,10 +13,15 @@
#include "shareLib.h"
enum iocStateEnum {
iocVoid, iocBuilding, iocBuilt, iocRunning, iocPaused
};
#ifdef __cplusplus
extern "C" {
#endif
epicsShareFunc enum iocStateEnum getIocState(void);
epicsShareFunc int iocInit(void);
epicsShareFunc int iocBuild(void);
epicsShareFunc int iocBuildIsolated(void);

View File

@@ -68,17 +68,6 @@ static void req_server (void *pParm)
IOC_sock = conf->tcp;
/* listen and accept new connections */
if ( listen ( IOC_sock, 20 ) < 0 ) {
char sockErrBuf[64];
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
errlogPrintf ( "CAS: Listen error: %s\n",
sockErrBuf );
epicsSocketDestroy (IOC_sock);
epicsThreadSuspendSelf ();
}
epicsEventSignal(castcp_startStopEvent);
while (TRUE) {
@@ -198,7 +187,7 @@ SOCKET* rsrv_grab_tcp(unsigned short *port)
epicsSocketEnableAddressReuseDuringTimeWaitState ( tcpsock );
if(bind(tcpsock, &scratch.sa, sizeof(scratch))==0) {
if(bind(tcpsock, &scratch.sa, sizeof(scratch))==0 && listen(tcpsock, 20)==0) {
if(scratch.ia.sin_port==0) {
/* use first socket to pick a random port */
osiSocklen_t alen = sizeof(ifaceAddr);

View File

@@ -1,143 +0,0 @@
#*************************************************************************
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
menu(aaiPOST) {
choice(aaiPOST_Always,"Always")
choice(aaiPOST_OnChange,"On Change")
}
recordtype(aai) {
include "dbCommon.dbd"
field(VAL,DBF_NOACCESS) {
prompt("Value")
asl(ASL0)
special(SPC_DBADDR)
pp(TRUE)
extra("void * val")
#=type DOUBLE[]
#=read Yes
#=write Yes
}
field(PREC,DBF_SHORT) {
prompt("Display Precision")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(INP,DBF_INLINK) {
prompt("Input Specification")
promptgroup("40 - Input")
interest(1)
}
field(EGU,DBF_STRING) {
prompt("Engineering Units")
promptgroup("80 - Display")
interest(1)
size(16)
prop(YES)
}
field(HOPR,DBF_DOUBLE) {
prompt("High Operating Range")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(LOPR,DBF_DOUBLE) {
prompt("Low Operating Range")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(NELM,DBF_ULONG) {
prompt("Number of Elements")
promptgroup("30 - Action")
special(SPC_NOMOD)
interest(1)
initial("1")
}
field(FTVL,DBF_MENU) {
prompt("Field Type of Value")
promptgroup("30 - Action")
special(SPC_NOMOD)
interest(1)
menu(menuFtype)
}
field(NORD,DBF_ULONG) {
prompt("Number elements read")
special(SPC_NOMOD)
}
field(BPTR,DBF_NOACCESS) {
prompt("Buffer Pointer")
special(SPC_NOMOD)
interest(4)
extra("void * bptr")
}
field(SIML,DBF_INLINK) {
prompt("Simulation Mode Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
special(SPC_MOD)
interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
prompt("Simulation Mode Severity")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
field(SIOL,DBF_INLINK) {
prompt("Simulation Input Link")
promptgroup("90 - Simulate")
interest(1)
}
field(OLDSIMM,DBF_MENU) {
prompt("Prev. Simulation Mode")
special(SPC_NOMOD)
interest(4)
menu(menuSimm)
}
field(SSCN,DBF_MENU) {
prompt("Sim. Mode Scan")
promptgroup("90 - Simulate")
interest(1)
menu(menuScan)
initial("65535")
}
field(SDLY,DBF_DOUBLE) {
prompt("Sim. Mode Async Delay")
promptgroup("90 - Simulate")
interest(2)
initial("-1.0")
}
%#include "callback.h"
field(SIMPVT,DBF_NOACCESS) {
prompt("Sim. Mode Private")
special(SPC_NOMOD)
interest(4)
extra("epicsCallback *simpvt")
}
field(MPST,DBF_MENU) {
prompt("Post Value Monitors")
promptgroup("80 - Display")
interest(1)
menu(aaiPOST)
}
field(APST,DBF_MENU) {
prompt("Post Archive Monitors")
promptgroup("80 - Display")
interest(1)
menu(aaiPOST)
}
field(HASH,DBF_ULONG) {
prompt("Hash of OnChange data.")
interest(3)
}
}

View File

@@ -0,0 +1,505 @@
#*************************************************************************
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
=title Array Analog Input (aai)
The array analog input record type is used to read array data. The array data can
contain any of the supported data types. The record is in many ways similar to the
waveform record. It allows, however, the device support to allocate the array
storage.
=recordtype aai
=cut
include "menuFtype.dbd"
menu(aaiPOST) {
choice(aaiPOST_Always,"Always")
choice(aaiPOST_OnChange,"On Change")
}
recordtype(aai) {
=head2 Parameter Fields
The record-specific fields are described below, grouped by functionality.
=head3 Scan Parameters
The array analog input record has the standard fields for specifying under what
circumstances the record will be processed. These fields are listed in L<Scan
Fields>. In addition, L<Scanning Specification> explains how these fields are
used. Note that I/O event scanning is only supported for those card types that
interrupt.
=head3 Read Parameters
These fields are configurable by the user to specify how and from where the record
reads its data. The INP field determines from where the array analog input gets
its input. It can be a hardware address, a channel access or database link, or a
constant. Only in records that use soft device support can the INP field be a
channel access link, a database link, or a constant. Otherwise, the INP field must
be a hardware address. See L<Address Specification> for information on the format
of hardware addresses and database links.
=head4 Fields related to waveform reading
The DTYP field must contain the name of the appropriate device support module.
The values retrieved from the input link are placed in an array referenced by
VAL. (If the INP link is a constant, elements can be placed in the array via
dbPuts.) NELM specifies the number of elements that the array will hold, while
FTVL specifies the data type of the elements.
=fields DTYP, INP, NELM, FTVL
=head4 Possible data types for FTVL
=menu menuFtype
=head3 Operator Display Parameters
These parameters are used to present meaningful data to the operator. They
display the value and other parameters of the waveform either textually or
graphically.
=head4 Fields related to I<Operator Display>
EGU is a string of up to 16 characters describing the units that the array data
measures. It is retrieved by the C<<< get_units() >>> record support routine.
The HOPR and LOPR fields set the upper and lower display limits for array
elements referenced by the VAL field. Both the C<<< get_graphic_double() >>> and
C<<< get_control_double() >>> record support routines retrieve these fields.
The PREC field determines the floating point precision with which to display the
array values. It is used whenever the C<<< get_precision() >>> record support
routine is called.
See L<Fields Common to All Record Types> for more on the record name (NAME) and
description (DESC) fields.
=fields EGU, HOPR, LOPR, PREC, NAME, DESC
=head3 Alarm Parameters
The array analog input record has the alarm parameters common to all record types.
=head3 Monitor Parameters
These parameters are used to determine when to send monitors placed on the VAL
field. The APST and MPST fields are a menu with choices "Always" and "On
Change". The default is "Always", thus monitors will normally be sent every time
the record processes. Selecting "On Change" causes a 32-bit hash of the VAL
field buffer to be calculated and compared with the previous hash value every
time the record processes; the monitor will only be sent if the hash is
different, indicating that the buffer has changed. Note that there is a small
chance that two different value buffers might result in the same hash value, so
for critical systems "Always" may be a better choice, even though it re-sends
duplicate data.
=head4 Record fields related to I<Monitor Parameters>
=fields APST, MPST, HASH
=head4 Menu choices for C<APST> and C<MPST> fields
=menu aaiPOST
=head3 Run-time Parameters
These parameters are used by the run-time code for processing the array analog
input record. They are not configured using a configuration tool. Only the VAL
field is modifiable at run-time.
VAL references the array where the array analog input record stores its data. The
BPTR field holds the address of the array.
The NORD field holds a counter of the number of elements that have been read
into the array.
=fields VAL, BPTR, NORD
The following fields are used to operate the array analog input record in the
simulation mode. See L<Simulation Mode> for more information on the simulation
mode fields.
=fields SIOL, SIML, SIMM, SIMS
=begin html
<br>
<hr>
<br>
=end html
=head2 Record Support
=head3 Record Support Routines
=head4 init_record
static long init_record(aaiRecord *prec, int pass)
If device support includes C<init_record()>, it is called.
Checks if device support allocated array space. If not, space for the array is
allocated using NELM and FTVL. The array address is stored in the record.
This routine initializes SIMM with the value of SIML if SIML type is CONSTANT
link or creates a channel access link if SIML type is PV_LINK. VAL is likewise
initialized if SIOL is CONSTANT or PV_LINK.
This routine next checks to see that device support is available and a device
support read routine is defined. If either does not exist, an error message is
issued and processing is terminated
=head4 process
static long process(aaiRecord *prec)
See L</"Record Processing"> section below.
=head4 cvt_dbaddr
static long cvt_dbaddr(DBADDR *paddr)
This is called by dbNameToAddr. It makes the dbAddr structure refer to the
actual buffer holding the result.
=head4 get_array_info
static long get_array_info(DBADDR *paddr, long *no_elements, long *offset)
Obtains values from the array referenced by VAL.
=head4 put_array_info
static long put_array_info(DBADDR *paddr, long nNew)
Writes values into the array referenced by VAL.
=head4 get_units
static long get_units(DBADDR *paddr, char *units)
Retrieves EGU.
=head4 get_prec
static long get_precision(DBADDR *paddr, long *precision)
Retrieves PREC if field is VAL field. Otherwise, calls C<<< recGblGetPrec() >>>.
=head4 get_graphic_double
static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd)
Sets the upper display and lower display limits for a field. If the field is VAL
the limits are set to HOPR and LOPR, else if the field has upper and lower
limits defined they will be used, else the upper and lower maximum values for
the field type will be used.
Sets the following values:
upper_disp_limit = HOPR
lower_disp_limit = LOPR
=head4 get_control_double
static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd)
Sets the upper control and the lower control limits for a field. If the field is
VAL the limits are set to HOPR and LOPR, else if the field has upper and lower
limits defined they will be used, else the upper and lower maximum values for
the field type will be used.
Sets the following values
upper_ctrl_limit = HOPR
lower_ctrl_limit = LOPR
=head3 Record Processing
Routine process implements the following algorithm:
=over
=item 1.
Check to see that the appropriate device support module exists. If it doesn't,
an error message is issued and processing is terminated with the PACT field
still set to TRUE. This ensures that processes will no longer be called for this
record. Thus error storms will not occur.
=item 2.
Call device support read routine C<read_aai()>.
=item 3.
If PACT has been changed to TRUE, the device support read routine has started
but has not completed writing the new value. In this case, the processing
routine merely returns, leaving PACT TRUE.
=item 4.
Check to see if monitors should be invoked.
=over
=item *
Alarm monitors are invoked if the alarm status or severity has changed.
=item *
Archive and value change monitors are invoked if APST or MPST are Always or if
the result of the hash calculation is different.
=item *
NSEV and NSTA are reset to 0.
=back
=item 5.
Scan forward link if necessary, set PACT FALSE, and return.
=back
=begin html
<br>
<hr>
<br>
=end html
=cut
include "dbCommon.dbd"
field(VAL,DBF_NOACCESS) {
prompt("Value")
asl(ASL0)
special(SPC_DBADDR)
pp(TRUE)
extra("void * val")
#=type DOUBLE[]
#=read Yes
#=write Yes
}
field(PREC,DBF_SHORT) {
prompt("Display Precision")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(INP,DBF_INLINK) {
prompt("Input Specification")
promptgroup("40 - Input")
interest(1)
}
field(EGU,DBF_STRING) {
prompt("Engineering Units")
promptgroup("80 - Display")
interest(1)
size(16)
prop(YES)
}
field(HOPR,DBF_DOUBLE) {
prompt("High Operating Range")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(LOPR,DBF_DOUBLE) {
prompt("Low Operating Range")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(NELM,DBF_ULONG) {
prompt("Number of Elements")
promptgroup("30 - Action")
special(SPC_NOMOD)
interest(1)
initial("1")
}
field(FTVL,DBF_MENU) {
prompt("Field Type of Value")
promptgroup("30 - Action")
special(SPC_NOMOD)
interest(1)
menu(menuFtype)
}
field(NORD,DBF_ULONG) {
prompt("Number elements read")
special(SPC_NOMOD)
}
field(BPTR,DBF_NOACCESS) {
prompt("Buffer Pointer")
special(SPC_NOMOD)
interest(4)
extra("void * bptr")
}
field(SIML,DBF_INLINK) {
prompt("Simulation Mode Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
special(SPC_MOD)
interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
prompt("Simulation Mode Severity")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
field(SIOL,DBF_INLINK) {
prompt("Simulation Input Link")
promptgroup("90 - Simulate")
interest(1)
}
field(OLDSIMM,DBF_MENU) {
prompt("Prev. Simulation Mode")
special(SPC_NOMOD)
interest(4)
menu(menuSimm)
}
field(SSCN,DBF_MENU) {
prompt("Sim. Mode Scan")
promptgroup("90 - Simulate")
interest(1)
menu(menuScan)
initial("65535")
}
field(SDLY,DBF_DOUBLE) {
prompt("Sim. Mode Async Delay")
promptgroup("90 - Simulate")
interest(2)
initial("-1.0")
}
%#include "callback.h"
field(SIMPVT,DBF_NOACCESS) {
prompt("Sim. Mode Private")
special(SPC_NOMOD)
interest(4)
extra("epicsCallback *simpvt")
}
field(MPST,DBF_MENU) {
prompt("Post Value Monitors")
promptgroup("80 - Display")
interest(1)
menu(aaiPOST)
}
field(APST,DBF_MENU) {
prompt("Post Archive Monitors")
promptgroup("80 - Display")
interest(1)
menu(aaiPOST)
}
field(HASH,DBF_ULONG) {
prompt("Hash of OnChange data.")
interest(3)
}
}
=head2 Device Support
=head3 Fields Of Interest To Device Support
Each array analog input record record must have an associated set of device
support routines. The primary responsibility of the device support routines is to
obtain a new array value whenever C<read_aai()> is called. The device support
routines are primarily interested in the following fields:
=fields PACT, DPVT, NSEV, NSTA, INP, NELM, FTVL, BPTR, NORD
=head3 Device Support Routines
Device support consists of the following routines:
=head4 report
long report(int level)
This optional routine is called by the IOC command C<dbior> and is passed the
report level that was requested by the user.
It should print a report on the state of the device support to stdout.
The C<level> parameter may be used to output increasingly more detailed
information at higher levels, or to select different types of information with
different levels.
Level zero should print no more than a small summary.
=head4 init
long init(int after)
This optional routine is called twice at IOC initialization time.
The first call happens before any of the C<init_record()> calls are made, with
the integer parameter C<after> set to 0.
The second call happens after all of the C<init_record()> calls have been made,
with C<after> set to 1.
=head4 init_record
long init_record(dbCommon *precord)
This routine is optional. If provided, it is called by the record support
C<init_record()> routine.
=head4 get_ioint_info
long get_ioint_info(int cmd, dbCommon *precord, IOSCANPVT *ppvt)
This routine is called by the ioEventScan system each time the record is added
or deleted from an I/O event scan list. cmd has the value (0,1) if the
record is being (added to, deleted from) an I/O event list. It must be
provided for any device type that can use the ioEvent scanner.
=head4 read_aai
long read_aai(dbCommon *precord)
This routine must provide a new input value. It returns the following values:
=over
=item *
0: Success.
=item *
Other: Error.
=back
=head3 Device Support For Soft Records
The C<<< Soft Channel >>> device support module is provided to read values from
other records and store them in arrays. If INP is a constant link, then read_aai
does nothing. In this case, the record can be used to hold arrays written via
dbPuts. If INP is a database or channel access link, the new array value is read
from the link. NORD is set.
This module places a value directly in VAL and NORD is set to the number of items
in the array.
If the INP link type is constant, then NORD is set to zero.
=cut

View File

@@ -1,143 +0,0 @@
#*************************************************************************
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
menu(aaoPOST) {
choice(aaoPOST_Always,"Always")
choice(aaoPOST_OnChange,"On Change")
}
recordtype(aao) {
include "dbCommon.dbd"
field(VAL,DBF_NOACCESS) {
prompt("Value")
asl(ASL0)
special(SPC_DBADDR)
pp(TRUE)
extra("void * val")
#=type DOUBLE[]
#=read Yes
#=write Yes
}
field(PREC,DBF_SHORT) {
prompt("Display Precision")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(OUT,DBF_OUTLINK) {
prompt("Output Specification")
promptgroup("50 - Output")
interest(1)
}
field(EGU,DBF_STRING) {
prompt("Engineering Units")
promptgroup("80 - Display")
interest(1)
size(16)
prop(YES)
}
field(HOPR,DBF_DOUBLE) {
prompt("High Operating Range")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(LOPR,DBF_DOUBLE) {
prompt("Low Operating Range")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(NELM,DBF_ULONG) {
prompt("Number of Elements")
promptgroup("30 - Action")
special(SPC_NOMOD)
interest(1)
initial("1")
}
field(FTVL,DBF_MENU) {
prompt("Field Type of Value")
promptgroup("30 - Action")
special(SPC_NOMOD)
interest(1)
menu(menuFtype)
}
field(NORD,DBF_ULONG) {
prompt("Number elements read")
special(SPC_NOMOD)
}
field(BPTR,DBF_NOACCESS) {
prompt("Buffer Pointer")
special(SPC_NOMOD)
interest(4)
extra("void * bptr")
}
field(SIML,DBF_INLINK) {
prompt("Simulation Mode Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
special(SPC_MOD)
interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
prompt("Simulation Mode Severity")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
field(SIOL,DBF_OUTLINK) {
prompt("Simulation Output Link")
promptgroup("90 - Simulate")
interest(1)
}
field(OLDSIMM,DBF_MENU) {
prompt("Prev. Simulation Mode")
special(SPC_NOMOD)
interest(4)
menu(menuSimm)
}
field(SSCN,DBF_MENU) {
prompt("Sim. Mode Scan")
promptgroup("90 - Simulate")
interest(1)
menu(menuScan)
initial("65535")
}
field(SDLY,DBF_DOUBLE) {
prompt("Sim. Mode Async Delay")
promptgroup("90 - Simulate")
interest(2)
initial("-1.0")
}
%#include "callback.h"
field(SIMPVT,DBF_NOACCESS) {
prompt("Sim. Mode Private")
special(SPC_NOMOD)
interest(4)
extra("epicsCallback *simpvt")
}
field(MPST,DBF_MENU) {
prompt("Post Value Monitors")
promptgroup("80 - Display")
interest(1)
menu(aaoPOST)
}
field(APST,DBF_MENU) {
prompt("Post Archive Monitors")
promptgroup("80 - Display")
interest(1)
menu(aaoPOST)
}
field(HASH,DBF_ULONG) {
prompt("Hash of OnChange data.")
interest(3)
}
}

View File

@@ -0,0 +1,503 @@
#*************************************************************************
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
=title Array Analog Output (aao)
The array analog output record type is used to write array data. The array data
can contain any of the supported data types. The record is in many ways similar to
the waveform record but outputs arrays instead of reading them. It also allows the
device support to allocate the array storage.
=recordtype aao
=cut
include "menuFtype.dbd"
menu(aaoPOST) {
choice(aaoPOST_Always,"Always")
choice(aaoPOST_OnChange,"On Change")
}
recordtype(aao) {
=head2 Parameter Fields
The record-specific fields are described below, grouped by functionality.
=head3 Scan Parameters
The array analog output record has the standard fields for specifying under what
circumstances the record will be processed. These fields are listed in L<Scan
Fields>. In addition, L<Scanning Specification> explains how these fields are
used. I/O event scanning is only available when supported by device support.
=head3 Write Parameters
These fields are configurable by the user to specify how and where to the record
writes its data. The OUT field determines where the array analog output writes its
output. It can be a hardware address, a channel access or database link, or a
constant. Only in records that use soft device support can the OUT field be a
channel access link, a database link, or a constant. Otherwise, the OUT field must
be a hardware address. See L<Address Specification> for information on the format
of hardware addresses and database links.
=head4 Fields related to array writing
The DTYP field must contain the name of the appropriate device support module. The
values in the array referenced by are written to the location specified in the OUT
field. (If the OUT link is a constant, no data are written.) NELM specifies the
maximum number of elements that the array can hold, while FTVL specifies the data
type of the elements.
=fields DTYP, OUT, NELM, FTVL
=head4 Possible data types for FTVL
=menu menuFtype
=head3 Operator Display Parameters
These parameters are used to present meaningful data to the operator. They
display the value and other parameters of the waveform either textually or
graphically.
=head4 Fields related to I<Operator Display>
EGU is a string of up to 16 characters describing the units that the array data
measures. It is retrieved by the C<<< get_units >>> record support routine.
The HOPR and LOPR fields set the upper and lower display limits for array
elements referenced by the VAL field. Both the C<<< get_graphic_double >>> and
C<<< get_control_double >>> record support routines retrieve these fields.
The PREC field determines the floating point precision with which to display the
array values. It is used whenever the C<<< get_precision >>> record support
routine is called.
See L<Fields Common to All Record Types> for more on the record name (NAME) and
description (DESC) fields.
=fields EGU, HOPR, LOPR, PREC, NAME, DESC
=head3 Alarm Parameters
The array analog output record has the alarm parameters common to all record
types.
=head3 Monitor Parameters
These parameters are used to determine when to send monitors placed on the VAL
field. The APST and MPST fields are a menu with choices "Always" and "On
Change". The default is "Always", thus monitors will normally be sent every time
the record processes. Selecting "On Change" causes a 32-bit hash of the VAL
field buffer to be calculated and compared with the previous hash value every
time the record processes; the monitor will only be sent if the hash is
different, indicating that the buffer has changed. Note that there is a small
chance that two different value buffers might result in the same hash value, so
for critical systems "Always" may be a better choice, even though it re-sends
duplicate data.
=head4 Record fields related to I<Monitor Parameters>
=fields APST, MPST, HASH
=head4 Menu choices for C<APST> and C<MPST> fields
=menu aaoPOST
=head3 Run-time Parameters
These parameters are used by the run-time code for processing the array analog
output record. They are not configured using a configuration tool. Only the VAL
field is modifiable at run-time.
VAL references the array where the array analog output record stores its data. The
BPTR field holds the address of the array.
The NORD field holds a counter of the number of elements that have been written to
the output,
=fields VAL, BPTR, NORD
The following fields are used to operate the array analog output record in the
simulation mode. See L<Simulation Mode> for more information on the simulation
mode fields.
=fields SIOL, SIML, SIMM, SIMS
=begin html
<br>
<hr>
<br>
=end html
=head2 Record Support
=head3 Record Support Routines
=head4 init_record
static long init_record(aaoRecord *prec, int pass)
If device support includes C<init_record()>, it is called.
Checks if device support allocated array space. If not, space for the array is
allocated using NELM and FTVL. The array address is stored in the record.
This routine initializes SIMM with the value of SIML if SIML type is CONSTANT
link or creates a channel access link if SIML type is PV_LINK. VAL is likewise
initialized if SIOL is CONSTANT or PV_LINK.
This routine next checks to see that device support is available and a device
support write routine is defined. If either does not exist, an error message is
issued and processing is terminated
=head4 process
static long process(aaoRecord *prec)
See L</"Record Processing"> section below.
=head4 cvt_dbaddr
static long cvt_dbaddr(DBADDR *paddr)
This is called by dbNameToAddr. It makes the dbAddr structure refer to the
actual buffer holding the result.
=head4 get_array_info
static long get_array_info(DBADDR *paddr, long *no_elements, long *offset)
Obtains values from the array referenced by VAL.
=head4 put_array_info
static long put_array_info(DBADDR *paddr, long nNew)
Writes values into the array referenced by VAL.
=head4 get_units
static long get_units(DBADDR *paddr, char *units)
Retrieves EGU.
=head4 get_prec
static long get_precision(DBADDR *paddr, long *precision)
Retrieves PREC if field is VAL field. Otherwise, calls C<<< recGblGetPrec() >>>.
=head4 get_graphic_double
static long get_graphic_double(DBADDR *paddr, struct dbr_grDouble *pgd)
Sets the upper display and lower display limits for a field. If the field is VAL
the limits are set to HOPR and LOPR, else if the field has upper and lower
limits defined they will be used, else the upper and lower maximum values for
the field type will be used.
Sets the following values:
upper_disp_limit = HOPR
lower_disp_limit = LOPR
=head4 get_control_double
static long get_control_double(DBADDR *paddr, struct dbr_ctrlDouble *pcd)
Sets the upper control and the lower control limits for a field. If the field is
VAL the limits are set to HOPR and LOPR, else if the field has upper and lower
limits defined they will be used, else the upper and lower maximum values for
the field type will be used.
Sets the following values
upper_ctrl_limit = HOPR
lower_ctrl_limit = LOPR
=head3 Record Processing
Routine process implements the following algorithm:
=over
=item 1.
Check to see that the appropriate device support module exists. If it doesn't,
an error message is issued and processing is terminated with the PACT field
still set to TRUE. This ensures that processes will no longer be called for this
record. Thus error storms will not occur.
=item 2.
Call device support write routine C<write_aao>.
=item 3.
If PACT has been changed to TRUE, the device support read routine has started
but has not completed writing the new value. In this case, the processing
routine merely returns, leaving PACT TRUE.
=item 4.
Check to see if monitors should be invoked.
=over
=item *
Alarm monitors are invoked if the alarm status or severity has changed.
=item *
Archive and value change monitors are invoked if APST or MPST are Always or if
the result of the hash calculation is different.
=item *
NSEV and NSTA are reset to 0.
=back
=item 5.
Scan forward link if necessary, set PACT FALSE, and return.
=back
=begin html
<br>
<hr>
<br>
=end html
=cut
include "dbCommon.dbd"
field(VAL,DBF_NOACCESS) {
prompt("Value")
asl(ASL0)
special(SPC_DBADDR)
pp(TRUE)
extra("void * val")
#=type DOUBLE[]
#=read Yes
#=write Yes
}
field(PREC,DBF_SHORT) {
prompt("Display Precision")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(OUT,DBF_OUTLINK) {
prompt("Output Specification")
promptgroup("50 - Output")
interest(1)
}
field(EGU,DBF_STRING) {
prompt("Engineering Units")
promptgroup("80 - Display")
interest(1)
size(16)
prop(YES)
}
field(HOPR,DBF_DOUBLE) {
prompt("High Operating Range")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(LOPR,DBF_DOUBLE) {
prompt("Low Operating Range")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(NELM,DBF_ULONG) {
prompt("Number of Elements")
promptgroup("30 - Action")
special(SPC_NOMOD)
interest(1)
initial("1")
}
field(FTVL,DBF_MENU) {
prompt("Field Type of Value")
promptgroup("30 - Action")
special(SPC_NOMOD)
interest(1)
menu(menuFtype)
}
field(NORD,DBF_ULONG) {
prompt("Number elements read")
special(SPC_NOMOD)
}
field(BPTR,DBF_NOACCESS) {
prompt("Buffer Pointer")
special(SPC_NOMOD)
interest(4)
extra("void * bptr")
}
field(SIML,DBF_INLINK) {
prompt("Simulation Mode Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
special(SPC_MOD)
interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
prompt("Simulation Mode Severity")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
field(SIOL,DBF_OUTLINK) {
prompt("Simulation Output Link")
promptgroup("90 - Simulate")
interest(1)
}
field(OLDSIMM,DBF_MENU) {
prompt("Prev. Simulation Mode")
special(SPC_NOMOD)
interest(4)
menu(menuSimm)
}
field(SSCN,DBF_MENU) {
prompt("Sim. Mode Scan")
promptgroup("90 - Simulate")
interest(1)
menu(menuScan)
initial("65535")
}
field(SDLY,DBF_DOUBLE) {
prompt("Sim. Mode Async Delay")
promptgroup("90 - Simulate")
interest(2)
initial("-1.0")
}
%#include "callback.h"
field(SIMPVT,DBF_NOACCESS) {
prompt("Sim. Mode Private")
special(SPC_NOMOD)
interest(4)
extra("epicsCallback *simpvt")
}
field(MPST,DBF_MENU) {
prompt("Post Value Monitors")
promptgroup("80 - Display")
interest(1)
menu(aaoPOST)
}
field(APST,DBF_MENU) {
prompt("Post Archive Monitors")
promptgroup("80 - Display")
interest(1)
menu(aaoPOST)
}
field(HASH,DBF_ULONG) {
prompt("Hash of OnChange data.")
interest(3)
}
}
=head2 Device Support
=head3 Fields Of Interest To Device Support
Each array analog output record record must have an associated set of device
support routines. The primary responsibility of the device support routines is to
write the array data value whenever C<write_aao()> is called. The device support
routines are primarily interested in the following fields:
=fields PACT, DPVT, NSEV, NSTA, OUT, NELM, FTVL, BPTR, NORD
=head3 Device Support Routines
Device support consists of the following routines:
=head4 report
long report(int level)
This optional routine is called by the IOC command C<dbior> and is passed the
report level that was requested by the user.
It should print a report on the state of the device support to stdout.
The C<level> parameter may be used to output increasingly more detailed
information at higher levels, or to select different types of information with
different levels.
Level zero should print no more than a small summary.
=head4 init
long init(int after)
This optional routine is called twice at IOC initialization time.
The first call happens before any of the C<init_record()> calls are made, with
the integer parameter C<after> set to 0.
The second call happens after all of the C<init_record()> calls have been made,
with C<after> set to 1.
=head4 init_record
init_record(dbCommon *precord)
This routine is optional. If provided, it is called by the record support
C<init_record()> routine.
=head4 get_ioint_info
long get_ioint_info(int cmd, dbCommon *precord, IOSCANPVT *ppvt)
This routine is called by the ioEventScan system each time the record is added
or deleted from an I/O event scan list. cmd has the value (0,1) if the
record is being (added to, deleted from) an I/O event list. It must be
provided for any device type that can use the ioEvent scanner.
=head4 write_aao
long write_aao(dbCommon *precord)
This routine must write the array data to output. It returns the following values:
=over
=item *
0: Success.
=item *
Other: Error.
=back
=head3 Device Support For Soft Records
The C<<< Soft Channel >>> device support module is provided to write values to
other records and store them in arrays. If OUT is a constant link, then
C<write_aao()> does nothing. In this case, the record can be used to hold arrays
written via dbPuts. If OUT is a database or channel access link, the array value
is written to the link. NORD is set to the number of items in the array.
If the OUT link type is constant, then NORD is set to zero.
=cut

View File

@@ -190,7 +190,13 @@ noise.
The AFTC field sets the time constant on a low-pass filter that delays the
reporting of limit alarms until the signal has been within the alarm range for
that number of seconds (the default AFTC value of zero retains the previous
behavior).
behavior). The record must be scanned often enough for the filtering action to
work effectively and the alarm severity can only change when the record is
processed, but that processing does not have to be regular; the filter uses the
time since the record last processed in its calculation. Setting AFTC to a
positive number of seconds will delay the record going into or out of a minor
alarm severity or from minor to major severity until the input signal has been
in the alarm range for that number of seconds.
=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST, AFTC, LALM

View File

@@ -4,7 +4,7 @@
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
# in file LICENSE that is included with this distribution.
#*************************************************************************
=title Analog Output Record (ao)
@@ -104,33 +104,32 @@ The LINR field can specify C<LINEAR> or C<SLOPE> for linear conversions,
C<NO CONVERSION> for no conversions at all, or the name of a breakpoint table
such as C<typeKdegC> for breakpoint conversions.
Note that the ESLO, EOFF, EGUF, and EGUL fields are only used for linear
conversions.
Also note that none of these fields have any significance for records that use
the Soft Channel device support module.
The EGUF and EGUL fields should be set for C<LINEAR> conversions, and the ESLO
and EOFF fields for C<SLOPE> conversion. Note that none of these fields have any
significance for records that use the Soft Channel device support module.
=over
=item EGUF, EGUF
The user must calculate these fields when configuring the database for records
The user must set these fields when configuring the database for records
that use C<LINEAR> conversions.
They are used to calculate the values for ESLO and EOFF.
See Conversion Specification for more information on how to calculate these
fields.
=item ESLO, EOFF
Computed by device support from EGUF and EGUL when LINR specifies C<LINEAR>.
These values must be supplied by the user when LINR specifies C<SLOPE>.
Used only when LINR is C<LINEAR> or C<SLOPE>.
=item AOFF, ASLO
These fields are adjustment parameters for the raw output values.
They are applied to the raw output value after conversion from engineering
units.
=item ESLO, EOFF
Computed by device support using EGUF and EGUL when LINR specifies C<LINEAR>.
These values must be supplied by the user when LINR specifies C<SLOPE>.
Used only when LINR is C<LINEAR> or C<SLOPE>.
=item ROFF
This field can be used to offset the raw value generated by the conversion
@@ -168,8 +167,7 @@ addresses.
For soft records the output link can be a database link, a channel
access link, or a constant value. If the link is a constant, no output
is sent. See Address Specification for information on the format of
database and channel access addresses.
is sent.
=fields DTYP, OUT
@@ -193,8 +191,8 @@ The PREC field determines the floating point precision with which to
display VAL, OVAL and PVAL. It is used whenever the get_precision
record support routine is called.
See Fields Common to All Record Types for more on the record name
(NAME) and description (DESC) fields.
See L<Fields Common to All Record Types|dbCommonRecord/Operator Display
Parameters> for more on the record name (NAME) and description (DESC) fields.
=fields EGU, HOPR, LOPR, PREC, NAME, DESC
@@ -209,9 +207,10 @@ and LOW fields, which must be floating-point values. For each of these
fields, there is a corresponding severity field which can be either
NO_ALARM, MINOR, or MAJOR.
See Alarm Specification for a complete explanation of alarms and these
fields. See Invalid Alarm Output Action for more information on the
IVOA and IVOV fields. Alarm Fields lists other fields related to a
See L<Invalid Output Action Fields|dbCommonOutput/Invalid Output Action Fields>
for more information on the IVOA and IVOV fields.
L<Alarm Fields|dbCommonRecord/Alarm Fields> lists other fields related to a
alarms that are common to all record types.
=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST, IVOA, IVOV
@@ -260,15 +259,15 @@ processing.
=fields ORAW, RBV, ORBV, LALM, ALST, MLST, INIT, PBRK, LBRK, PVAL, OMOD
The following fields are used to operate the analog output in the
simulation mode. See Fields Common to Many Record Types for more
information on these fields.
The following fields are used when the record is in simulation mode. See
L<Fields Common to Output Record Types|dbCommonOutput/Simulation Fields> for
more information on these fields.
=fields SIOL, SIML, SIMM, SIMS
=cut
include "dbCommon.dbd"
include "dbCommon.dbd"
field(VAL,DBF_DOUBLE) {
prompt("Desired Output")
promptgroup("50 - Output")
@@ -602,6 +601,8 @@ get_precision, get_graphic_double, and get_control_double routines.
=item init_record
C<long init_record(aoRecord *prec, int pass);>
This routine initializes SIMM if SIML is a constant or creates a
channel access link if SIML is PV_LINK. If SIOL is PV_LINK a channel
access link is created.
@@ -633,10 +634,14 @@ then set to FALSE. PVAL is set to VAL.
=item process
C<long process(aoRecord *prec);>
See next section.
=item special
C<long special(DBADDR *paddr, int after);>
The only special processing for analog output records is SPC_LINCONV
which is invoked whenever either of the fields LINR, EGUF, EGUL or ROFF
is changed If the device support routine special_linconv exists it is
@@ -647,6 +652,8 @@ re-initialized.
=item get_alarm_double
C<long get_alarm_double(DBADDR *, struct dbr_alDouble *);>
Sets the following values:
upper_alarm_limit = HIHI
@@ -796,7 +803,9 @@ Device support consists of the following routines:
=over
=item C<long report(int level)>
=item report
C<long report(int level);>
This optional routine is called by the IOC command C<dbior> and is passed the
report level that was requested by the user.
@@ -806,7 +815,9 @@ information at higher levels, or to select different types of information with
different levels.
Level zero should print no more than a small summary.
=item C<long init(int after)>
=item init
C<long init(int after);>
This optional routine is called twice at IOC initialization time.
The first call happens before any of the C<init_record()> calls are made, with
@@ -814,7 +825,9 @@ the integer parameter C<after> set to 0.
The second call happens after all of the C<init_record()> calls have been made,
with C<after> set to 1.
=item C<long init_record(aoRecord *prec)>
=item init_record
C<long init_record(aoRecord *prec);>
This optional routine is called by the record initialization code for each ao
record instance that has its DTYP field set to use this device support.
@@ -836,7 +849,9 @@ should also fetch that value and put it into the record's RVAL or VAL field. The
return value should be zero if the RVAL field has been set, or 2 if either the
VAL field has been set or if the last output value cannot be retrieved.
=item C<long get_ioint_info(int cmd, aoRecord *prec, IOSCANPVT *piosl)>
=item get_ioint_info
C<long get_ioint_info(int cmd, aoRecord *prec, IOSCANPVT *piosl);>
This optional routine is called whenever the record's SCAN field is being
changed to or from the value C<I/O Intr> to find out which I/O Interrupt Scan
@@ -864,7 +879,9 @@ thread.
The C<scanIoRequest()> routine is safe to call from an interrupt service routine
on embedded architectures (vxWorks and RTEMS).
=item C<long write_ao(aoRecord *prec)>
=item write_ao
C<long write_ao(aoRecord *prec);>
This essential routine is called whenever the record has a new output value to
send to the device. It is responsible for performing the write operation, using
@@ -883,7 +900,9 @@ that happens the C<write_ao()> routine will be called again with PACT still set
to TRUE; it should then set it to FALSE to indicate the write has completed, and
return.
=item C<long special_linconv(aoRecord *prec, int after)>
=item special_linconv
C<long special_linconv(aoRecord *prec, int after);>
This optional routine should be provided if the record type's unit conversion
features are used by the device support's C<write_ao()> routine utilizing the

View File

@@ -318,10 +318,13 @@ XOR : Bitwise Exclusive Or
C<~> : One's Complement
=item *
C<<< << >>> : Left shift
C<<< << >>> : Arithmetic Left Shift
=item *
C<<< >> >>> : Right shift
C<<< >> >>> : Arithmetic Right Shift
=item *
C<<<< >>> >>>> : Logical Right Shift
=back

View File

@@ -350,10 +350,13 @@ XOR : Bitwise Exclusive Or
C<~> : One's Complement
=item *
C<<< << >>> : Left shift
C<<< << >>> : Arithmetic Left Shift
=item *
C<<< >> >>> : Right shift
C<<< >> >>> : Arithmetic Right Shift
=item *
C<<<< >>> >>>> : Logical Right Shift
=back

View File

@@ -4,7 +4,7 @@
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* recEvent.c - Record Support Routines for Event records */
@@ -103,7 +103,7 @@ static long init_record(struct dbCommon *pcommon, int pass)
recGblInitSimm(pcommon, &prec->sscn, &prec->oldsimm, &prec->simm, &prec->siml);
recGblInitConstantLink(&prec->siol, DBF_STRING, &prec->sval);
if( (pdset=(struct eventdset *)(prec->dset)) && (pdset->init_record) )
if( (pdset=(struct eventdset *)(prec->dset)) && (pdset->init_record) )
status=(*pdset->init_record)(prec);
prec->epvt = eventNameToHandle(prec->val);
@@ -118,12 +118,12 @@ static long process(struct dbCommon *pcommon)
long status=0;
unsigned char pact=prec->pact;
if((pdset!=NULL) && (pdset->number >= 5) && pdset->read_event )
if((pdset!=NULL) && (pdset->number >= 5) && pdset->read_event )
status=readValue(prec); /* read the new value */
/* check if device support set pact */
if ( !pact && prec->pact ) return(0);
prec->pact = TRUE;
postEvent(prec->epvt);
recGblGetTimeStampSimm(prec, prec->simm, &prec->siol);

View File

@@ -133,33 +133,28 @@ static void wdogCallback(epicsCallback *arg)
return;
}
static long wdogInit(histogramRecord *prec)
static void wdogInit(histogramRecord *prec)
{
myCallback *pcallback;
if (!prec->wdog && prec->sdel > 0) {
/* initialize a callback object */
pcallback = calloc(1, sizeof(myCallback));
pcallback->prec = prec;
if (!pcallback)
return -1;
callbackSetCallback(wdogCallback, &pcallback->callback);
callbackSetUser(pcallback, &pcallback->callback);
callbackSetPriority(priorityLow, &pcallback->callback);
prec->wdog = pcallback;
}
if (!prec->wdog)
return -1;
pcallback = prec->wdog;
if (!pcallback)
return -1;
if (prec->sdel > 0) {
myCallback *pcallback = prec->wdog;
if (!pcallback) {
/* initialize a callback object */
pcallback = calloc(1, sizeof(myCallback));
if (!pcallback)
return;
pcallback->prec = prec;
callbackSetCallback(wdogCallback, &pcallback->callback);
callbackSetUser(pcallback, &pcallback->callback);
callbackSetPriority(priorityLow, &pcallback->callback);
prec->wdog = pcallback;
}
/* start new timer on monitor */
callbackRequestDelayed(&pcallback->callback, prec->sdel);
}
return 0;
}
static long init_record(struct dbCommon *pcommon, int pass)

View File

@@ -1,173 +0,0 @@
#*************************************************************************
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
menu(histogramCMD) {
choice(histogramCMD_Read,"Read")
choice(histogramCMD_Clear,"Clear")
choice(histogramCMD_Start,"Start")
choice(histogramCMD_Stop,"Stop")
}
recordtype(histogram) {
include "dbCommon.dbd"
field(VAL,DBF_NOACCESS) {
prompt("Value")
asl(ASL0)
special(SPC_DBADDR)
extra("void * val")
#=type ULONG[]
#=read Yes
#=write Yes
}
field(NELM,DBF_USHORT) {
prompt("Num of Array Elements")
promptgroup("30 - Action")
special(SPC_NOMOD)
interest(1)
initial("1")
}
field(CSTA,DBF_SHORT) {
prompt("Collection Status")
special(SPC_NOMOD)
interest(1)
initial("1")
}
field(CMD,DBF_MENU) {
prompt("Collection Control")
asl(ASL0)
special(SPC_CALC)
interest(1)
menu(histogramCMD)
}
field(ULIM,DBF_DOUBLE) {
prompt("Upper Signal Limit")
promptgroup("30 - Action")
special(SPC_RESET)
interest(1)
prop(YES)
}
field(LLIM,DBF_DOUBLE) {
prompt("Lower Signal Limit ")
promptgroup("30 - Action")
special(SPC_RESET)
interest(1)
prop(YES)
}
field(WDTH,DBF_DOUBLE) {
prompt("Element Width")
special(SPC_NOMOD)
interest(3)
}
field(SGNL,DBF_DOUBLE) {
prompt("Signal Value")
special(SPC_MOD)
}
field(PREC,DBF_SHORT) {
prompt("Display Precision")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(SVL,DBF_INLINK) {
prompt("Signal Value Location")
promptgroup("40 - Input")
interest(1)
}
field(BPTR,DBF_NOACCESS) {
prompt("Buffer Pointer")
special(SPC_NOMOD)
interest(4)
extra("epicsUInt32 *bptr")
}
field(WDOG,DBF_NOACCESS) {
prompt("Watchdog callback")
special(SPC_NOMOD)
interest(4)
extra("void * wdog")
}
field(MDEL,DBF_SHORT) {
prompt("Monitor Count Deadband")
promptgroup("80 - Display")
interest(1)
}
field(MCNT,DBF_SHORT) {
prompt("Counts Since Monitor")
special(SPC_NOMOD)
interest(3)
}
field(SDEL,DBF_DOUBLE) {
prompt("Monitor Seconds Dband")
promptgroup("80 - Display")
special(SPC_RESET)
interest(1)
}
field(SIOL,DBF_INLINK) {
prompt("Simulation Input Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SVAL,DBF_DOUBLE) {
prompt("Simulation Value")
}
field(SIML,DBF_INLINK) {
prompt("Simulation Mode Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
special(SPC_MOD)
interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
prompt("Simulation Mode Severity")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
field(OLDSIMM,DBF_MENU) {
prompt("Prev. Simulation Mode")
special(SPC_NOMOD)
interest(4)
menu(menuSimm)
}
field(SSCN,DBF_MENU) {
prompt("Sim. Mode Scan")
promptgroup("90 - Simulate")
interest(1)
menu(menuScan)
initial("65535")
}
field(SDLY,DBF_DOUBLE) {
prompt("Sim. Mode Async Delay")
promptgroup("90 - Simulate")
interest(2)
initial("-1.0")
}
%#include "callback.h"
field(SIMPVT,DBF_NOACCESS) {
prompt("Sim. Mode Private")
special(SPC_NOMOD)
interest(4)
extra("epicsCallback *simpvt")
}
field(HOPR,DBF_ULONG) {
prompt("High Operating Range")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(LOPR,DBF_ULONG) {
prompt("Low Operating Range")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
}
variable(histogramSDELprecision, int)

View File

@@ -0,0 +1,445 @@
#*************************************************************************
# Copyright (c) 2002 The University of Chicago, as Operator of Argonne
# National Laboratory.
# Copyright (c) 2002 The Regents of the University of California, as
# Operator of Los Alamos National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
=title Histogram Record (histogram)
The histogram record is used to store frequency counts of a signal into an array
of arbitrary length. The user can configure the range of the signal value that
the array will store. Anything outside this range will be ignored.
=head2 Parameter Fields
The record-specific fields are described below.
=recordtype histogram
=cut
menu(histogramCMD) {
choice(histogramCMD_Read,"Read")
choice(histogramCMD_Clear,"Clear")
choice(histogramCMD_Start,"Start")
choice(histogramCMD_Stop,"Stop")
}
recordtype(histogram) {
=head3 Read Parameters
The SVL is the input link where the record reads its value. It can be a
constant, a database link, or a channel access link. If SVL is a database or
channel access link, then SGNL is read from SVL. If SVL is a constant, then SGNL
is initialized with the constant value but can be changed via dbPuts. The C<Soft
Channel> device support module can be specified in the DTYP field.
The ULIM and LLIM fields determine the usable range of signal values. Any value
of SGNL below LLIM or above ULIM is outside the range and will not be stored in
the array. In the NELM field the user must specify the array size, e.g., the
number of array elements. Each element in the NELM field holds the counts for an
interval of the range of signal counts, the range specified by ULIM and LLIM.
These intervals are determined by dividing the range by NELM:
(ULIM - LLIM) / NELM.
=fields SVL, SGNL, DTYP, NELM, ULIM, LLIM
=head3 Operator Display Parameters
These parameters are used to present meaningful data to the operator. These
fields are used to display the value and other parameters of the histogram
either textually or graphically. See L<Fields Common to All Record Types> for
more on the record name (NAME) and description (DESC) fields.
=fields NAME, DESC
=head3 Alarm Parameters
The Histogram record has the alarm parameters common to all record types.
L<Alarm Fields> lists other fields related to a alarms that are common to all
record types.
=head3 Monitor Parameters
The MDEL field implements the monitor count deadband. Only when MCNT is greater
than the value given to MDEL are monitors triggered, MCNT being the number of
counts since the last time the record was processed. If MDEL is -1, everytime
the record is processed, a monitor is triggered regardless.
If SDEL is greater than 0, it causes a callback routine to be called. The number
specified in SDEL is the callback routines interval. The callback routine is
called every SDEL seconds. The callback routine posts an event if MCNT is
greater than 0.
=fields MDEL, SDEL
=head3 Run-time and Simulation Mode Parameters
These parameters are used by the run-time code for processing the histogram.
They are not configurable by the user prior to run-time. They represent the
current state of the record. Many of them are used to process the histogram more
efficiently.
The BPTR field contains a pointer to the unsigned long array of frequency
values. The VAL field references this array as well. However, the BPTR field is
not accessible at run-time.
The MCNT field keeps counts the number of signal counts since the last monitor
was invoked.
The collections controls field (CMD) is a menu field with five choices:
=menu histogramCMD
When CMD is C<Read>, the record retrieves its values and adds them to the signal
array. This command will first clear the signal counts which have already been
read when it is first invoked.
The C<Clear> command erases the signal counts, setting the elements in the array
back to zero. Afterwards, the CMD field is set back to C<Read>.
The C<Start> command simply causes the record to read signal values into the
array. Unlike C<Read>, it doesn't clear the array first.
The C<Stop> command disables the reading of signal values into the array.
The C<Setup> command waits until the C<start> or C<read> command has been issued
to start counting.
The CSTA or collections status field implements the CMD field choices by
enabling or disabling the reading of values into the histogram array. While
FALSE, no signals are added to the array. While TRUE, signals are read and added
to the array. The field is initialized to TRUE. The C<Stop> command is the only
command that sets CSTA to FALSE. On the other hand, the C<Start> command is the
only command that sets it to TRUE. Thus, C<Start> must be invoked after each
C<Stop> command in order to enable counting; invoking C<Read> will not enable
signal counting after C<Stop> has been invoked.
A typical use of these fields would be to initialize the CMD field to C<Read>
(it is initialized to this command by default), to use the C<Stop> command to
disable counting when necessary, after which the C<Start> command can be invoked
to re-start the signal count.
The WDTH field is a private field that holds the signal width of the array
elements. For instance, if the LLIM was configured to be 4.0 and ULIM was
configured to be 12.0 and the NELM was set to 4, then the WDTH for each array
would be 2. Thus, it is (ULIM - LLIM) / NELM.
=fields BPTR, VAL, MCNT, CMD, CSTA, WDTH
The following fields are used to operate the histogram record in simulation
mode. See L<Fields Common to Many Record Types> for more information on the
simulation mode fields.
=fields SIOL, SVAL, SIML, SIMM, SIMS
=cut
include "dbCommon.dbd"
field(VAL,DBF_NOACCESS) {
prompt("Value")
asl(ASL0)
special(SPC_DBADDR)
extra("void * val")
#=type ULONG[]
#=read Yes
#=write Yes
}
field(NELM,DBF_USHORT) {
prompt("Num of Array Elements")
promptgroup("30 - Action")
special(SPC_NOMOD)
interest(1)
initial("1")
}
field(CSTA,DBF_SHORT) {
prompt("Collection Status")
special(SPC_NOMOD)
interest(1)
initial("1")
}
field(CMD,DBF_MENU) {
prompt("Collection Control")
asl(ASL0)
special(SPC_CALC)
interest(1)
menu(histogramCMD)
}
field(ULIM,DBF_DOUBLE) {
prompt("Upper Signal Limit")
promptgroup("30 - Action")
special(SPC_RESET)
interest(1)
prop(YES)
}
field(LLIM,DBF_DOUBLE) {
prompt("Lower Signal Limit ")
promptgroup("30 - Action")
special(SPC_RESET)
interest(1)
prop(YES)
}
field(WDTH,DBF_DOUBLE) {
prompt("Element Width")
special(SPC_NOMOD)
interest(3)
}
field(SGNL,DBF_DOUBLE) {
prompt("Signal Value")
special(SPC_MOD)
}
field(PREC,DBF_SHORT) {
prompt("Display Precision")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(SVL,DBF_INLINK) {
prompt("Signal Value Location")
promptgroup("40 - Input")
interest(1)
}
field(BPTR,DBF_NOACCESS) {
prompt("Buffer Pointer")
special(SPC_NOMOD)
interest(4)
extra("epicsUInt32 *bptr")
}
field(WDOG,DBF_NOACCESS) {
prompt("Watchdog callback")
special(SPC_NOMOD)
interest(4)
extra("void * wdog")
}
field(MDEL,DBF_SHORT) {
prompt("Monitor Count Deadband")
promptgroup("80 - Display")
interest(1)
}
field(MCNT,DBF_SHORT) {
prompt("Counts Since Monitor")
special(SPC_NOMOD)
interest(3)
}
field(SDEL,DBF_DOUBLE) {
prompt("Monitor Seconds Dband")
promptgroup("80 - Display")
special(SPC_RESET)
interest(1)
}
field(SIOL,DBF_INLINK) {
prompt("Simulation Input Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SVAL,DBF_DOUBLE) {
prompt("Simulation Value")
}
field(SIML,DBF_INLINK) {
prompt("Simulation Mode Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
special(SPC_MOD)
interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
prompt("Simulation Mode Severity")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
field(OLDSIMM,DBF_MENU) {
prompt("Prev. Simulation Mode")
special(SPC_NOMOD)
interest(4)
menu(menuSimm)
}
field(SSCN,DBF_MENU) {
prompt("Sim. Mode Scan")
promptgroup("90 - Simulate")
interest(1)
menu(menuScan)
initial("65535")
}
field(SDLY,DBF_DOUBLE) {
prompt("Sim. Mode Async Delay")
promptgroup("90 - Simulate")
interest(2)
initial("-1.0")
}
%#include "callback.h"
field(SIMPVT,DBF_NOACCESS) {
prompt("Sim. Mode Private")
special(SPC_NOMOD)
interest(4)
extra("epicsCallback *simpvt")
}
field(HOPR,DBF_ULONG) {
prompt("High Operating Range")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
field(LOPR,DBF_ULONG) {
prompt("Low Operating Range")
promptgroup("80 - Display")
interest(1)
prop(YES)
}
=head2 Record Support
=head3 Record Support Routines
=head4 init_record
Using NELM, space for the unsigned long array is allocated and the width WDTH of
the array is calculated.
This routine initializes SIMM with the value of SIML if SIML type is CONSTANT
link or creates a channel access link if SIML type is PV_LINK. SVAL is likewise
initialized if SIOL is CONSTANT or PV_LINK.
This routine next checks to see that device support and a device support read
routine are available. If device support includes C<init_record()>, it is
called.
=head4 process
See next section.
=head4 special
Special is invoked whenever the fields CMD, SGNL, ULIM, or LLIM are changed.
If SGNL is changed, add_count is called.
If ULIM or LLIM are changed, WDTH is recalculated and clear_histogram is called.
If CMD is less or equal to 1, clear_histogram is called and CMD is reset to 0.
If CMD is 2, CSTA is set to TRUE and CMD is reset to 0. If CMD is 3, CSTA is set
to FALSE and CMD is reset to 0.
clear_histogram zeros out the histogram array. add_count increments the
frequency in the histogram array.
=head4 cvt_dbaddr
This is called by dbNameToAddr. It makes the dbAddr structure refer to the
actual buffer holding the array.
=head4 get_array_info
Obtains values from the array referenced by VAL.
=head4 put_array_info
Writes values into the array referenced by VAL.
=head3 Record Processing
Routine process implements the following algorithm:
=over
=item 1.
Check to see that the appropriate device support module exists. If it doesn't,
an error message is issued and processing is terminated with the PACT field set
to TRUE. This ensures that processes will no longer be called for this record.
Thus error storms will not occur.
=item 2.
readValue is called. See L<Input Records> for more information
=item 3.
If PACT has been changed to TRUE, the device support read routine has started
but has not completed writing the new value. In this case, the processing
routine merely returns, leaving PACT TRUE.
=item 4.
Add count to histogram array.
=item 5.
Check to see if monitors should be invoked. Alarm monitors are invoked if the
alarm status or severity has changed. Archive and value change monitors are
invoked if MDEL conditions are met. NSEV and NSTA are reset to 0.
=item 6.
Scan forward link if necessary, set PACT and INIT to FALSE, and return.
=back
=head2 Device Support
=head3 Fields Of Interest To Device Support
The device support routines are primarily interested in the following fields:
=fields PACT, DPVT, UDF, NSEV, NSTA, SVL, SGNL
=head3 Device Support Routines
Device support consists of the following routines:
=head4 long report(int level)
This optional routine is called by the IOC command C<dbior> and is passed the
report level that was requested by the user.
It should print a report on the state of the device support to stdout.
The C<level> parameter may be used to output increasingly more detailed
information at higher levels, or to select different types of information with
different levels.
Level zero should print no more than a small summary.
=head4 long init(int after)
This optional routine is called twice at IOC initialization time.
The first call happens before any of the C<init_record()> calls are made, with
the integer parameter C<after> set to 0.
The second call happens after all of the C<init_record()> calls have been made,
with C<after> set to 1.
=head4 init_record
init_record(precord)
This routine is called by the record support C<init_record()> routine. It makes
sure that SGNL is a CONSTANT, PV_LINK, DB_LINK, or CA_LINK. It also retrieves a
value for SVL from SGNL. If SGNL is none of the above, an error is generated.
=head4 read_histogram
read_histogram(*precord)
This routine is called by the record support routines. It retrieves a value for
SVL from SGNL.
=head3 Device Support For Soft Records
Only the device support module C<Soft Channel> is currently provided, though
other device support modules may be provided at the user's site.
=head4 Soft Channel
The C<Soft Channel> device support routine retrieves a value from SGNL. SGNL
must be CONSTANT, PV_LINK, DB_LINK, or CA_LINK.
=cut
}
variable(histogramSDELprecision, int)

View File

@@ -1,115 +0,0 @@
#*************************************************************************
# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
recordtype(lsi) {
include "dbCommon.dbd"
%#include "devSup.h"
%
%/* Declare Device Support Entry Table */
%typedef struct lsidset {
% long number;
% DEVSUPFUN report;
% DEVSUPFUN init;
% DEVSUPFUN init_record;
% DEVSUPFUN get_ioint_info;
% DEVSUPFUN read_string;
%} lsidset;
%
field(VAL,DBF_NOACCESS) {
prompt("Current Value")
asl(ASL0)
pp(TRUE)
special(SPC_DBADDR)
extra("char *val")
}
field(OVAL,DBF_NOACCESS) {
prompt("Old Value")
special(SPC_DBADDR)
interest(3)
extra("char *oval")
}
field(SIZV,DBF_USHORT) {
prompt("Size of buffers")
promptgroup("40 - Input")
special(SPC_NOMOD)
interest(1)
initial("41")
}
field(LEN,DBF_ULONG) {
prompt("Length of VAL")
special(SPC_NOMOD)
}
field(OLEN,DBF_ULONG) {
prompt("Length of OVAL")
special(SPC_NOMOD)
}
field(INP,DBF_INLINK) {
prompt("Input Specification")
promptgroup("40 - Input")
interest(1)
}
field(MPST,DBF_MENU) {
prompt("Post Value Monitors")
promptgroup("80 - Display")
interest(1)
menu(menuPost)
}
field(APST,DBF_MENU) {
prompt("Post Archive Monitors")
promptgroup("80 - Display")
interest(1)
menu(menuPost)
}
field(SIML,DBF_INLINK) {
prompt("Simulation Mode Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
special(SPC_MOD)
interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
prompt("Simulation Mode Severity")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
field(SIOL,DBF_INLINK) {
prompt("Simulation Input Link")
promptgroup("90 - Simulate")
interest(1)
}
field(OLDSIMM,DBF_MENU) {
prompt("Prev. Simulation Mode")
special(SPC_NOMOD)
interest(4)
menu(menuSimm)
}
field(SSCN,DBF_MENU) {
prompt("Sim. Mode Scan")
promptgroup("90 - Simulate")
interest(1)
menu(menuScan)
initial("65535")
}
field(SDLY,DBF_DOUBLE) {
prompt("Sim. Mode Async Delay")
promptgroup("90 - Simulate")
interest(2)
initial("-1.0")
}
%#include "callback.h"
field(SIMPVT,DBF_NOACCESS) {
prompt("Sim. Mode Private")
special(SPC_NOMOD)
interest(4)
extra("epicsCallback *simpvt")
}
}

View File

@@ -0,0 +1,234 @@
#*************************************************************************
# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
=title Long String Input Record (lsi)
The long string input record is used to retrieve an arbitrary ASCII string with
a maximum length of 65535 characters.
=head2 Parameter Fields
The record-specific fields are described below, grouped by functionality.
=recordtype lsi
=cut
recordtype(lsi) {
=head3 Scan Parameters
The long string input record has the standard fields for specifying under what
circumstances it will be processed. These fields are listed in L<Scan Fields>.
In addition, L<Scanning Specification> explains how these fields are used.
=head3 Input Specification
The INP field determines where the long string input record obtains its string
from. It can be a database or channel access link, or a constant. If constant,
the VAL field is initialized with the constant and can be changed via dbPuts.
Otherwise, the string is read from the specified location each time the record
is processed and placed in the VAL field. The maximum number of characters in
VAL is given by SIZV, and cannot be larger than 65535. In addition, the
appropriate device support module must be entered into the DTYP field.
See L<Address Specification> for information on specifying links.
=fields VAL, OVAL, SIZV, INP, DTYP
=cut
include "dbCommon.dbd"
%#include "devSup.h"
%
%/* Declare Device Support Entry Table */
%typedef struct lsidset {
% long number;
% DEVSUPFUN report;
% DEVSUPFUN init;
% DEVSUPFUN init_record;
% DEVSUPFUN get_ioint_info;
% DEVSUPFUN read_string;
%} lsidset;
%
field(VAL,DBF_NOACCESS) {
prompt("Current Value")
asl(ASL0)
pp(TRUE)
special(SPC_DBADDR)
extra("char *val")
#=type STRING[SIZV]
#=read Yes
#=write Yes
}
field(OVAL,DBF_NOACCESS) {
prompt("Old Value")
special(SPC_DBADDR)
interest(3)
extra("char *oval")
#=type STRING[SIZV]
#=read Yes
#=write No
}
field(SIZV,DBF_USHORT) {
prompt("Size of buffers")
promptgroup("40 - Input")
special(SPC_NOMOD)
interest(1)
initial("41")
}
field(LEN,DBF_ULONG) {
prompt("Length of VAL")
special(SPC_NOMOD)
}
field(OLEN,DBF_ULONG) {
prompt("Length of OVAL")
special(SPC_NOMOD)
}
field(INP,DBF_INLINK) {
prompt("Input Specification")
promptgroup("40 - Input")
interest(1)
}
=head3 Monitor Parameters
These parameters are used to specify when the monitor post should be sent by the
C<monitor()> routine. There are two possible choices:
APST is used for archiver monitors and MPST for all other type of monitors.
=fields MPST, APST
=cut
field(MPST,DBF_MENU) {
prompt("Post Value Monitors")
promptgroup("80 - Display")
interest(1)
menu(menuPost)
}
field(APST,DBF_MENU) {
prompt("Post Archive Monitors")
promptgroup("80 - Display")
interest(1)
menu(menuPost)
}
=head3 Operator Display Parameters
See L<Fields Common to All Record Types> for more on the record name (NAME) and
description (DESC) fields.
=fields NAME, DESC
=head3 Alarm Parameters
The long string input record has the alarm parameters common to all record
types. L<Alarm Fields> lists other fields related to a alarms that are common to
all record types.
=head3 Run-time and Simulation Mode Parameters
The old value field (OVAL) of the long string input record is used to implement
value change monitors for VAL. If VAL is not equal to OVAL, then monitors are
triggered. LEN contains the length of the string in VAL, OLEN contains the
length of the string in OVAL.
=fields OVAL, LEN, OLEN
The following fields are used to operate the string input in the simulation
mode. See L<Simulation Mode> for more information on simulation mode fields.
=fields SIOL, SIML, SIMM, SIMS
=cut
field(SIML,DBF_INLINK) {
prompt("Simulation Mode Link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
special(SPC_MOD)
interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
prompt("Simulation Mode Severity")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
field(SIOL,DBF_INLINK) {
prompt("Simulation Input Link")
promptgroup("90 - Simulate")
interest(1)
}
field(OLDSIMM,DBF_MENU) {
prompt("Prev. Simulation Mode")
special(SPC_NOMOD)
interest(4)
menu(menuSimm)
}
field(SSCN,DBF_MENU) {
prompt("Sim. Mode Scan")
promptgroup("90 - Simulate")
interest(1)
menu(menuScan)
initial("65535")
}
field(SDLY,DBF_DOUBLE) {
prompt("Sim. Mode Async Delay")
promptgroup("90 - Simulate")
interest(2)
initial("-1.0")
}
%#include "callback.h"
field(SIMPVT,DBF_NOACCESS) {
prompt("Sim. Mode Private")
special(SPC_NOMOD)
interest(4)
extra("epicsCallback *simpvt")
}
}
=head2 Device Support Interface
The record requires device support to provide an entry table (dset) which
defines the following members:
typedef struct {
long number;
long (*report)(int level);
long (*init)(int after);
long (*init_record)(lsiRecord *prec);
long (*get_ioint_info)(int cmd, lsiRecord *prec, IOSCANPVT *piosl);
long (*read_string)(lsiRecord *prec);
} lsidset;
The module must set C<number> to at least 5, and provide a pointer to its
C<read_string()> routine; the other function pointers may be C<NULL> if their
associated functionality is not required for this support layer.
Most device supports also provide an C<init_record()> routine to configure the
record instance and connect it to the hardware or driver support layer.
=head2 Device Support for Soft Records
A device support module for DTYP C<Soft Channel> is provided for retrieving
values from other records or other software components.
Device support for DTYP C<getenv> is provided for retrieving strings from
environment variables. C<INST_IO> addressing C<< @<environment variable> >> is
used on the C<INP> link field to select the desired environment variable.
=cut

View File

@@ -1,139 +0,0 @@
#*************************************************************************
# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
recordtype(lso) {
include "dbCommon.dbd"
%#include "devSup.h"
%
%/* Declare Device Support Entry Table */
%typedef struct lsodset {
% long number;
% DEVSUPFUN report;
% DEVSUPFUN init;
% DEVSUPFUN init_record;
% DEVSUPFUN get_ioint_info;
% DEVSUPFUN write_string;
%} lsodset;
%
field(VAL,DBF_NOACCESS) {
prompt("Current Value")
asl(ASL0)
pp(TRUE)
special(SPC_DBADDR)
extra("char *val")
}
field(OVAL,DBF_NOACCESS) {
prompt("Previous Value")
special(SPC_DBADDR)
interest(3)
extra("char *oval")
}
field(SIZV,DBF_USHORT) {
prompt("Size of buffers")
promptgroup("50 - Output")
special(SPC_NOMOD)
interest(1)
initial("41")
}
field(LEN,DBF_ULONG) {
prompt("Length of VAL")
special(SPC_NOMOD)
}
field(OLEN,DBF_ULONG) {
prompt("Length of OVAL")
special(SPC_NOMOD)
interest(3)
}
field(DOL,DBF_INLINK) {
prompt("Desired Output Link")
promptgroup("40 - Input")
interest(1)
}
field(IVOA,DBF_MENU) {
prompt("INVALID Output Action")
promptgroup("50 - Output")
interest(2)
menu(menuIvoa)
}
field(IVOV,DBF_STRING) {
prompt("INVALID Output Value")
promptgroup("50 - Output")
interest(2)
size(40)
}
field(OMSL,DBF_MENU) {
prompt("Output Mode Select")
promptgroup("50 - Output")
interest(1)
menu(menuOmsl)
}
field(OUT,DBF_OUTLINK) {
prompt("Output Specification")
promptgroup("50 - Output")
interest(1)
}
field(MPST,DBF_MENU) {
prompt("Post Value Monitors")
promptgroup("80 - Display")
interest(1)
menu(menuPost)
}
field(APST,DBF_MENU) {
prompt("Post Archive Monitors")
promptgroup("80 - Display")
interest(1)
menu(menuPost)
}
field(SIML,DBF_INLINK) {
prompt("Simulation Mode link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
special(SPC_MOD)
interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
prompt("Simulation Mode Severity")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
field(SIOL,DBF_OUTLINK) {
prompt("Simulation Output Link")
promptgroup("90 - Simulate")
interest(1)
}
field(OLDSIMM,DBF_MENU) {
prompt("Prev. Simulation Mode")
special(SPC_NOMOD)
interest(4)
menu(menuSimm)
}
field(SSCN,DBF_MENU) {
prompt("Sim. Mode Scan")
promptgroup("90 - Simulate")
interest(1)
menu(menuScan)
initial("65535")
}
field(SDLY,DBF_DOUBLE) {
prompt("Sim. Mode Async Delay")
promptgroup("90 - Simulate")
interest(2)
initial("-1.0")
}
%#include "callback.h"
field(SIMPVT,DBF_NOACCESS) {
prompt("Sim. Mode Private")
special(SPC_NOMOD)
interest(4)
extra("epicsCallback *simpvt")
}
}

View File

@@ -0,0 +1,293 @@
#*************************************************************************
# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
=title Long String Output Record (lso)
The long string output record is used to write an arbitrary ASCII string with a
maximum length of 65535 characters.
=head2 Parameter Fields
The record-specific fields are described below, grouped by functionality.
=recordtype lso
=cut
include "menuIvoa.dbd"
recordtype(lso) {
=head3 Scan Parameters
The long string output record has the standard fields for specifying under what
circumstances it will be processed. These fields are listed in L<Scan Fields>.
In addition, L<Scanning Specification> explains how these fields are used.
=head3 Desired Output Parameters
The long string output record must specify from where it gets its desired output
string. The first field that determines where the desired output originates is
the output mode select (OMSL) field, which can have two possible value:
C<closed_loop> or C<supervisory>. If C<supervisory> is specified, DOL is
ignored, the current value of VAL is written, and VAL can be changed externally
via dbPuts at run-time. If C<closed_loop> is specified, the VAL field's value is
obtained from the address specified in the desired output location field (DOL)
which can be either a database link or a channel access link.
The maximum number of characters in VAL is given by SIZV, and cannot be larger
than 65535.
DOL can also be a constant in addition to a link, in which case VAL is
initialized to the constant value. Your string constant, however, may be
interpreted as a CA link name. If you want to initialize your string output
record, it is therefore best to use the VAL field. Note that if DOL is a
constant, OMSL cannot be C<closed_loop>.
See L<Address Specification> for information on specifying links.
=fields VAL, SIZV, DOL, OMSL
=head3 Output Specification
The output link specified in the OUT field specifies where the long string
output record is to write its string. The link can be a database or channel
access link. If the OUT field is a constant, no output will be written.
See L<Address Specification> for information on specifying links.
In addition, the appropriate device support module must be entered into the DTYP
field.
=fields OUT, DTYP
=head3 Monitor Parameters
These parameters are used to specify when the monitor post should be sent by the
C<monitor()> routine. There are two possible choices:
APST is used for archiver monitors and MPST for all other type of monitors.
=fields MPST, APST
=head3 Operator Display Parameters
See L<Fields Common to All Record Types> for more on the record name (NAME) and
description (DESC) fields.
=fields NAME, DESC
=head3 Alarm Parameters
The long string input record has the alarm parameters common to all record
types. L<Alarm Fields> lists other fields related to a alarms that are common to
all record types.
The IVOA field specifies an action to take when the INVALID alarm is triggered.
There are three possible actions:
=head4 Menu menuIvoa
=menu menuIvoa
When C<<< Set output to IVOV >>>, the value contained in the IVOV field is
written to the output link during an alarm condition. See
L<Invalid Alarm Output Action>
for more information on the IVOA and IVOV fields.
L<Alarm Fields>
lists other fields related to a alarms that are common to all record types.
=fields IVOA, IVOV
=cut
include "dbCommon.dbd"
%#include "devSup.h"
%
%/* Declare Device Support Entry Table */
%typedef struct lsodset {
% long number;
% DEVSUPFUN report;
% DEVSUPFUN init;
% DEVSUPFUN init_record;
% DEVSUPFUN get_ioint_info;
% DEVSUPFUN write_string;
%} lsodset;
%
field(VAL,DBF_NOACCESS) {
prompt("Current Value")
asl(ASL0)
pp(TRUE)
special(SPC_DBADDR)
extra("char *val")
}
field(OVAL,DBF_NOACCESS) {
prompt("Previous Value")
special(SPC_DBADDR)
interest(3)
extra("char *oval")
}
field(SIZV,DBF_USHORT) {
prompt("Size of buffers")
promptgroup("50 - Output")
special(SPC_NOMOD)
interest(1)
initial("41")
}
field(LEN,DBF_ULONG) {
prompt("Length of VAL")
special(SPC_NOMOD)
}
field(OLEN,DBF_ULONG) {
prompt("Length of OVAL")
special(SPC_NOMOD)
interest(3)
}
field(DOL,DBF_INLINK) {
prompt("Desired Output Link")
promptgroup("40 - Input")
interest(1)
}
field(IVOA,DBF_MENU) {
prompt("INVALID Output Action")
promptgroup("50 - Output")
interest(2)
menu(menuIvoa)
}
field(IVOV,DBF_STRING) {
prompt("INVALID Output Value")
promptgroup("50 - Output")
interest(2)
size(40)
}
field(OMSL,DBF_MENU) {
prompt("Output Mode Select")
promptgroup("50 - Output")
interest(1)
menu(menuOmsl)
}
field(OUT,DBF_OUTLINK) {
prompt("Output Specification")
promptgroup("50 - Output")
interest(1)
}
field(MPST,DBF_MENU) {
prompt("Post Value Monitors")
promptgroup("80 - Display")
interest(1)
menu(menuPost)
}
field(APST,DBF_MENU) {
prompt("Post Archive Monitors")
promptgroup("80 - Display")
interest(1)
menu(menuPost)
}
=head3 Run-time and Simulation Mode Parameters
The old value field (OVAL) of the long string input record is used to implement
value change monitors for VAL. If VAL is not equal to OVAL, then monitors are
triggered. LEN contains the length of the string in VAL, OLEN contains the
length of the string in OVAL.
=fields OVAL, LEN, OLEN
The following fields are used to operate the string input in the simulation
mode. See L<Simulation Mode> for more information on simulation mode fields.
=fields SIOL, SIML, SIMM, SIMS
=cut
field(SIML,DBF_INLINK) {
prompt("Simulation Mode link")
promptgroup("90 - Simulate")
interest(1)
}
field(SIMM,DBF_MENU) {
prompt("Simulation Mode")
special(SPC_MOD)
interest(1)
menu(menuYesNo)
}
field(SIMS,DBF_MENU) {
prompt("Simulation Mode Severity")
promptgroup("90 - Simulate")
interest(2)
menu(menuAlarmSevr)
}
field(SIOL,DBF_OUTLINK) {
prompt("Simulation Output Link")
promptgroup("90 - Simulate")
interest(1)
}
field(OLDSIMM,DBF_MENU) {
prompt("Prev. Simulation Mode")
special(SPC_NOMOD)
interest(4)
menu(menuSimm)
}
field(SSCN,DBF_MENU) {
prompt("Sim. Mode Scan")
promptgroup("90 - Simulate")
interest(1)
menu(menuScan)
initial("65535")
}
field(SDLY,DBF_DOUBLE) {
prompt("Sim. Mode Async Delay")
promptgroup("90 - Simulate")
interest(2)
initial("-1.0")
}
%#include "callback.h"
field(SIMPVT,DBF_NOACCESS) {
prompt("Sim. Mode Private")
special(SPC_NOMOD)
interest(4)
extra("epicsCallback *simpvt")
}
}
=head2 Device Support Interface
The record requires device support to provide an entry table (dset) which
defines the following members:
typedef struct {
long number;
long (*report)(int level);
long (*init)(int after);
long (*init_record)(lsoRecord *prec);
long (*get_ioint_info)(int cmd, lsoRecord *prec, IOSCANPVT *piosl);
long (*write_string)(lsoRecord *prec);
} lsodset;
The module must set C<number> to at least 5, and provide a pointer to its
C<write_string()> routine; the other function pointers may be C<NULL> if their
associated functionality is not required for this support layer.
Most device supports also provide an C<init_record()> routine to configure the
record instance and connect it to the hardware or driver support layer.
=head2 Device Support for Soft Records
Device support for DTYP C<Soft Channel> is provided for writing values to other
records or other software components.
Device support for DTYP C<stdio> is provided for writing values to the stdout,
stderr, or errlog streams. C<INST_IO> addressing C<@stdout>, C<@stderr> or
C<@errlog> is used on the OUT link field to select the desired stream.
=cut

View File

@@ -1,109 +0,0 @@
#*************************************************************************
# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
recordtype(printf) {
include "dbCommon.dbd"
%#include "devSup.h"
%
%/* Declare Device Support Entry Table */
%typedef struct printfdset {
% long number;
% DEVSUPFUN report;
% DEVSUPFUN init;
% DEVSUPFUN init_record;
% DEVSUPFUN get_ioint_info;
% DEVSUPFUN write_string;
%} printfdset;
%
field(VAL,DBF_NOACCESS) {
prompt("Result")
asl(ASL0)
pp(TRUE)
special(SPC_DBADDR)
extra("char *val")
}
field(SIZV,DBF_USHORT) {
prompt("Size of VAL buffer")
promptgroup("30 - Action")
special(SPC_NOMOD)
interest(1)
initial("41")
}
field(LEN,DBF_ULONG) {
prompt("Length of VAL")
special(SPC_NOMOD)
}
field(OUT,DBF_OUTLINK) {
prompt("Output Specification")
promptgroup("50 - Output")
interest(1)
}
field(FMT,DBF_STRING) {
prompt("Format String")
promptgroup("30 - Action")
pp(TRUE)
size(81)
}
field(IVLS,DBF_STRING) {
prompt("Invalid Link String")
promptgroup("30 - Action")
size(16)
initial("LNK")
}
field(INP0,DBF_INLINK) {
prompt("Input 0")
promptgroup("40 - Input")
interest(1)
}
field(INP1,DBF_INLINK) {
prompt("Input 1")
promptgroup("40 - Input")
interest(1)
}
field(INP2,DBF_INLINK) {
prompt("Input 2")
promptgroup("40 - Input")
interest(1)
}
field(INP3,DBF_INLINK) {
prompt("Input 3")
promptgroup("40 - Input")
interest(1)
}
field(INP4,DBF_INLINK) {
prompt("Input 4")
promptgroup("40 - Input")
interest(1)
}
field(INP5,DBF_INLINK) {
prompt("Input 5")
promptgroup("40 - Input")
interest(1)
}
field(INP6,DBF_INLINK) {
prompt("Input 6")
promptgroup("40 - Input")
interest(1)
}
field(INP7,DBF_INLINK) {
prompt("Input 7")
promptgroup("40 - Input")
interest(1)
}
field(INP8,DBF_INLINK) {
prompt("Input 8")
promptgroup("40 - Input")
interest(1)
}
field(INP9,DBF_INLINK) {
prompt("Input 9")
promptgroup("40 - Input")
interest(1)
}
%/* Number of INPx fields defined */
%#define PRINTF_NLINKS 10
}

View File

@@ -0,0 +1,323 @@
#*************************************************************************
# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne
# National Laboratory.
# EPICS BASE is distributed subject to a Software License Agreement found
# in file LICENSE that is included with this distribution.
#*************************************************************************
=title Printf Record (printf)
The printf record is used to generate and write a string using a format
specification and parameters, analogous to the C C<printf()> function.
=head2 Parameter Fields
The record-specific fields are described below, grouped by functionality.
=recordtype printf
=cut
recordtype(printf) {
=head3 Scan Parameters
The printf record has the standard fields for specifying under what
circumstances it will be processed. These fields are listed in L<Scan Fields>.
In addition, L<Scanning Specification> explains how these fields are used.
=head3 String Generation Parameters
The printf record must specify the desired output string with embedded format
specifiers in the FMT field. Plain characters are copied directly to the output
string. A pair of percent characters 'C<%%>' are converted into a single percent
character in the output string. A single precent character 'C<%>' introduces a
format specifier and is followed by zero or more of the standard C<printf()>
format flags and modifiers:
=over 4
=item *
Plus ('C<+>')
=item *
Minus ('C<->')
=item *
Space ('C< >')
=item *
Hash ('C<#>')
=item *
Minimum Field Width (decimal digits or 'C<*>')
=item *
Precision ('C<.>' followed by decimal digits or 'C<*>')
=item *
Length Modifier 'C<hh>' E<ndash> Reads link as DBR_CHAR or DBR_UCHAR
=item *
Length Modifier 'C<h>' E<ndash> Reads link as DBR_SHORT or DBR_USHORT for
integer conversions, DBR_FLOAT for floating-point conversions.
=item *
Length Modifier 'C<l>' E<ndash> Reads link as DBR_LONG or DBR_ULONG for integer
conversions, array of DBR_CHAR for string conversion.
=back
The following character specifies the conversion to perform, see your operating
system's C<printf()> documentation for more details. These conversions
ultimately call the C<snprintf()> routine for the actual string conversion
process, so are subject to the behaviour of that routine.
=over 4
=item *
'C<c>' E<ndash> Convert to a character. Only single byte characters are
permitted.
=item *
'C<d>' or 'C<i>' E<ndash> Convert to a decimal integer.
=item *
'C<o>' E<ndash> Convert to an unsigned octal integer.
=item *
'C<u>' E<ndash> Convert to an unsigned decimal integer.
=item *
'C<x>' E<ndash> Convert to an unsigned hexadecimal integer, using C<abcdef>.
=item *
'C<X>' E<ndash> Convert to an unsigned hexadecimal integer, using C<ABCDEF>.
=item *
'C<e>' or 'C<E>' E<ndash> Convert to floating-point in exponent style, reading
the link as DBR_DOUBLE or DBR_FLOAT.
=item *
'C<f>' or 'C<F>' E<ndash> Convert to floating-point in fixed-point style,
reading the link as DBR_DOUBLE or DBR_FLOAT.
=item *
'C<g>' or 'C<G>' E<ndash> Convert to floating-point in general style, reading
the link as DBR_DOUBLE or DBR_FLOAT.
=item *
'C<s>' E<ndash> Insert string, reading the link as DBR_STRING or array of
DBR_CHAR.
=back
The fields INP0 ... INP9 are input links that provide the parameter values to be
formatted into the output. The format specifiers in the FMT string determine
which type of the data is requested through the appropriate input link. As with
C<printf()> a C<*> character may be used in the format to specify width and/or
precision instead of numeric literals, in which case additional input links are
used to provide the necessary integer parameter or parameters. See L<Address
Specification> for information on specifying links.
The formatted string is written to the VAL field. The maximum number of
characters in VAL is given by SIZV, and cannot be larger than 65535. The LEN
field contains the length of the formatted string in the VAL field.
=fields FMT, INP0, INP1, INP2, INP3, INP4, INP5, INP6, INP7, INP8, INP9, VAL, SIZV, LEN
=head3 Output Specification
The output link specified in the OUT field specifies where the printf record is
to write the contents of its VAL field. The link can be a database or channel
access link. If the OUT field is a constant, no output will be written.
See L<Address Specification> for information on specifying links.
In addition, the appropriate device support module must be entered into the DTYP
field.
=fields OUT, DTYP
=head3 Operator Display Parameters
See L<Fields Common to All Record Types> for more on the record name (NAME) and
description (DESC) fields.
=fields NAME, DESC
=cut
include "dbCommon.dbd"
%#include "devSup.h"
%
%/* Declare Device Support Entry Table */
%typedef struct printfdset {
% long number;
% DEVSUPFUN report;
% DEVSUPFUN init;
% DEVSUPFUN init_record;
% DEVSUPFUN get_ioint_info;
% DEVSUPFUN write_string;
%} printfdset;
%
field(VAL,DBF_NOACCESS) {
prompt("Result")
asl(ASL0)
pp(TRUE)
special(SPC_DBADDR)
extra("char *val")
#=type STRING[SIZV]
#=read Yes
#=write Yes
}
field(SIZV,DBF_USHORT) {
prompt("Size of VAL buffer")
promptgroup("30 - Action")
special(SPC_NOMOD)
interest(1)
initial("41")
}
field(LEN,DBF_ULONG) {
prompt("Length of VAL")
special(SPC_NOMOD)
}
field(OUT,DBF_OUTLINK) {
prompt("Output Specification")
promptgroup("50 - Output")
interest(1)
}
field(FMT,DBF_STRING) {
prompt("Format String")
promptgroup("30 - Action")
pp(TRUE)
size(81)
}
=head3 Alarm Parameters
The printf record has the alarm parameters common to all record types.
L<Alarm Fields> lists other fields related to a alarms that are common to all
record types.
The IVLS field specifies a string which is sent to the OUT link if if input
link data are invalid.
=fields IVLS
=cut
field(IVLS,DBF_STRING) {
prompt("Invalid Link String")
promptgroup("30 - Action")
size(16)
initial("LNK")
}
field(INP0,DBF_INLINK) {
prompt("Input 0")
promptgroup("40 - Input")
interest(1)
}
field(INP1,DBF_INLINK) {
prompt("Input 1")
promptgroup("40 - Input")
interest(1)
}
field(INP2,DBF_INLINK) {
prompt("Input 2")
promptgroup("40 - Input")
interest(1)
}
field(INP3,DBF_INLINK) {
prompt("Input 3")
promptgroup("40 - Input")
interest(1)
}
field(INP4,DBF_INLINK) {
prompt("Input 4")
promptgroup("40 - Input")
interest(1)
}
field(INP5,DBF_INLINK) {
prompt("Input 5")
promptgroup("40 - Input")
interest(1)
}
field(INP6,DBF_INLINK) {
prompt("Input 6")
promptgroup("40 - Input")
interest(1)
}
field(INP7,DBF_INLINK) {
prompt("Input 7")
promptgroup("40 - Input")
interest(1)
}
field(INP8,DBF_INLINK) {
prompt("Input 8")
promptgroup("40 - Input")
interest(1)
}
field(INP9,DBF_INLINK) {
prompt("Input 9")
promptgroup("40 - Input")
interest(1)
}
%/* Number of INPx fields defined */
%#define PRINTF_NLINKS 10
}
=head2 Device Support Interface
The record requires device support to provide an entry table (dset) which
defines the following members:
typedef struct {
long number;
long (*report)(int level);
long (*init)(int after);
long (*init_record)(printfRecord *prec);
long (*get_ioint_info)(int cmd, printfRecord *prec, IOSCANPVT *piosl);
long (*write_string)(printfRecord *prec);
} printfdset;
The module must set C<number> to at least 5, and provide a pointer to its
C<write_string()> routine; the other function pointers may be C<NULL> if their
associated functionality is not required for this support layer.
Most device supports also provide an C<init_record()> routine to configure the
record instance and connect it to the hardware or driver support layer.
=head2 Device Support for Soft Records
A soft device support module Soft Channel is provided for writing values to
other records or other software components.
Device support for DTYP C<stdio> is provided for writing values to the stdout,
stderr, or errlog streams. C<INST_IO> addressing C<@stdout>, C<@stderr> or
C<@errlog> is used on the OUT link field to select the desired stream.
=cut

View File

@@ -48,7 +48,7 @@ The string input record has the standard fields for specifying under what
circumstances it will be processed. These fields are listed in L<Scan Fields>.
In addition, L<Scanning Specification> explains how these fields are used.
=head3 Read Parameters
=head3 Input Specification
The INP field determines where the string input record gets its string. It can
be a database or channel access link, or a constant. If constant, the VAL field
@@ -118,7 +118,6 @@ monitors for VAL. If VAL is not equal to OVAL, then monitors are triggered.
=fields OVAL
The following fields are used to operate the string input in the simulation
mode. See L<Simulation Mode> for more information on simulation mode fields.
@@ -277,15 +276,48 @@ routines are primarily interested in the following fields:
=fields PACT, DPVT, UDF, VAL, INP
=head3 Device Support Routines (devSiSoft.c)
=head3 Device Support Routines
Device support consists of the following routines:
=head4 report
long report(int level)
This optional routine is called by the IOC command C<dbior> and is passed the
report level that was requested by the user.
It should print a report on the state of the device support to stdout.
The C<level> parameter may be used to output increasingly more detailed
information at higher levels, or to select different types of information with
different levels.
Level zero should print no more than a small summary.
=head4 init
long init(int after)
This optional routine is called twice at IOC initialization time.
The first call happens before any of the C<init_record()> calls are made, with
the integer parameter C<after> set to 0.
The second call happens after all of the C<init_record()> calls have been made,
with C<after> set to 1.
=head4 init_record
long init_record(stringinRecord *prec)
long init_record(dbCommon *prec)
This routine is optional. If provided, it is called by the record support
C<init_record()> routine.
=head4 get_ioint_info
long get_ioint_info(int cmd, dbCommon *precord, IOSCANPVT *ppvt)
This routine is called by the ioEventScan system each time the record is added
or deleted from an I/O event scan list. C<cmd> has the value (0,1) if the
record is being (added to, deleted from) an I/O event list. It must be
provided for any device type that can use the ioEvent scanner.
=head4 read_stringin
long read_stringin(stringinRecord *prec)
@@ -302,17 +334,11 @@ This routine must provide a new input value. It returns the following values:
=head3 Device Support for Soft Records
The C<<< Soft Channel >>> module places a value directly in VAL.
The C<<< Soft Channel >>> module reads a value directly into VAL.
If the INP link type is constant, the double constant, if non-zero, is converted
to a string and stored into VAL by C<init_record()>, and UDF is set to FALSE. If
the INP link type is PV_LINK, then dbCaAddInlink is called by C<init_record()>.
read_stringin calls recGblGetLinkValue to read the current value of VAL. See
L<Soft Input>.
If the return status of recGblGetLinkValue is zero, then read_stringin sets UDF
to FALSE. The status of recGblGetLinkValue is returned.
Device support for DTYP C<getenv> is provided for retrieving strings from environment variables.
C<INST_IO> addressing C!!@<environment variable> !!is used on the C<INP> link field to select the
desired environment variable.
=cut

View File

@@ -55,7 +55,7 @@ explains how these fields are used.
The string output record must specify from where it gets its desired output
string. The first field that determines where the desired output originates is
the output mode select (OSML) field, which can have two possible value: C<<<
the output mode select (OMSL) field, which can have two possible value: C<<<
closed_loop >>> or C<<< supervisory >>>. If C<<< supervisory >>> is specified,
DOL is ignored, the current value of VAL is written, and the VAL can be changed
externally via dbPuts at run-time. If C<<< closed_loop >>> is specified, the VAL
@@ -87,7 +87,7 @@ for information on specifying links.
menu(menuOmsl)
}
=head3 Write Parameters
=head3 Output Specification
The output link specified in the OUT field specifies where the string output
record is to write its string. The link can be a database or channel access
@@ -353,7 +353,47 @@ primarily interested in the following fields:
=fields PACT, DPVT, NSEV, NSTA, VAL, OUT
=head3 Device Support Routines (devSoSoft.c)
=head3 Device Support Routines
Device support consists of the following routines:
=head4 report
long report(int level)
This optional routine is called by the IOC command C<dbior> and is passed the
report level that was requested by the user.
It should print a report on the state of the device support to stdout.
The C<level> parameter may be used to output increasingly more detailed
information at higher levels, or to select different types of information with
different levels.
Level zero should print no more than a small summary.
=head4 init
long init(int after)
This optional routine is called twice at IOC initialization time.
The first call happens before any of the C<init_record()> calls are made, with
the integer parameter C<after> set to 0.
The second call happens after all of the C<init_record()> calls have been made,
with C<after> set to 1.
=head4 init_record
long init_record(dbCommon *prec)
This routine is optional. If provided, it is called by the record support
C<init_record()> routine.
=head4 get_ioint_info
long get_ioint_info(int cmd, dbCommon *precord, IOSCANPVT *ppvt)
This routine is called by the ioEventScan system each time the record is added
or deleted from an I/O event scan list. C<cmd> has the value (0,1) if the
record is being (added to, deleted from) an I/O event list. It must be
provided for any device type that can use the ioEvent scanner.
=head4 write_stringout
@@ -373,11 +413,9 @@ This routine must output a new value. It returns the following values:
The C<<< Soft Channel >>> device support module writes the current value of VAL.
If the OUT link type is PV_LINK, then dbCaAddInlink is called by
C<init_record()>.
write_so calls recGblPutLinkValue to write the current value of VAL. See
L<Soft Output>.
Device support for DTYP C<stdio> is provided for writing values to the stdout,
stderr, or errlog streams. C<INST_IO> addressing C<@stdout>, C<@stderr> or
C<@errlog> is used on the OUT link field to select the desired stream.
=cut

View File

@@ -49,7 +49,7 @@ L<Address Specification>
for information on specifying links.
In addition, the DTYP field must specify a device support module. Currently, the
only device support module is C<<< Soft Channel >>>.
only device support module is C<Soft Channel>.
=fields INP, DTYP
@@ -59,13 +59,13 @@ These parameters determine the number of array elements (the array length) and
the data type of those elements. The Field Type of Value (FTVL) field determines
the data type of the array.
The user specifies the maximum number of elements allowed in the subarray in the
MALM field. Generally, the number should be equal to the number of elements of
the Waveform array (found in the Waveform's NELM field). The MALM field is used
to allocate memory. The subArray's Number of Elements (NELM) field is where the
user specifies the actual number of elements that the subArray will contain. It
should of course be no greater than MALM; if it is, the record processing
routine sets it equal to MALM.
The user specifies the maximum number of elements that can be read into the
subarray in the MALM field. This number should normally be equal to the number
of elements of the Waveform array (found in the Waveform's NELM field). The MALM
field is used to allocate memory. The subArray's Number of Elements (NELM) field
is where the user specifies the actual number of elements that the subArray will
extract. It should of course be no greater than MALM; if it is, the record
processing routine sets it equal to MALM.
The INDX field determines the offset of the subArray record's array in relation
to the Waveform's. For instance, if INDX is 2, then the subArray will read NELM
@@ -83,15 +83,15 @@ display the value and other parameters of the subarray record either textually
or graphically.
EGU is a string of up to 16 characters describing the engineering units (if any)
of the values which the subArray holds. It is retrieved by the C<<< get_units
>>> record support routine.
of the values which the subArray holds. It is retrieved by the C<get_units()>
record support routine.
The HOPR and LOPR fields set the upper and lower display limits for the
sub-array elements. Both the C<<< get_graphic_double >>> and C<<<
get_control_double >>> record support routines retrieve these fields.
sub-array elements. Both the C<get_graphic_double()> and C<get_control_double()>
record support routines retrieve these fields.
The PREC field determines the floating point precision with which to display
VAL. It is used whenever the C<<< get_precision >>> record support routine is
VAL. It is used whenever the C<get_precision()> record support routine is
called.
See L<Fields Common to All Record Types>
@@ -110,9 +110,9 @@ record types.
These fields are not configurable by the user. They are used for the record's
internal processing or to represent the current state of the record.
The NORD field holds a counter of the number of elements read into the array. It
can be less than NELM even after the array is full if NELM exceeds the number of
existing elements in the referenced array, i.e., the Waveform's array.
The NORD field holds the number of elements that were actually read into the
array. It will be less than NELM whenever the sum of the NELM and INDX fields
exceeds the number of existing elements found in the source array.
BPTR contains a pointer to the record's array.
@@ -150,14 +150,14 @@ See L<Record Processing>.
long (*cvt_dbaddr)(struct dbAddr *paddr)
This is called by dbNameToAddr. It makes the dbAddr structure refer to the
This is called by C<dbNameToAddr()>. It makes the dbAddr structure refer to the
actual buffer holding the result.
=head4 get_array_info
long (*get_array_info)(struct dbAddr *paddr, long *no_elements, long *offset)
Retrieves NELM.
Retrieves NORD.
=head4 put_array_info
@@ -171,14 +171,14 @@ Sets NORD.
For the elements in the array, this routine routines HOPR and LOPR. For the INDX
field, this routine returns MALM - 1 and 0. For NELM, it returns MALM and 1. For
other fields, it calls C<<< recGblGetGraphicDouble() >>>.
other fields, it calls C<recGblGetGraphicDouble()>.
=head4 get_control_double
long (*get_control_double)(struct dbAddr *paddr, struct dbr_ctrlDouble *p)
For array elements, this routine retrieves HOPR and LOPR. Otherwise, C<<<
recGblGetControlDouble() >>> is called.
For array elements, this routine retrieves HOPR and LOPR. Otherwise,
C<recGblGetControlDouble()> is called.
=head4 get_units
@@ -212,13 +212,13 @@ INDX is greater than or equal to MALM it is set to MALM-1.
=item 3.
Call device support read routine. This routine is expected to place the desired
sub-array at the beginning of the buffer and set NORD to the number of elements
of the sub-array that were read.
Call the device support's C<read_sa()> routine. This routine is expected to
place the desired sub-array at the beginning of the buffer and set NORD to the
number of elements of the sub-array that were read.
=item 4.
If PACT has been changed to TRUE, the device support read routine has started
If PACT has been changed to TRUE, the device support read operation has started
but has not completed writing the new value. In this case, the processing
routine merely returns, leaving PACT TRUE. Otherwise, process sets PACT TRUE at
this time. This asynchronous processing logic is not currently used but has been
@@ -305,12 +305,11 @@ sub-array were acquired.
=head3 Device Support For Soft Records
Only the device support module C<<< Soft Channel >>> is currently provided. The
INP link type must be either DB_LINK or CA_LINK.
Only the device support module C<Soft Channel> is currently provided.
=head4 Soft Channel
INP is expected to point to a waveform record.
INP is expected to point to an array field of a waveform record or similar.
=cut

View File

@@ -303,7 +303,9 @@ interested in the following fields:
Device support consists of the following routines:
=head4 long report(int level)
=head4 report
long report(int level)
This optional routine is called by the IOC command C<dbior> and is passed the
report level that was requested by the user.
@@ -313,7 +315,9 @@ information at higher levels, or to select different types of information with
different levels.
Level zero should print no more than a small summary.
=head4 long init(int after)
=head4 init
long init(int after)
This optional routine is called twice at IOC initialization time.
The first call happens before any of the C<init_record()> calls are made, with
@@ -323,14 +327,14 @@ with C<after> set to 1.
=head4 init_record
init_record(precord)
long init_record(dbCommon *precord)
This routine is optional. If provided, it is called by the record support
C<init_record()> routine.
=head4 get_ioint_info
get_ioint_info(int cmd,struct dbCommon *precord,IOSCANPVT *ppvt)
long get_ioint_info(int cmd, dbCommon *precord, IOSCANPVT *ppvt)
This routine is called by the ioEventScan system each time the record is added
or deleted from an I/O event scan list. cmd has the value (0,1) if the
@@ -339,7 +343,7 @@ provided for any device type that can use the ioEvent scanner.
=head4 read_wf
read_wf(precord)
long read_wf(waveformRecord *prec)
This routine must provide a new input value. It returns the following values:
@@ -361,38 +365,11 @@ The C<<< Soft Channel >>> device support module is provided to read values from
other records and store them in arrays. If INP is a constant link, then read_wf
does nothing. In this case, the record can be used to hold arrays written via
dbPuts. If INP is a database or channel access link, the new array value is read
from the link. NORD is set.
from the link. NORD is set to the number of items in the array.
This module places a value directly in VAL.
If the INP link type is constant, then NORD is set to zero. If the INP link type
is PV_LINK, then dbCaAddInlink is called by C<init_record()>.
read_wf calls recGblGetLinkValue which performs the following steps:
=over
=item *
If the INP link type is CONSTANT recGblGetLinkValue does nothing.
=item *
If the INP link type is DB_LINK, then dbGetLink is called to obtain a new input
value. If dbGetLink returns an error, a LINK_ALARM with a severity of
INVALID_ALARM is raised.
=item *
If the INP link type is CA_LINK, then dbCaGetLink is called to obtain a new
input value. If dbCaGetLink returns an error, a LINK_ALARM with a severity of
INVALID_ALARM is raised.
=item *
NORD is set to the number of values returned and read_wf returns.
=back
If the INP link type is constant, then NORD is set to zero.
=cut

View File

@@ -19,26 +19,9 @@ use EPICS::macLib;
use EPICS::Readfile;
BEGIN {
$::XHTML = eval "require Pod::Simple::XHTML; 1";
$::ENTITIES = eval "require HTML::Entities; 1";
$::XHTML = eval "require EPICS::PodXHtml; 1";
if (!$::XHTML) {
require Pod::Simple::HTML;
}
if (!$::ENTITIES) {
my %entities = (
q{>} => 'gt',
q{<} => 'lt',
q{'} => '#39',
q{"} => 'quot',
q{&} => 'amp',
);
sub encode_entities {
my $str = shift;
my $ents = join '', keys %entities;
$str =~ s/([ $ents ])/'&' . ($entities{$1} || sprintf '#x%X', ord $1) . ';'/xge;
return $str;
}
require EPICS::PodHtml;
}
}
@@ -131,7 +114,7 @@ my $contentType =
'<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" >';
if ($::XHTML) {
$podHtml = Pod::Simple::XHTML->new();
$podHtml = EPICS::PodXHtml->new();
$podHtml->html_doctype(<< '__END_DOCTYPE');
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN'
@@ -153,7 +136,7 @@ __END_DOCTYPE
}
} else { # Fall back to HTML
$Pod::Simple::HTML::Content_decl = $contentType;
$podHtml = Pod::Simple::HTML->new();
$podHtml = EPICS::PodHtml->new();
$podHtml->html_css('style.css');
$idify = sub {
@@ -191,7 +174,7 @@ my $pod = join "\n", '=for html <div class="pod">', '',
} $dbd->pod,
'=for html </div>', '';
$podHtml->force_title(encode_entities($title));
$podHtml->force_title($podHtml->encode_entities($title));
$podHtml->perldoc_url_prefix('');
$podHtml->perldoc_url_postfix('.html');
$podHtml->output_fh($out);

View File

@@ -25,6 +25,7 @@
#include "postfix.h"
#include "postfixPvt.h"
static double calcRandom(void);
static int cond_search(const char **ppinst, int match);
@@ -48,7 +49,6 @@ epicsShareFunc long
double *ptop; /* stack pointer */
double top; /* value from top of stack */
epicsInt32 itop; /* integer from top of stack */
epicsUInt32 utop; /* unsigned integer from top of stack */
int op;
int nargs;
@@ -287,45 +287,60 @@ epicsShareFunc long
*ptop = ! *ptop;
break;
/* For bitwise operations on values with bit 31 set, double values
* must first be cast to unsigned to correctly set that bit; the
* double value must be negative in that case. The result must be
* cast to a signed integer before converting to the double result.
/* Be VERY careful converting double to int in case bit 31 is set!
* Out-of-range errors give very different results on different sytems.
* Convert negative doubles to signed and positive doubles to unsigned
* first to avoid overflows if bit 32 is set.
* The result is always signed, values with bit 31 set are negative
* to avoid problems when writing the value to signed integer fields
* like longout.VAL or ao.RVAL. However unsigned fields may give
* problems on some architectures. (Fewer than giving problems with
* signed integer. Maybe the conversion functions should handle
* overflows better.)
*/
#define d2i(x) ((x)<0?(epicsInt32)(x):(epicsInt32)(epicsUInt32)(x))
#define d2ui(x) ((x)<0?(epicsUInt32)(epicsInt32)(x):(epicsUInt32)(x))
case BIT_OR:
utop = *ptop--;
*ptop = (epicsInt32) ((epicsUInt32) *ptop | utop);
top = *ptop--;
*ptop = (double)(d2i(*ptop) | d2i(top));
break;
case BIT_AND:
utop = *ptop--;
*ptop = (epicsInt32) ((epicsUInt32) *ptop & utop);
top = *ptop--;
*ptop = (double)(d2i(*ptop) & d2i(top));
break;
case BIT_EXCL_OR:
utop = *ptop--;
*ptop = (epicsInt32) ((epicsUInt32) *ptop ^ utop);
top = *ptop--;
*ptop = (double)(d2i(*ptop) ^ d2i(top));
break;
case BIT_NOT:
utop = *ptop;
*ptop = (epicsInt32) ~utop;
*ptop = (double)~d2i(*ptop);
break;
/* The shift operators use signed integers, so a right-shift will
* extend the sign bit into the left-hand end of the value. The
* double-casting through unsigned here is important, see above.
/* In C the shift operators decide on an arithmetic or logical shift
* based on whether the integer is signed or unsigned.
* With signed integers, a right-shift is arithmetic and will
* extend the sign bit into the left-hand end of the value. When used
* with unsigned values a logical shift is performed. The
* double-casting through signed/unsigned here is important, see above.
*/
case RIGHT_SHIFT:
utop = *ptop--;
*ptop = ((epicsInt32) (epicsUInt32) *ptop) >> (utop & 31);
case RIGHT_SHIFT_ARITH:
top = *ptop--;
*ptop = (double)(d2i(*ptop) >> (d2i(top) & 31));
break;
case LEFT_SHIFT:
utop = *ptop--;
*ptop = ((epicsInt32) (epicsUInt32) *ptop) << (utop & 31);
case LEFT_SHIFT_ARITH:
top = *ptop--;
*ptop = (double)(d2i(*ptop) << (d2i(top) & 31));
break;
case RIGHT_SHIFT_LOGIC:
top = *ptop--;
*ptop = (double)(d2ui(*ptop) >> (d2ui(top) & 31u));
break;
case NOT_EQ:
@@ -382,11 +397,11 @@ epicsShareFunc long
*presult = *ptop;
return 0;
}
#if defined(_WIN32) && defined(_M_X64) && !defined(_MINGW)
# pragma optimize("", on)
#endif
epicsShareFunc long
calcArgUsage(const char *pinst, unsigned long *pinputs, unsigned long *pstores)
{

View File

@@ -148,13 +148,14 @@ static const ELEMENT operators[] = {
{":=", 0, 0, -1, STORE_OPERATOR, STORE_A},
{";", 0, 0, 0, EXPR_TERMINATOR,NOT_GENERATED},
{"<", 3, 3, -1, BINARY_OPERATOR,LESS_THAN},
{"<<", 2, 2, -1, BINARY_OPERATOR,LEFT_SHIFT},
{"<<", 2, 2, -1, BINARY_OPERATOR,LEFT_SHIFT_ARITH},
{"<=", 3, 3, -1, BINARY_OPERATOR,LESS_OR_EQ},
{"=", 3, 3, -1, BINARY_OPERATOR,EQUAL},
{"==", 3, 3, -1, BINARY_OPERATOR,EQUAL},
{">", 3, 3, -1, BINARY_OPERATOR,GR_THAN},
{">=", 3, 3, -1, BINARY_OPERATOR,GR_OR_EQ},
{">>", 2, 2, -1, BINARY_OPERATOR,RIGHT_SHIFT},
{">>", 2, 2, -1, BINARY_OPERATOR,RIGHT_SHIFT_ARITH},
{">>>", 2, 2, -1, BINARY_OPERATOR,RIGHT_SHIFT_LOGIC},
{"?", 0, 0, -1, CONDITIONAL, COND_IF},
{"AND", 2, 2, -1, BINARY_OPERATOR,BIT_AND},
{"OR", 1, 1, -1, BINARY_OPERATOR,BIT_OR},
@@ -579,8 +580,9 @@ epicsShareFunc void
"BIT_AND",
"BIT_EXCL_OR",
"BIT_NOT",
"RIGHT_SHIFT",
"LEFT_SHIFT",
"RIGHT_SHIFT_ARITH",
"LEFT_SHIFT_ARITH",
"RIGHT_SHIFT_LOGIC",
/* Relationals */
"NOT_EQ",
"LESS_THAN",

View File

@@ -84,8 +84,9 @@ typedef enum {
BIT_AND,
BIT_EXCL_OR,
BIT_NOT,
RIGHT_SHIFT,
LEFT_SHIFT,
RIGHT_SHIFT_ARITH,
LEFT_SHIFT_ARITH,
RIGHT_SHIFT_LOGIC,
/* Relationals */
NOT_EQ,
LESS_THAN,

View File

@@ -3,14 +3,12 @@
* National Laboratory.
* Copyright (c) 2002 The Regents of the University of California, as
* Operator of Los Alamos National Laboratory.
* EPICS BASE Versions 3.13.7
* and higher are distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* logClient.c,v 1.25.2.6 2004/10/07 13:37:34 mrk Exp */
/*
* Author: Jeffrey O. Hill
* Date: 080791
* Author: Jeffrey O. Hill
* Date: 080791
*/
/*
@@ -80,7 +78,7 @@ static void logClientClose ( logClient *pClient )
* mutex on
*/
epicsMutexMustLock (pClient->mutex);
/*
* close any preexisting connection to the log server
*/
@@ -140,9 +138,9 @@ static void logClientDestroy (logClientId id)
epicsMutexMustLock ( pClient->mutex );
do {
epicsMutexUnlock ( pClient->mutex );
epicsEventWaitWithTimeout (
pClient->stateChangeNotify,
LOG_SERVER_SHUTDOWN_TIMEOUT / 10.0 );
epicsEventWaitWithTimeout (
pClient->stateChangeNotify,
LOG_SERVER_SHUTDOWN_TIMEOUT / 10.0 );
epicsTimeGetCurrent ( & current );
diff = epicsTimeDiffInSeconds ( & current, & begin );
epicsMutexMustLock ( pClient->mutex );
@@ -151,8 +149,8 @@ static void logClientDestroy (logClientId id)
epicsMutexUnlock ( pClient->mutex );
if ( ! pClient->shutdownConfirm ) {
fprintf ( stderr, "log client shutdown: timed out stopping"
" reconnect thread for \"%s\" after %.1f seconds - cleanup aborted\n",
fprintf ( stderr, "log client shutdown: timed out stopping reconnect\n"
" thread for '%s' after %.1f seconds - cleanup aborted\n",
pClient->name, LOG_SERVER_SHUTDOWN_TIMEOUT );
return;
}
@@ -174,7 +172,7 @@ static void sendMessageChunk(logClient * pClient, const char * message) {
strSize = strlen ( message );
while ( strSize ) {
unsigned msgBufBytesLeft =
unsigned msgBufBytesLeft =
sizeof ( pClient->msgBuf ) - pClient->nextMsgIndex;
if ( msgBufBytesLeft < strSize && pClient->nextMsgIndex != 0u && pClient->connected)
@@ -197,7 +195,7 @@ static void sendMessageChunk(logClient * pClient, const char * message) {
}
}
/*
/*
* logClientSend ()
*/
void epicsShareAPI logClientSend ( logClientId id, const char * message )
@@ -240,8 +238,7 @@ void epicsShareAPI logClientFlush ( logClientId id )
nSent += status;
}
if ( pClient->backlog > 0 && status >= 0 )
{
if ( pClient->backlog > 0 && status >= 0 ) {
/* On Linux send 0 bytes can detect EPIPE */
/* NOOP on Windows, fails on vxWorks */
errno = 0;
@@ -252,9 +249,9 @@ void epicsShareAPI logClientFlush ( logClientId id )
if ( status < 0 ) {
if ( ! pClient->shutdown ) {
char sockErrBuf[128];
epicsSocketConvertErrnoToString ( sockErrBuf, sizeof ( sockErrBuf ) );
fprintf ( stderr, "log client: lost contact with log server at \"%s\" because \"%s\"\n",
pClient->name, sockErrBuf );
epicsSocketConvertErrnoToString(sockErrBuf, sizeof(sockErrBuf));
fprintf(stderr, "log client: lost contact with log server at '%s'\n"
" because \"%s\"\n", pClient->name, sockErrBuf);
}
pClient->backlog = 0;
logClientClose ( pClient );
@@ -285,19 +282,19 @@ static void logClientMakeSock (logClient *pClient)
}
epicsMutexMustLock (pClient->mutex);
/*
* allocate a socket
/*
* allocate a socket
*/
pClient->sock = epicsSocketCreate ( AF_INET, SOCK_STREAM, 0 );
if ( pClient->sock == INVALID_SOCKET ) {
char sockErrBuf[128];
epicsSocketConvertErrnoToString (
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
fprintf ( stderr, "log client: no socket error %s\n",
fprintf ( stderr, "log client: no socket error %s\n",
sockErrBuf );
}
epicsMutexUnlock (pClient->mutex);
if (logClientDebug)
@@ -312,16 +309,16 @@ static void logClientConnect (logClient *pClient)
osiSockIoctl_t optval;
int errnoCpy;
int status;
if ( pClient->sock == INVALID_SOCKET ) {
logClientMakeSock ( pClient );
if ( pClient->sock == INVALID_SOCKET ) {
return;
}
}
while ( 1 ) {
status = connect (pClient->sock,
status = connect (pClient->sock,
(struct sockaddr *)&pClient->addr, sizeof(pClient->addr));
if ( status >= 0 ) {
break;
@@ -345,8 +342,9 @@ static void logClientConnect (logClient *pClient)
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
fprintf (stderr,
"log client: failed to connect to \"%s\" because %d=\"%s\"\n",
pClient->name, errnoCpy, sockErrBuf);
"log client: failed to connect to server '%s'"
" because '%s'\n",
pClient->name, sockErrBuf);
pClient->connFailStatus = errnoCpy;
}
logClientClose ( pClient );
@@ -365,12 +363,14 @@ static void logClientConnect (logClient *pClient)
* (after a long delay)
*/
optval = TRUE;
status = setsockopt (pClient->sock, SOL_SOCKET, SO_KEEPALIVE, (char *)&optval, sizeof(optval));
status = setsockopt (pClient->sock, SOL_SOCKET, SO_KEEPALIVE,
(char *)&optval, sizeof(optval));
if (status<0) {
char sockErrBuf[128];
epicsSocketConvertErrnoToString (
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
fprintf (stderr, "log client: unable to enable keepalive option because \"%s\"\n", sockErrBuf);
fprintf (stderr, "log client: unable to enable SO_KEEPALIVE\n"
" because '%s'\n", sockErrBuf);
}
/*
@@ -380,9 +380,9 @@ static void logClientConnect (logClient *pClient)
status = shutdown (pClient->sock, SHUT_RD);
if (status < 0) {
char sockErrBuf[128];
epicsSocketConvertErrnoToString (
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
fprintf (stderr, "%s:%d shutdown(sock,SHUT_RD) error was \"%s\"\n",
fprintf (stderr, "%s:%d shutdown(sock,SHUT_RD) error was '%s'\n",
__FILE__, __LINE__, sockErrBuf);
/* not fatal (although it shouldn't happen) */
}
@@ -395,25 +395,28 @@ static void logClientConnect (logClient *pClient)
*/
{
struct linger lingerval;
lingerval.l_onoff = TRUE;
lingerval.l_linger = 60*5;
status = setsockopt (pClient->sock, SOL_SOCKET, SO_LINGER, (char *) &lingerval, sizeof(lingerval));
lingerval.l_linger = 60*5;
status = setsockopt (pClient->sock, SOL_SOCKET, SO_LINGER,
(char *) &lingerval, sizeof(lingerval));
if (status<0) {
char sockErrBuf[128];
epicsSocketConvertErrnoToString (
epicsSocketConvertErrnoToString (
sockErrBuf, sizeof ( sockErrBuf ) );
fprintf (stderr, "log client: unable to set linger options because \"%s\"\n", sockErrBuf);
fprintf(stderr, "log client: unable to set SO_LINGER\n"
" because '%s'\n", sockErrBuf);
}
}
pClient->connectCount++;
epicsMutexUnlock ( pClient->mutex );
epicsEventSignal ( pClient->stateChangeNotify );
fprintf ( stderr, "log client: connected to log server at \"%s\"\n", pClient->name );
fprintf(stderr, "log client: connected to log server at '%s'\n",
pClient->name);
}
/*
@@ -493,7 +496,7 @@ logClientId epicsShareAPI logClientCreate (
}
pClient->restartThreadId = epicsThreadCreate (
"logRestart", epicsThreadPriorityLow,
"logRestart", epicsThreadPriorityLow,
epicsThreadGetStackSize(epicsThreadStackSmall),
logClientRestart, pClient );
if ( pClient->restartThreadId == NULL ) {
@@ -501,7 +504,7 @@ logClientId epicsShareAPI logClientCreate (
epicsEventDestroy ( pClient->stateChangeNotify );
epicsEventDestroy ( pClient->shutdownNotify );
free (pClient);
fprintf(stderr, "log client: unable to start log client connection watch dog thread\n");
fprintf(stderr, "log client: unable to start reconnection thread\n");
return NULL;
}
@@ -516,10 +519,11 @@ void epicsShareAPI logClientShow (logClientId id, unsigned level)
logClient *pClient = (logClient *) id;
if ( pClient->connected ) {
printf ("log client: connected to log server at \"%s\"\n", pClient->name);
printf ("log client: connected to log server at '%s'\n", pClient->name);
}
else {
printf ("log client: disconnected from log server at \"%s\"\n", pClient->name);
printf ("log client: disconnected from log server at '%s'\n",
pClient->name);
}
if (logClientPrefix) {

View File

@@ -383,5 +383,11 @@ extern "C" {
}
} // extern "C"
// Ensure the main thread gets a unique ID
epicsThreadId epicsThreadMainId = epicsThreadGetIdSelf();
static epicsThreadId initMainThread(void) {
epicsThreadId main = epicsThreadGetIdSelf();
epicsThreadSetOkToBlock(1);
return main;
}
// Ensure the main thread gets a unique ID and allows blocking I/O
epicsThreadId epicsThreadMainId = initMainThread();

View File

@@ -48,8 +48,10 @@ void epicsAtomicLock ( EpicsAtomicLockKey * )
status = pthread_mutex_lock ( & mutex );
if ( status == 0 ) return;
assert ( status == EINTR );
static const useconds_t retryDelayUSec = 100000;
usleep ( retryDelayUSec );
struct timespec retryDelay = { 0, 100000000 };
struct timespec remainingDelay;
while (nanosleep(&retryDelay, &remainingDelay) == -1 && errno == EINTR)
retryDelay = remainingDelay;
countDown--;
assert ( countDown );
}

View File

@@ -2,7 +2,7 @@
* Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
* in file LICENSE that is included with this distribution.
\*************************************************************************/
#include <stddef.h>
@@ -101,7 +101,7 @@ void ClockTime_Init(int synchronize)
if (synchronize == CLOCKTIME_SYNC) {
if (ClockTimePvt.synchronize == CLOCKTIME_NOSYNC) {
#if defined(vxWorks) || defined(__rtems__)
/* Start synchronizing */
ClockTimePvt.synchronize = synchronize;
@@ -229,7 +229,11 @@ int osdTimeGetCurrent(epicsTimeStamp *pDest)
return 0;
}
#endif /* CLOCK_REALTIME */
/* Used in Report function below: */
#define UNINIT_ERROR "initialized"
#else
#define UNINIT_ERROR "available"
#endif /* CLOCK_REALTIME && !WIN32 */
/* Allow the following report routine to be compiled anyway
* to avoid getting a build warning from ranlib.
@@ -242,13 +246,7 @@ int ClockTime_Report(int level)
char timebuf[32];
if (onceId == EPICS_THREAD_ONCE_INIT) {
printf("OS Clock driver not %s.\n",
#ifdef CLOCK_REALTIME
"initialized"
#else
"available"
#endif /* CLOCK_REALTIME */
);
puts("OS Clock driver not " UNINIT_ERROR);
}
else if (ClockTimePvt.synchronize == CLOCKTIME_SYNC) {
int synchronized, syncFromPriority;

View File

@@ -114,6 +114,11 @@ epicsThreadTest_SRCS += epicsThreadTest.cpp
testHarness_SRCS += epicsThreadTest.cpp
TESTS += epicsThreadTest
TESTPROD_HOST += epicsThreadClassTest
epicsThreadClassTest_SRCS += epicsThreadClassTest.cpp
testHarness_SRCS += epicsThreadClassTest.cpp
TESTS += epicsThreadClassTest
TESTPROD_HOST += epicsThreadOnceTest
epicsThreadOnceTest_SRCS += epicsThreadOnceTest.c
testHarness_SRCS += epicsThreadOnceTest.c

View File

@@ -104,7 +104,7 @@ void testUInt32Calc(const char *expr, epicsUInt32 expected) {
testDiag("calcPerform: error evaluating '%s'", expr);
}
uresult = (epicsUInt32) result;
uresult = (result < 0.0 ? (epicsUInt32)(epicsInt32)result : (epicsUInt32)result);
pass = (uresult == expected);
if (!testOk(pass, "%s", expr)) {
testDiag("Expected result is 0x%x (%u), actually got 0x%x (%u)",
@@ -296,8 +296,8 @@ MAIN(epicsCalcTest)
int repeat;
const double a=1.0, b=2.0, c=3.0, d=4.0, e=5.0, f=6.0,
g=7.0, h=8.0, i=9.0, j=10.0, k=11.0, l=12.0;
testPlan(613);
testPlan(630);
/* LITERAL_OPERAND elements */
testExpr(0);
@@ -320,7 +320,7 @@ MAIN(epicsCalcTest)
testExpr(Inf);
testCalc("Infinity", Inf);
testExpr(NaN);
/* OPERAND elements */
testExpr(a);
testExpr(b);
@@ -337,7 +337,7 @@ MAIN(epicsCalcTest)
testExpr(PI);
testExpr(D2R);
testExpr(R2D);
for (repeat=0; repeat<100; repeat++) {
double res = doCalc("rndm");
if (res<0 || res >1) {
@@ -346,13 +346,13 @@ MAIN(epicsCalcTest)
}
}
testOk(repeat == 100, "rndm");
/* UNARY_MINUS element */
testExpr(-1);
testExpr(-Inf);
testExpr(- -1);
testCalc("-0x80000000", 2147483648.0);
/* UNARY_OPERATOR elements */
testExpr((1));
testExpr(!0);
@@ -544,7 +544,7 @@ MAIN(epicsCalcTest)
testExpr(tanh(0.5));
testExpr(~5);
testExpr(~~5);
/* BINARY_OPERATOR elements */
testExpr(0 != 1);
testExpr(0 != 0);
@@ -565,24 +565,24 @@ MAIN(epicsCalcTest)
testExpr(NaN != Inf);
testExpr(NaN != -Inf);
testExpr(NaN != NaN);
testCalc("0 # 1", 0 != 1);
testCalc("0 # 0", 0 != 0);
testCalc("1 # 0", 1 != 0);
testCalc("1 # 0 # 2", 1 != 0 != 2);
testExpr(7 % 4);
testExpr(-7 % 4);
testExpr(63 % 16 % 6)
testCalc("1 % 0", NaN);
testExpr(7 & 4);
testExpr(0 && 0);
testExpr(0 && 1);
testExpr(1 && 0);
testExpr(1 && 1);
testExpr(2 * 2);
testExpr(0.0 * Inf);
testExpr(0.0 * -Inf);
@@ -599,32 +599,38 @@ MAIN(epicsCalcTest)
testExpr(NaN * Inf);
testExpr(NaN * -Inf);
testExpr(NaN * NaN);
testCalc("2 ** 0.2", pow(2., 0.2));
testCalc("2 ** -0.2", pow(2., -0.2));
testCalc("-0.2 ** 2", pow(-0.2, 2.));
testCalc("-0.2 ** -2", pow(-0.2, -2));
testCalc("2 ** 2 ** 3", pow(pow(2., 2.), 3.));
testExpr(0 + 1);
testExpr(0.0 + Inf);
testExpr(0.0 + -Inf);
testExpr(0.0 + NaN);
testExpr(Inf + 0.0);
testExpr(Inf + Inf);
// only test CALC as MSVC seems to incorrectly evaluate this expression at compile time.
// see note in epicsMathTest
#if defined(_WIN32) && defined(_MSC_VER)
testCalc("Inf + -Inf", NaN);
#else
testExpr(Inf + -Inf);
#endif
testExpr(Inf + NaN);
testExpr(-Inf + 0.0);
#if defined(_WIN32) && defined(_MSC_VER)
testCalc("-Inf + Inf", NaN);
#else
testExpr(-Inf + Inf);
#endif
testExpr(-Inf + -Inf);
testExpr(-Inf + NaN);
testExpr(NaN + 0.0);
testExpr(NaN + Inf);
testExpr(NaN + -Inf);
testExpr(NaN + NaN);
testExpr(0 - 1);
testExpr(0 - 1 - 2);
testExpr(0.0 - Inf);
@@ -642,7 +648,7 @@ MAIN(epicsCalcTest)
testExpr(NaN - Inf);
testExpr(NaN - -Inf);
testExpr(NaN - NaN);
testExpr(2.0 / 3.0);
testExpr(1.0 / 2.0 / 3.0);
testExpr(0.0 / Inf);
@@ -660,7 +666,7 @@ MAIN(epicsCalcTest)
testExpr(NaN / Inf);
testExpr(NaN / -Inf);
testExpr(NaN / NaN);
testExpr(0 < 1);
testExpr(0 < 0);
testExpr(1 < 0);
@@ -680,10 +686,10 @@ MAIN(epicsCalcTest)
testExpr(NaN < Inf);
testExpr(NaN < -Inf);
testExpr(NaN < NaN);
testExpr(1 << 2);
testExpr(1 << 3 << 2)
testExpr(1 << 3 << 2);
testExpr(0 <= 1);
testExpr(0 <= 0);
testExpr(1 <= 0);
@@ -703,12 +709,12 @@ MAIN(epicsCalcTest)
testExpr(NaN <= Inf);
testExpr(NaN <= -Inf);
testExpr(NaN <= NaN);
testCalc("0 = 1", 0 == 1);
testCalc("0 = 0", 0 == 0);
testCalc("1 = 0", 1 == 0);
testCalc("2 = 2 = 1", 2 == 2 == 1);
testExpr(0 == 1);
testExpr(0 == 0);
testExpr(1 == 0);
@@ -728,7 +734,7 @@ MAIN(epicsCalcTest)
testExpr(NaN == Inf);
testExpr(NaN == -Inf);
testExpr(NaN == NaN);
testExpr(0 > 1);
testExpr(0 > 0);
testExpr(1 > 0);
@@ -748,7 +754,7 @@ MAIN(epicsCalcTest)
testExpr(NaN > Inf);
testExpr(NaN > -Inf);
testExpr(NaN > NaN);
testExpr(0 >= 1);
testExpr(0 >= 0);
testExpr(1 >= 0);
@@ -768,29 +774,31 @@ MAIN(epicsCalcTest)
testExpr(NaN >= Inf);
testExpr(NaN >= -Inf);
testExpr(NaN >= NaN);
testExpr(8 >> 1);
testCalc("8 >>> 1", 8u >> 1u);
testExpr(64 >> 2 >> 1);
testCalc("64 >>> 2 >>> 1", 64u >> 2u >> 1u);
testExpr(7 AND 4);
testExpr(1 OR 8);
testExpr(3 XOR 9);
testCalc("2 ^ 0.2", pow(2., 0.2));
testCalc("2 ^ -0.2", pow(2., -0.2));
testCalc("(-0.2) ^ 2", pow(-0.2, 2.));
testCalc("(-0.2) ^ -2", pow(-0.2, -2.));
testCalc("2 ^ 2 ^ 3", pow(pow(2., 2.), 3.));
testExpr(1 | 8);
testExpr(0 || 0);
testExpr(0 || 1);
testExpr(1 || 0);
testExpr(1 || 1);
/* CONDITIONAL elements */
testExpr(0 ? 1 : 2);
testExpr(1 ? 1 : 2);
@@ -804,7 +812,7 @@ MAIN(epicsCalcTest)
testExpr(0 ? 2 : 1 ? 3 : 4);
testExpr(1 ? 2 : 0 ? 3 : 4);
testExpr(1 ? 2 : 1 ? 3 : 4);
/* STORE_OPERATOR and EXPR_TERM elements*/
testCalc("a := 0; a", 0);
testCalc("b := 0; b", 0);
@@ -818,7 +826,7 @@ MAIN(epicsCalcTest)
testCalc("j := 0; j", 0);
testCalc("k := 0; k", 0);
testCalc("l := 0; l", 0);
testCalc("a; a := 0", a);
testCalc("b; b := 0", b);
testCalc("c; c := 0", c);
@@ -831,7 +839,7 @@ MAIN(epicsCalcTest)
testCalc("j; j := 0", j);
testCalc("k; k := 0", k);
testCalc("l; l := 0", l);
// Check relative precedences.
testExpr(0 ? 1 : 2 | 4); // 0 1
testExpr(1 ? 1 : 2 | 4); // 0 1
@@ -869,11 +877,14 @@ MAIN(epicsCalcTest)
testExpr(3 << 2 & 10); // 2 2
testCalc("18 & 6 << 2", (18 & 6) << 2); // 2 2
testExpr(36 >> 2 & 10); // 2 2
testCalc("36 >>> 2 & 10", 36u >> 2u & 10u); // 2 2
testCalc("18 & 20 >> 2", (18 & 20) >> 2); // 2 2
testCalc("18 & 20 >>> 2", (18u & 20u) >> 2);// 2 2
testExpr(3 & 4 == 4); // 2 3
testExpr(3 AND 4 == 4); // 2 3
testCalc("1 << 2 != 4", 1 << (2 != 4)); // 2 3
testCalc("16 >> 2 != 4", 16 >> (2 != 4)); // 2 3
testCalc("16 >>> 2 != 4", 16u >> (2 != 4)); // 2 3
testExpr(3 AND -2); // 2 8
testExpr(0 < 1 ? 2 : 3); // 3 0
testExpr(1 <= 0 ? 2 : 3); // 3 0
@@ -885,12 +896,12 @@ MAIN(epicsCalcTest)
testExpr(-1 - 2); // 7 4
testCalc("-2 ** 2", pow(-2., 2.)); // 7 6
testCalc("-2 ^ 2", pow(-2., 2.)); // 7 6
// Check parentheses
testCalc("(1 | 2) ** 3", pow((double) (1 | 2), 3.));// 8 6
testCalc("1+(1|2)**3", 1+pow((double) (1 | 2), 3.));// 8 6
testExpr(1+(1?(1<2):(1>2))*2);
testArgs("a", A_A, 0);
testArgs("A", A_A, 0);
testArgs("B", A_B, 0);
@@ -920,7 +931,7 @@ MAIN(epicsCalcTest)
testArgs("11.1;L:=0", 0, A_L);
testArgs("12.1;A:=0;B:=A;C:=B;D:=C", 0, A_A|A_B|A_C|A_D);
testArgs("13.1;B:=A;A:=B;C:=D;D:=C", A_A|A_D, A_A|A_B|A_C|A_D);
// Malformed expressions
testBadExpr("0x0.1", CALC_ERR_SYNTAX);
testBadExpr("1*", CALC_ERR_INCOMPLETE);
@@ -945,7 +956,11 @@ MAIN(epicsCalcTest)
testUInt32Calc("~0xaaaaaaaa", 0x55555555u);
testUInt32Calc("~~0xaaaaaaaa", 0xaaaaaaaau);
testUInt32Calc("0xaaaaaaaa >> 8", 0xffaaaaaau);
testUInt32Calc("0x55555555 >> 8", 0x00555555u);
testUInt32Calc("0xaaaaaaaa >>> 8", 0x00aaaaaau);
testUInt32Calc("0x55555555 >>> 8", 0x00555555u);
testUInt32Calc("0xaaaaaaaa << 8", 0xaaaaaa00u);
testUInt32Calc("0x55555555 << 8", 0x55555500u);
// using integer literals assigned to variables
testUInt32Calc("a:=0xaaaaaaaa; b:=0xffff0000; a AND b", 0xaaaa0000u);
testUInt32Calc("a:=0xaaaaaaaa; b:=0xffff0000; a OR b", 0xffffaaaau);
@@ -953,7 +968,11 @@ MAIN(epicsCalcTest)
testUInt32Calc("a:=0xaaaaaaaa; ~a", 0x55555555u);
testUInt32Calc("a:=0xaaaaaaaa; ~~a", 0xaaaaaaaau);
testUInt32Calc("a:=0xaaaaaaaa; a >> 8", 0xffaaaaaau);
testUInt32Calc("a:=0xaaaaaaaa; a >>> 8", 0x00aaaaaau);
testUInt32Calc("a:=0xaaaaaaaa; a << 8", 0xaaaaaa00u);
testUInt32Calc("a:=0x55555555; a >> 8", 0x00555555u);
testUInt32Calc("a:=0x55555555; a >>> 8", 0x00555555u);
testUInt32Calc("a:=0x55555555; a << 8", 0x55555500u);
// Test proper conversion of double values (+ 0.1 enforces double literal)
// when used as inputs to the bitwise operations.
@@ -973,9 +992,13 @@ MAIN(epicsCalcTest)
testUInt32Calc("~ -1431655766.1", 0x55555555u);
testUInt32Calc("~ 2863311530.1", 0x55555555u);
testUInt32Calc("-1431655766.1 >> 0", 0xaaaaaaaau);
testUInt32Calc("-1431655766.1 >>> 0", 0xaaaaaaaau);
testUInt32Calc("2863311530.1 >> 0", 0xaaaaaaaau);
testUInt32Calc("2863311530.1 >>> 0", 0xaaaaaaaau);
testUInt32Calc("-1431655766.1 >> 0.1", 0xaaaaaaaau);
testUInt32Calc("-1431655766.1 >>> 0.1", 0xaaaaaaaau);
testUInt32Calc("2863311530.1 >> 0.1", 0xaaaaaaaau);
testUInt32Calc("2863311530.1 >>> 0.1", 0xaaaaaaaau);
testUInt32Calc("-1431655766.1 << 0", 0xaaaaaaaau);
testUInt32Calc("2863311530.1 << 0", 0xaaaaaaaau);
testUInt32Calc("-1431655766.1 << 0.1", 0xaaaaaaaau);
@@ -983,4 +1006,3 @@ MAIN(epicsCalcTest)
return testDone();
}

View File

@@ -20,38 +20,38 @@ MAIN(epicsMathTest)
double huge = 1e300;
double tiny = 1e-300;
double c;
testPlan(35);
testOk1(!isnan(0.0));
testOk1(!isinf(0.0));
testOk1(!isnan(epicsINF));
testOk1(isinf(epicsINF));
testOk1(epicsINF == epicsINF);
testOk1(epicsINF > 0.0);
testOk1(epicsINF - epicsINF != 0.0);
#if defined(_MSC_VER)
testTodoBegin("Known failure on windows (MSVC optimizer bug?)");
#if defined(_WIN32) && defined(_MSC_VER)
testTodoBegin("Known failure on windows-x64 and win32-x86");
#endif
testOk1(epicsINF + -epicsINF != 0.0);
testOk1(-epicsINF + epicsINF != 0.0);
#if defined(_MSC_VER)
#if defined(_WIN32) && defined(_MSC_VER)
testTodoEnd();
#endif
testOk1(isnan(epicsINF - epicsINF));
#if defined(_MSC_VER)
testTodoBegin("Known failure on windows (MSVC optimizer bug?)");
#if defined(_WIN32) && defined(_MSC_VER)
testTodoBegin("Known failure on windows-x64 and win32-x86");
#endif
testOk1(isnan(epicsINF + -epicsINF));
testOk1(isnan(-epicsINF + epicsINF));
#if defined(_MSC_VER)
#if defined(_WIN32) && defined(_MSC_VER)
testTodoEnd();
#endif
testOk1(isnan(epicsNAN));
testOk1(!isinf(epicsNAN));
testOk1(epicsNAN != epicsNAN);
@@ -62,34 +62,34 @@ MAIN(epicsMathTest)
testOk1(!(epicsNAN > epicsNAN));
testOk1(isnan(epicsNAN - epicsNAN));
#if defined(_MSC_VER)
testTodoBegin("Known failure on windows (MSVC optimizer bug?)");
#if defined(_WIN32) && defined(_MSC_VER)
testTodoBegin("Known failure on windows-x64 and win32-x86");
#endif
testOk1(isnan(epicsNAN + -epicsNAN));
testOk1(isnan(-epicsNAN + epicsNAN));
#if defined(_MSC_VER)
#if defined(_WIN32) && defined(_MSC_VER)
testTodoEnd();
#endif
c = huge / tiny;
testOk(!isnan(c), "!isnan(1e300 / 1e-300)");
testOk(isinf(c), "isinf(1e300 / 1e-300)");
testOk(c > 0.0, "1e300 / 1e-300 > 0.0");
c = (-huge) / tiny;
testOk(!isnan(c), "!isnan(-1e300 / 1e-300)");
testOk(isinf(c), "isinf(-1e300 / 1e-300)");
testOk(c < 0.0, "-1e300 / 1e-300 < 0.0");
c = huge / huge;
testOk(!isnan(c), "!isnan(1e300 / 1e300)");
testOk(!isinf(c), "!isinf(1e300 / 1e300)");
testOk(c == 1.0, "1e300 / 1e300 == 1.0");
c = tiny / tiny;
testOk(!isnan(c), "!isnan(1e-300 / 1e-300)");
testOk(!isinf(c), "!isinf(1e-300 / 1e-300)");
testOk(c == 1.0, "1e300 / 1e-300 == 1.0");
return testDone();
}

View File

@@ -0,0 +1,210 @@
/*************************************************************************\
* Copyright (c) 2020 UChicago Argonne LLC, as Operator of Argonne
* National Laboratory.
* EPICS BASE is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
\*************************************************************************/
/* epicsThreadClassTest.cpp */
#include <stddef.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include "dbDefs.h"
#include "epicsAssert.h"
#include "epicsThread.h"
#include "epicsUnitTest.h"
#include "testMain.h"
/* Key to the char's that define the test case actions:
*
* Upper case letters are for parent thread actions
* B - Parent calls thread->start() and waits for child to start
* D - Parent deletes thread. This waits for child to return if it hasn't yet
* E - Parent calls thread->exitWait(), this may wait for child to return
* S - Parent sleeps for SLEEP_TIME seconds
* T - Parent sends sync trigger to child (w)
* W - Parent waits for sync trigger from child (t)
* X - Parent calls thread->exitWait(0)
*
* Lower case letters are for child thread actions
* d - Child deletes thread
* e - Child calls thread->exitWait()
* r - Child returns
* s - Child sleeps for SLEEP_TIME seconds
* t - Child sends sync trigger to parent (W)
* w - Child waits for sync trigger from child (T)
*
* Note that it is possible to write test cases that can hang,
* segfault, or that trigger errors from thread APIs.
*/
// The test cases
const char * const cases[] = {
// These cases don't start the thread:
"D", // Parent deletes thread
"ED", // Parent does exitWait(), deletes thread
// In these cases the parent deletes the thread
"BrSD", // Child returns; parent deletes thread
"BsDr", // Parent deletes thread; child returns
"BrSED", // Child returns; parent does exitWait(), deletes thread
"BsErD", // Parent does exitWait(); child returns; parent deletes thread
"BsXDr", // Parent does exitWait(0); parent deletes thread; child returns
"BwXTDsr", // Parent does exitWait(0); parent deletes thread; child returns
// These are currently broken
// "BetWSrD", // Child does exitWait(); sync; child returns; parent deletes thread
// "BetWsDr", // Child does exitWait(); sync; parent deletes thread; child returns
// In these cases the child deletes the thread
"BdrS", // Child deletes thread, returns
"BedrS", // Child does exitWait(), deletes thread, returns
"BwXTSdr", // Parent does exitWait(0); sync; child deletes thread, returns
NULL // Terminator
};
// How long to sleep for while the other thread works
#define SLEEP_TIME 1.0
class threadCase: public epicsThreadRunable {
public:
threadCase(const char * const tcase);
virtual ~threadCase();
virtual void run();
epicsThread *pthread;
epicsEvent startEvt;
epicsEvent childEvt;
epicsEvent parentEvt;
private:
const char * const name;
};
threadCase::threadCase(const char * const tcase) :
pthread(new epicsThread(*this, tcase,
epicsThreadGetStackSize(epicsThreadStackSmall))),
name(tcase)
{
testDiag("Constructing test case '%s'", name);
}
threadCase::~threadCase()
{
testDiag("Destroying test case '%s'", name);
}
void threadCase::run()
{
testDiag("Child running for '%s'", name);
startEvt.signal();
for (const char * pdo = name;
const char tdo = *pdo;
pdo++)
{
switch (tdo)
{
case 'd':
testDiag("'%c': Child deleting epicsThread", tdo);
delete pthread;
pthread = NULL;
break;
case 'e':
testDiag("'%c': Child calling exitWait()", tdo);
assert(pthread);
pthread->exitWait();
break;
case 's':
testDiag("'%c': Child sleeping", tdo);
epicsThreadSleep(SLEEP_TIME);
break;
case 't':
testDiag("'%c': Child sending trigger", tdo);
parentEvt.signal();
break;
case 'w':
testDiag("'%c': Child awaiting trigger", tdo);
childEvt.wait();
break;
case 'r':
testDiag("'%c': Child returning", tdo);
return;
}
}
testFail("Test case '%s' is missing 'r'", name);
}
MAIN(epicsThreadClassTest)
{
const int ntests = NELEMENTS(cases);
testPlan(ntests - 1); // The last element is the NULL terminator
for (const char * const * pcase = cases;
const char * const tcase = *pcase;
pcase++)
{
testDiag("======= Test case '%s' =======", tcase);
threadCase thrCase(tcase);
for (const char * pdo = tcase;
const char tdo = *pdo;
pdo++)
{
switch (tdo)
{
case 'B':
testDiag("'%c': Parent starting child", tdo);
assert(thrCase.pthread);
thrCase.pthread->start();
thrCase.startEvt.wait();
break;
case 'D':
testDiag("'%c': Parent deleting epicsThread", tdo);
assert(thrCase.pthread);
delete thrCase.pthread;
thrCase.pthread = NULL;
break;
case 'E':
testDiag("'%c': Parent calling exitWait()", tdo);
assert(thrCase.pthread);
thrCase.pthread->exitWait();
break;
case 'X':
testDiag("'%c': Parent calling exitWait(0)", tdo);
assert(thrCase.pthread);
thrCase.pthread->exitWait(0);
break;
case 'S':
testDiag("'%c': Parent sleeping", tdo);
epicsThreadSleep(SLEEP_TIME);
break;
case 'T':
testDiag("'%c': Parent sending trigger", tdo);
thrCase.childEvt.signal();
break;
case 'W':
testDiag("'%c': Parent awaiting trigger", tdo);
thrCase.parentEvt.wait();
break;
}
}
testPass("Test case '%s' passed", tcase);
}
return testDone();
}

View File

@@ -0,0 +1,62 @@
package EPICS::PodHtml;
use strict;
use warnings;
use base 'Pod::Simple::HTML';
sub encode_entities {
my ($self, $str) = @_;
my %entities = (
q{>} => 'gt',
q{<} => 'lt',
q{'} => '#39',
q{"} => 'quot',
q{&} => 'amp'
);
my $ents = join '', keys %entities;
$str =~ s/([$ents])/'&' . $entities{$1} . ';'/ge;
return $str;
}
# Translate L<link text|filename/Section name>
# into <a href="filename.html#Section-name">link text</a>
sub do_pod_link {
# EPICS::PodHtml object and Pod::Simple::PullParserStartToken object
my ($self, $link) = @_;
my $ret;
# Links to other EPICS POD files
if ($link->tagname eq 'L' and $link->attr('type') eq 'pod') {
my $to = $link->attr('to');
my $section = $link->attr('section');
$section = $self->section_escape($section)
if defined $section and length($section .= ''); # (stringify)
$ret = (defined $to and length $to) ? "$to.html" : '';
$ret .= "#$section" if defined $section and length $section;
}
else {
# all other links are generated by the parent class
$ret = $self->SUPER::do_pod_link($link);
}
return $ret;
}
# Generate the same section IDs as Pod::Simple::XHTML
sub section_name_tidy {
my($self, $section) = @_;
$section =~ s/^\s+//;
$section =~ s/\s+$//;
$section =~ tr/ /-/;
$section =~ s/[[:cntrl:][:^ascii:]]//g; # drop crazy characters
$section = $self->unicode_escape_url($section);
$section = '_' unless length $section;
return $section;
}
1;

View File

@@ -0,0 +1,40 @@
package EPICS::PodXHtml;
use strict;
use warnings;
use base 'Pod::Simple::XHTML';
BEGIN {
if ($Pod::Simple::XHTML::VERSION < '3.16') {
# encode_entities() wasn't a method, add it
our *encode_entities = sub {
my ($self, $str) = @_;
my %entities = (
q{>} => 'gt',
q{<} => 'lt',
q{'} => '#39',
q{"} => 'quot',
q{&} => 'amp'
);
my $ents = join '', keys %entities;
$str =~ s/([$ents])/'&' . $entities{$1} . ';'/ge;
return $str;
}
}
}
# Translate L<link text|filename/Section name>
# into <a href="filename.html#Section-name">link text</a>
sub resolve_pod_page_link {
my ($self, $to, $section) = @_;
my $ret = defined $to ? "$to.html" : '';
$ret .= '#' . $self->idify($self->encode_entities($section), 1)
if defined $section;
return $ret;
}
1;

View File

@@ -16,6 +16,8 @@ PERL_MODULES += EPICS/Path.pm
PERL_MODULES += EPICS/Release.pm
PERL_MODULES += EPICS/Readfile.pm
PERL_MODULES += EPICS/Getopts.pm
PERL_MODULES += EPICS/PodHtml.pm
PERL_MODULES += EPICS/PodXHtml.pm
# This goes into lib/perl, not bin/<host>
PERL_MODULES += EpicsHostArch.pl

View File

@@ -9,10 +9,13 @@
use strict;
use warnings;
use FindBin qw($Bin);
use lib "$Bin/../../lib/perl";
use Getopt::Std;
$Getopt::Std::STANDARD_HELP_VERSION = 1;
use Pod::Simple::HTML;
use EPICS::PodHtml;
use Pod::Usage;
@@ -86,7 +89,7 @@ my $root = '../' x scalar @inpath;
open my $out, '>', $opt_o or
die "Can't create $opt_o: $!\n";
my $podHtml = Pod::Simple::HTML->new();
my $podHtml = EPICS::PodHtml->new();
$podHtml->html_css($root . 'style.css');
$podHtml->perldoc_url_prefix('');