Merge branch '7.0' into add-simm-to-ao-records
This commit is contained in:
@@ -11,5 +11,6 @@
|
||||
|
||||
# This is a Makefile fragment, see src/ioc/Makefile.
|
||||
|
||||
$(patsubst %,$(COMMON_DIR)/%,$(BPT_DBD)) : \
|
||||
$(COMMON_DIR)/bpt%.dbd : $(MAKEBPT)
|
||||
$(addprefix $(COMMON_DIR)/,$(BPT_DBD)) : $(COMMON_DIR)/bpt%.dbd : \
|
||||
$(EPICS_BASE_HOST_BIN)/makeBpt$(HOSTEXE)
|
||||
# Don't try to use $(MAKEBPT) above
|
||||
|
||||
@@ -85,7 +85,7 @@ static epicsEventId startStopEvent;
|
||||
static char *threadNamePrefix[NUM_CALLBACK_PRIORITIES] = {
|
||||
"cbLow", "cbMedium", "cbHigh"
|
||||
};
|
||||
#define FULL_MSG(name) "callbackRequest: " name " ring buffer full\n"
|
||||
#define FULL_MSG(name) "callbackRequest: " ERL_ERROR " " name " ring buffer full\n"
|
||||
static char *fullMessage[NUM_CALLBACK_PRIORITIES] = {
|
||||
FULL_MSG("cbLow"), FULL_MSG("cbMedium"), FULL_MSG("cbHigh")
|
||||
};
|
||||
@@ -263,7 +263,9 @@ void callbackCleanup(void)
|
||||
|
||||
assert(epicsAtomicGetIntT(&mySet->threadsRunning)==0);
|
||||
epicsEventDestroy(mySet->semWakeUp);
|
||||
mySet->semWakeUp = NULL;
|
||||
epicsRingPointerDelete(mySet->queue);
|
||||
mySet->queue = NULL;
|
||||
}
|
||||
|
||||
epicsTimerQueueRelease(timerQueue);
|
||||
@@ -324,15 +326,19 @@ int callbackRequest(epicsCallback *pcallback)
|
||||
cbQueueSet *mySet;
|
||||
|
||||
if (!pcallback) {
|
||||
epicsInterruptContextMessage("callbackRequest: pcallback was NULL\n");
|
||||
epicsInterruptContextMessage("callbackRequest: " ERL_ERROR " pcallback was NULL\n");
|
||||
return S_db_notInit;
|
||||
}
|
||||
priority = pcallback->priority;
|
||||
if (priority < 0 || priority >= NUM_CALLBACK_PRIORITIES) {
|
||||
epicsInterruptContextMessage("callbackRequest: Bad priority\n");
|
||||
epicsInterruptContextMessage("callbackRequest: " ERL_ERROR " Bad priority\n");
|
||||
return S_db_badChoice;
|
||||
}
|
||||
mySet = &callbackQueue[priority];
|
||||
if (!mySet->queue) {
|
||||
epicsInterruptContextMessage("callbackRequest: " ERL_ERROR " Callbacks not initialized\n");
|
||||
return S_db_notInit;
|
||||
}
|
||||
if (mySet->queueOverflow) return S_db_bufFull;
|
||||
|
||||
pushOK = epicsRingPointerPush(mySet->queue, pcallback);
|
||||
|
||||
@@ -529,7 +529,7 @@ long dbProcess(dbCommon *precord)
|
||||
}
|
||||
}
|
||||
|
||||
/* If already active dont process */
|
||||
/* If already active don't process */
|
||||
if (precord->pact) {
|
||||
unsigned short monitor_mask;
|
||||
|
||||
@@ -931,7 +931,7 @@ long dbGet(DBADDR *paddr, short dbrType,
|
||||
no_elements = capacity = pfl->no_elements;
|
||||
}
|
||||
|
||||
/* Update field info from record (if neccessary);
|
||||
/* Update field info from record (if necessary);
|
||||
* may modify paddr->pfield.
|
||||
*/
|
||||
if (!dbfl_has_copy(pfl) &&
|
||||
@@ -1104,9 +1104,9 @@ static long dbPutFieldLink(DBADDR *paddr,
|
||||
if (link_info.ltype == PV_LINK &&
|
||||
(link_info.modifiers & (pvlOptCA | pvlOptCP | pvlOptCPP)) == 0) {
|
||||
chan = dbChannelCreate(link_info.target);
|
||||
if (chan && dbChannelOpen(chan) != 0) {
|
||||
errlogPrintf("ERROR: dbPutFieldLink %s.%s=%s: dbChannelOpen() failed\n",
|
||||
precord->name, pfldDes->name, link_info.target);
|
||||
if (chan && (status = dbChannelOpen(chan)) != 0) {
|
||||
errlogPrintf(ERL_ERROR ": dbPutFieldLink %s.%s=%s: dbChannelOpen() failed w/ 0x%lx\n",
|
||||
precord->name, pfldDes->name, link_info.target, status);
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
@@ -1325,7 +1325,6 @@ long dbPut(DBADDR *paddr, short dbrType,
|
||||
void *pfieldsave = paddr->pfield;
|
||||
rset *prset = dbGetRset(paddr);
|
||||
long status = 0;
|
||||
long offset;
|
||||
dbFldDes *pfldDes;
|
||||
int isValueField;
|
||||
|
||||
@@ -1349,20 +1348,25 @@ long dbPut(DBADDR *paddr, short dbrType,
|
||||
if (status) return status;
|
||||
}
|
||||
|
||||
if (paddr->pfldDes->special == SPC_DBADDR &&
|
||||
prset && prset->get_array_info) {
|
||||
long dummy;
|
||||
if (nRequest>1 || paddr->pfldDes->special == SPC_DBADDR) {
|
||||
long offset = 0;
|
||||
if (paddr->pfldDes->special == SPC_DBADDR &&
|
||||
prset && prset->get_array_info) {
|
||||
long dummy;
|
||||
|
||||
status = prset->get_array_info(paddr, &dummy, &offset);
|
||||
/* paddr->pfield may be modified */
|
||||
if (status) goto done;
|
||||
status = prset->get_array_info(paddr, &dummy, &offset);
|
||||
/* paddr->pfield may be modified */
|
||||
if (status) goto done;
|
||||
}
|
||||
if (no_elements < nRequest)
|
||||
nRequest = no_elements;
|
||||
status = dbPutConvertRoutine[dbrType][field_type](paddr, pbuffer,
|
||||
nRequest, no_elements, offset);
|
||||
/* update array info */
|
||||
if (!status && prset->put_array_info)
|
||||
if (!status && paddr->pfldDes->special == SPC_DBADDR &&
|
||||
prset && prset->put_array_info) {
|
||||
status = prset->put_array_info(paddr, nRequest);
|
||||
}
|
||||
} else {
|
||||
if (nRequest < 1) {
|
||||
recGblSetSevr(precord, LINK_ALARM, INVALID_ALARM);
|
||||
|
||||
@@ -73,7 +73,7 @@ DBCORE_API extern int dbAccessDebugPUTF;
|
||||
* options has a bit set for each option that was accepted
|
||||
* number_elements is actual number of elements obtained
|
||||
*
|
||||
* The individual items can be refered to by the expressions::
|
||||
* The individual items can be referred to by the expressions::
|
||||
*
|
||||
* buffer.status
|
||||
* buffer.severity
|
||||
|
||||
@@ -97,7 +97,7 @@ static long FIND_CONT_NODE(
|
||||
* processing in that lockset to this task. The separate task is
|
||||
* used so that locksets that do not have breakpoints are isolated
|
||||
* from locksets that do. This allows the processing of other
|
||||
* locksets to continue uninterupted, even if they exist on the same
|
||||
* locksets to continue uninterrupted, even if they exist on the same
|
||||
* scan list as a lockset containing a breakpoint.
|
||||
*
|
||||
* An entrypoint is the first record that gets processed in a lockset.
|
||||
@@ -250,7 +250,7 @@ static long FIND_CONT_NODE(
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise the breakpoint stack
|
||||
* Initialize the breakpoint stack
|
||||
*/
|
||||
void dbBkptInit(void)
|
||||
{
|
||||
@@ -331,6 +331,7 @@ long dbb(const char *record_name)
|
||||
if (pnode->ex_sem == NULL) {
|
||||
printf(" BKPT> Out of memory\n");
|
||||
dbScanUnlock(precord);
|
||||
free(pnode);
|
||||
epicsMutexUnlock(bkpt_stack_sem);
|
||||
return(1);
|
||||
}
|
||||
|
||||
@@ -196,6 +196,73 @@ static void caLinkDec(caLink *pca)
|
||||
if (callback) callback(userPvt);
|
||||
}
|
||||
|
||||
struct waitPvt {
|
||||
caLink *pca;
|
||||
epicsEventId evt;
|
||||
};
|
||||
enum testEvent {
|
||||
testEventConnect,
|
||||
testEventCount,
|
||||
};
|
||||
|
||||
static
|
||||
void testdbCaWaitForEventCB(void *raw)
|
||||
{
|
||||
struct waitPvt *pvt = raw;
|
||||
|
||||
epicsMutexMustLock(pvt->pca->lock);
|
||||
epicsEventMustTrigger(pvt->evt);
|
||||
epicsMutexUnlock(pvt->pca->lock);
|
||||
}
|
||||
|
||||
static
|
||||
void testdbCaWaitForEvent(DBLINK *plink, unsigned long cnt, enum testEvent event)
|
||||
{
|
||||
caLink *pca;
|
||||
epicsEventId evt = epicsEventMustCreate(epicsEventEmpty);
|
||||
|
||||
dbScanLock(plink->precord);
|
||||
|
||||
assert(plink->type==CA_LINK);
|
||||
pca = (caLink *)plink->value.pv_link.pvt;
|
||||
|
||||
epicsMutexMustLock(pca->lock);
|
||||
assert(!pca->monitor && !pca->connect && !pca->userPvt);
|
||||
|
||||
while(!pca->isConnected || (event==testEventCount && pca->nUpdate < cnt)) {
|
||||
struct waitPvt pvt = {pca, evt};
|
||||
pca->connect = &testdbCaWaitForEventCB;
|
||||
pca->monitor = &testdbCaWaitForEventCB;
|
||||
pca->userPvt = &pvt;
|
||||
|
||||
epicsMutexUnlock(pca->lock);
|
||||
dbScanUnlock(plink->precord);
|
||||
|
||||
epicsEventMustWait(evt);
|
||||
|
||||
dbScanLock(plink->precord);
|
||||
epicsMutexMustLock(pca->lock);
|
||||
|
||||
pca->connect = NULL;
|
||||
pca->monitor = NULL;
|
||||
pca->userPvt = NULL;
|
||||
}
|
||||
|
||||
epicsEventDestroy(evt);
|
||||
epicsMutexUnlock(pca->lock);
|
||||
dbScanUnlock(plink->precord);
|
||||
}
|
||||
|
||||
void testdbCaWaitForConnect(DBLINK *plink)
|
||||
{
|
||||
testdbCaWaitForEvent(plink, 0, testEventConnect);
|
||||
}
|
||||
|
||||
void testdbCaWaitForUpdateCount(DBLINK *plink, unsigned long cnt)
|
||||
{
|
||||
testdbCaWaitForEvent(plink, cnt, testEventCount);
|
||||
}
|
||||
|
||||
/* Block until worker thread has processed all previously queued actions.
|
||||
* Does not prevent additional actions from being queued.
|
||||
*/
|
||||
@@ -232,22 +299,6 @@ void dbCaSync(void)
|
||||
epicsEventDestroy(wake);
|
||||
}
|
||||
|
||||
DBCORE_API unsigned long dbCaGetUpdateCount(struct link *plink)
|
||||
{
|
||||
caLink *pca = (caLink *)plink->value.pv_link.pvt;
|
||||
unsigned long ret;
|
||||
|
||||
if (!pca) return (unsigned long)-1;
|
||||
|
||||
epicsMutexMustLock(pca->lock);
|
||||
|
||||
ret = pca->nUpdate;
|
||||
|
||||
epicsMutexUnlock(pca->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void dbCaCallbackProcess(void *userPvt)
|
||||
{
|
||||
struct link *plink = (struct link *)userPvt;
|
||||
@@ -785,6 +836,8 @@ static void connectionCallback(struct connection_handler_args arg)
|
||||
caLink *pca;
|
||||
short link_action = 0;
|
||||
struct link *plink;
|
||||
dbCaCallback connect = 0;
|
||||
void *userPvt = 0;
|
||||
|
||||
pca = ca_puser(arg.chid);
|
||||
assert(pca);
|
||||
@@ -851,11 +904,16 @@ static void connectionCallback(struct connection_handler_args arg)
|
||||
}
|
||||
pca->gotAttributes = 0;
|
||||
if (pca->dbrType != DBR_STRING) {
|
||||
/* will run connect() callback later */
|
||||
link_action |= CA_GET_ATTRIBUTES;
|
||||
} else {
|
||||
connect = pca->connect;
|
||||
userPvt = pca->userPvt;
|
||||
}
|
||||
done:
|
||||
if (link_action) addAction(pca, link_action);
|
||||
epicsMutexUnlock(pca->lock);
|
||||
if (connect) connect(userPvt);
|
||||
}
|
||||
|
||||
static void eventCallback(struct event_handler_args arg)
|
||||
@@ -881,10 +939,10 @@ static void eventCallback(struct event_handler_args arg)
|
||||
if (precord) {
|
||||
if (arg.status != ECA_NORDACCESS &&
|
||||
arg.status != ECA_GETFAIL)
|
||||
errlogPrintf("dbCa: eventCallback record %s error %s\n",
|
||||
errlogPrintf("dbCa: eventCallback record %s " ERL_ERROR " %s\n",
|
||||
precord->name, ca_message(arg.status));
|
||||
} else {
|
||||
errlogPrintf("dbCa: eventCallback error %s\n",
|
||||
errlogPrintf("dbCa: eventCallback " ERL_ERROR " %s\n",
|
||||
ca_message(arg.status));
|
||||
}
|
||||
goto done;
|
||||
@@ -1029,10 +1087,10 @@ static void getAttribEventCallback(struct event_handler_args arg)
|
||||
if (arg.status != ECA_NORMAL) {
|
||||
dbCommon *precord = plink->precord;
|
||||
if (precord) {
|
||||
errlogPrintf("dbCa: getAttribEventCallback record %s error %s\n",
|
||||
errlogPrintf("dbCa: getAttribEventCallback record %s " ERL_ERROR " %s\n",
|
||||
precord->name, ca_message(arg.status));
|
||||
} else {
|
||||
errlogPrintf("dbCa: getAttribEventCallback error %s\n",
|
||||
errlogPrintf("dbCa: getAttribEventCallback " ERL_ERROR " %s\n",
|
||||
ca_message(arg.status));
|
||||
}
|
||||
epicsMutexUnlock(pca->lock);
|
||||
@@ -1058,6 +1116,7 @@ static void getAttribEventCallback(struct event_handler_args arg)
|
||||
|
||||
static void dbCaTask(void *arg)
|
||||
{
|
||||
epicsEventId requestSync = NULL;
|
||||
taskwdInsert(0, NULL, NULL);
|
||||
SEVCHK(ca_context_create(ca_enable_preemptive_callback),
|
||||
"dbCaTask calling ca_context_create");
|
||||
@@ -1078,13 +1137,20 @@ static void dbCaTask(void *arg)
|
||||
|
||||
epicsMutexMustLock(workListLock);
|
||||
if (!(pca = (caLink *)ellGet(&workList))){ /* Take off list head */
|
||||
if(requestSync) {
|
||||
/* dbCaSync() requires workListLock to be held here */
|
||||
epicsEventMustTrigger(requestSync);
|
||||
requestSync = NULL;
|
||||
}
|
||||
epicsMutexUnlock(workListLock);
|
||||
if (dbCaCtl == ctlExit) goto shutdown;
|
||||
break; /* workList is empty */
|
||||
}
|
||||
link_action = pca->link_action;
|
||||
if (link_action&CA_SYNC)
|
||||
epicsEventMustTrigger((epicsEventId)pca->userPvt); /* dbCaSync() requires workListLock to be held here */
|
||||
if (link_action&CA_SYNC) {
|
||||
assert(!requestSync);
|
||||
requestSync = pca->userPvt;
|
||||
}
|
||||
pca->link_action = 0;
|
||||
if (link_action & CA_CLEAR_CHANNEL) --removesOutstanding;
|
||||
epicsMutexUnlock(workListLock); /* Give back immediately */
|
||||
|
||||
@@ -48,8 +48,12 @@ DBCORE_API long dbCaPutLink(struct link *plink,short dbrType,
|
||||
extern struct ca_client_context * dbCaClientContext;
|
||||
|
||||
#ifdef EPICS_DBCA_PRIVATE_API
|
||||
/* Wait CA link work queue to become empty. eg. after from dbPut() to OUT */
|
||||
DBCORE_API void dbCaSync(void);
|
||||
DBCORE_API unsigned long dbCaGetUpdateCount(struct link *plink);
|
||||
/* Wait for the data update counter to reach the specified value. */
|
||||
DBCORE_API void testdbCaWaitForUpdateCount(DBLINK *plink, unsigned long cnt);
|
||||
/* Wait for CA link to become connected */
|
||||
DBCORE_API void testdbCaWaitForConnect(DBLINK *plink);
|
||||
#endif
|
||||
|
||||
/* These macros are for backwards compatibility */
|
||||
|
||||
@@ -77,12 +77,12 @@ 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:
|
||||
local copy of menuScan.dbd and adding more choices as required. Periodic scan
|
||||
rates should normally be defined in order following the other scan types, with
|
||||
the longest periods appearing first. Scan periods can be specified with a unit
|
||||
string of C<second>/C<seconds>, C<minute>/C<minutes>, C<hour>/C<hours> or
|
||||
C<Hertz>/C<Hz>. Seconds are used if no unit is included in the choice string.
|
||||
For example these rates are all valid:
|
||||
|
||||
1 hour
|
||||
0.5 hours
|
||||
@@ -97,7 +97,7 @@ 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
|
||||
before those with higher phase number. It is generally better practice to use
|
||||
linked passive records to enforce the order of processing rather than a phase
|
||||
number.
|
||||
|
||||
@@ -109,23 +109,23 @@ 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
|
||||
The B<DISV> field specifies a "disable value". Record processing cannot
|
||||
begin when the value of this field is equal to the value of the DISA
|
||||
field, meaning the record is disabled. Note that field values of a record
|
||||
can be changed by database or Channel Access puts, even if the 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<DISA> field contains the value that is compared with DISV to determine if
|
||||
the record is disabled. A value is obtained for the DISA field from the B<SDIS>
|
||||
link field before the IOC tries to process the record. If SDIS is not set, DISA
|
||||
may be set by some other method to enable and disable the record.
|
||||
|
||||
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.
|
||||
|
||||
If the B<PROC> field of a record is written to, the record is processed.
|
||||
|
||||
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
|
||||
@@ -135,15 +135,18 @@ 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
|
||||
The B<PACT> field is TRUE while the record is active (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<FLNK> field is a link pointing to another record (the "target" record).
|
||||
Processing a record with the FLNK field set will trigger processing of the
|
||||
target record towards the end of processing the first record (but before PACT is
|
||||
cleared), provided the target record's SCAN field is set to C<Passive>. If the
|
||||
FLNK field is a Channel Access link it must point to the PROC field of the
|
||||
target record.
|
||||
|
||||
The B<SPVT> field is for internal use by the scanning system.
|
||||
|
||||
@@ -227,6 +230,8 @@ The B<SPVT> field is for internal use by the scanning system.
|
||||
}
|
||||
field(DISP,DBF_UCHAR) {
|
||||
prompt("Disable putField")
|
||||
promptgroup("10 - Common")
|
||||
interest(1)
|
||||
}
|
||||
field(PROC,DBF_UCHAR) {
|
||||
prompt("Force Processing")
|
||||
@@ -236,35 +241,46 @@ The B<SPVT> field is for internal use by the scanning system.
|
||||
|
||||
=head3 Alarm Fields
|
||||
|
||||
These fields indicate the status and severity of alarms, or else determine the
|
||||
Alarm fields indicate the status and severity of record alarms, or determine
|
||||
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
|
||||
fields not common to all records. Those 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<AMSG> string field may contain more detailed information about the alarm.
|
||||
|
||||
The STAT, SEVR and AMSG fields hold alarm information as seen outside of the
|
||||
database. The B<NSTA>, B<NSEV> and B<NAMSG> fields are used during record
|
||||
processing by the database access, record support, and device support routines
|
||||
to set new alarm status and severity values and message text. Whenever any
|
||||
software component discovers an alarm condition, it calls one of these routines
|
||||
to register the alarm:
|
||||
|
||||
recGblSetSevr(precord, new_status, new_severity);
|
||||
recGblSetSevrMsg(precord, new_status, new_severity, "Message", ...);
|
||||
|
||||
These check the current alarm severity and update the NSTA, NSEV and NAMSG
|
||||
fields if appropriate so they always relate to the highest severity alarm seen
|
||||
so far during record processing. The file alarm.h defines the allowed alarm
|
||||
status and severity values. Towards the end of record processing these fields
|
||||
are copied into the STAT, SEVR and AMSG fields and alarm monitors triggered.
|
||||
|
||||
The B<ACKS> field contains the highest unacknowledged alarm severity.
|
||||
|
||||
The B<ACKT> field specifies if it is necessary to acknowledge transient
|
||||
The B<ACKT> field specifies whether 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.
|
||||
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) or
|
||||
Inf (Infinite) value. UDF defaults to TRUE but can be set in a database file.
|
||||
Record and device support routines which write to the VAL field are generally
|
||||
responsible for setting and clearing UDF.
|
||||
|
||||
=fields STAT, SEVR, NSTA, NSEV, ACKS, ACKT, UDF
|
||||
=fields STAT, SEVR, AMSG, NSTA, NSEV, NAMSG, ACKS, ACKT, UDF
|
||||
|
||||
=cut
|
||||
|
||||
@@ -422,9 +438,11 @@ The B<DPVT> field is is for private use of the device support modules.
|
||||
|
||||
=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<TPRO> field can be used to trace record processing. When this field is
|
||||
non-zero and the record is processed, a trace message will be be printed for
|
||||
this record and any other record in the same lock-set that is triggered by a
|
||||
database link from this record. The trace message includes the name of the
|
||||
thread doing the processing, and the name of the record being processed.
|
||||
|
||||
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
|
||||
@@ -435,32 +453,27 @@ database processing can be supported using this.
|
||||
|
||||
=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<ASG> string field sets the name of the access security group used for this
|
||||
record. If left empty, the record is placed in group C<DEFAULT>.
|
||||
|
||||
The B<ASP> field is a field for private use of the access security system.
|
||||
The B<ASP> field is private for use by 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<DISP> field can be set to a non-zero value to reject puts from outside of
|
||||
the IOC (i.e. via Channel Access or PV Access) to any field of the record other
|
||||
than to the DISP field itself. Field changes and record processing can still be
|
||||
instigated from inside the IOC using DB links and the IOC scan mechanisms.
|
||||
|
||||
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<DTYP> field specifies the device type for the record. Most record types
|
||||
have their own set of device types which are specified in the IOC's database
|
||||
definition file. If a record type does not call any device support routines,
|
||||
the DTYP and DSET fields are not used.
|
||||
|
||||
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<MLOK> field contains a mutex which is locked by the monitor routines in
|
||||
dbEvent.c whenever the monitor list for this record is accessed.
|
||||
|
||||
The B<MLIS> field is the head of the list of monitors connected to this
|
||||
The B<MLIS> field holds a linked list of client 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.
|
||||
any fields that change as a result of record processing.
|
||||
|
||||
The B<PPN> field contains the address of a putNotify callback.
|
||||
|
||||
@@ -474,23 +487,44 @@ 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<TIME> field holds the time stamp when this record was last processed.
|
||||
|
||||
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<UTAG> field can be used to hold a site-specific 64-bit User Tag value
|
||||
that is associated with the record's time stamp.
|
||||
|
||||
The B<TSE> field value indicates the mechanism to use to get the time stamp:
|
||||
|
||||
=over
|
||||
|
||||
=item *
|
||||
|
||||
C< 0> E<mdash> Get the current time as normal
|
||||
|
||||
=item *
|
||||
|
||||
C<-1> E<mdash> Ask the time stamp driver for its best source of the current time, if
|
||||
available.
|
||||
|
||||
=item *
|
||||
|
||||
C<-2> E<mdash> Device support sets the time stamp and the optional User Tag from the
|
||||
hardware.
|
||||
|
||||
=item *
|
||||
|
||||
Positive values (normally between 1-255) get the time of the last occurance of
|
||||
the numbered generalTime event.
|
||||
|
||||
=back
|
||||
|
||||
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.
|
||||
link points to the TIME field of a record then the time stamp and User Tag of
|
||||
that record are copied directly into this record (Channel Access links can only
|
||||
copy the time stamp, not the User Tag). If the link points to any other field,
|
||||
that field's value is read and stored in the TSE field which is then used to
|
||||
provide the time stamp as described above.
|
||||
|
||||
=fields ASG, ASP, DISP, DTYP, MLOK, MLIS, PPN, PPNR, PUTF, RDES, RPRO, TIME, TSE, TSEL
|
||||
=fields ASG, ASP, DISP, DTYP, MLOK, MLIS, PPN, PPNR, PUTF, RDES, RPRO, TIME, UTAG, TSE, TSEL
|
||||
|
||||
=cut
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ cvt_st_ ## TYPE(const char *from, void *pfield, const dbAddr *paddr) { \
|
||||
return epicsParse##TYPE(from, to, 0, &end); \
|
||||
}
|
||||
|
||||
/* Instanciate for CHAR, UCHAR, SHORT, USHORT and LONG */
|
||||
/* Instantiate for CHAR, UCHAR, SHORT, USHORT and LONG */
|
||||
cvt_st_int(Int8)
|
||||
cvt_st_int(UInt8)
|
||||
cvt_st_int(Int16)
|
||||
@@ -99,7 +99,7 @@ static long cvt_st_UInt32(const char *from, void *pfield, const dbAddr *paddr)
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Instanciate for INT64 and UINT64 */
|
||||
/* Instantiate for INT64 and UINT64 */
|
||||
cvt_st_int(Int64)
|
||||
cvt_st_int(UInt64)
|
||||
|
||||
@@ -117,7 +117,7 @@ cvt_st_ ## TYPE(const char *from, void *pfield, const dbAddr *paddr) { \
|
||||
return epicsParse##TYPE(from, to, &end); \
|
||||
}
|
||||
|
||||
/* Instanciate for FLOAT32 and FLOAT64 */
|
||||
/* Instantiate for FLOAT32 and FLOAT64 */
|
||||
cvt_st_float(Float32)
|
||||
cvt_st_float(Float64)
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
\*************************************************************************/
|
||||
|
||||
/*
|
||||
* Auther Jeff Hill
|
||||
* Author Jeff Hill
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -98,7 +98,7 @@ static int dblsj_string(void *ctx, const unsigned char *val, size_t len) {
|
||||
char *pdest = parser->pdest;
|
||||
|
||||
if (parser->dbrType != DBF_STRING) {
|
||||
errlogPrintf("dbConvertJSON: dblsj_string dbrType error\n");
|
||||
errlogPrintf("dbConvertJSON: dblsj_string dbrType " ERL_ERROR "\n");
|
||||
return 0; /* Illegal */
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* This name should probably be changed to inclue "array" */
|
||||
/* This name should probably be changed to include "array" */
|
||||
DBCORE_API long dbPutConvertJSON(const char *json, short dbrType,
|
||||
void *pdest, long *psize);
|
||||
DBCORE_API long dbLSConvertJSON(const char *json, char *pdest,
|
||||
|
||||
@@ -188,8 +188,11 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer,
|
||||
&& dbChannelSpecial(chan) != SPC_ATTRIBUTE
|
||||
&& ellCount(&chan->filters) == 0)
|
||||
{
|
||||
/* simple scalar: set up shortcut */
|
||||
unsigned short dbfType = dbChannelFinalFieldType(chan);
|
||||
/* Simple scalar w/o filters, so *Final* type has no additional information.
|
||||
* Needed to correctly handle DBF_MENU fields, which become DBF_ENUM during
|
||||
* probe of dbChannelOpen().
|
||||
*/
|
||||
unsigned short dbfType = dbChannelFieldType(chan);
|
||||
|
||||
if (dbrType < 0 || dbrType > DBR_ENUM || dbfType > DBF_DEVICE)
|
||||
return S_db_badDbrtype;
|
||||
|
||||
@@ -84,12 +84,13 @@ struct event_user {
|
||||
epicsMutexId lock;
|
||||
epicsEventId ppendsem; /* Wait while empty */
|
||||
epicsEventId pflush_sem; /* wait for flush */
|
||||
epicsEventId pexitsem; /* wait for event task to join */
|
||||
|
||||
EXTRALABORFUNC *extralabor_sub;/* off load to event task */
|
||||
void *extralabor_arg;/* parameter to above */
|
||||
|
||||
epicsThreadId taskid; /* event handler task id */
|
||||
struct evSubscrip *pSuicideEvent; /* event that is deleteing itself */
|
||||
struct evSubscrip *pSuicideEvent; /* event that is deleting itself */
|
||||
unsigned queovr; /* event que overflow count */
|
||||
unsigned char pendexit; /* exit pend task */
|
||||
unsigned char extra_labor; /* if set call extra labor func */
|
||||
@@ -101,7 +102,7 @@ struct event_user {
|
||||
|
||||
/*
|
||||
* Reliable intertask communication requires copying the current value of the
|
||||
* channel for later queing so 3 stepper motor steps of 10 each do not turn
|
||||
* channel for later queuing so 3 stepper motor steps of 10 each do not turn
|
||||
* into only 10 or 20 total steps part of the time.
|
||||
*/
|
||||
|
||||
@@ -122,6 +123,8 @@ static char *EVENT_PEND_NAME = "eventTask";
|
||||
|
||||
static struct evSubscrip canceledEvent;
|
||||
|
||||
static epicsMutexId stopSync;
|
||||
|
||||
static unsigned short ringSpace ( const struct event_que *pevq )
|
||||
{
|
||||
if ( pevq->evque[pevq->putix] == EVENTQEMPTY ) {
|
||||
@@ -260,6 +263,10 @@ int dbel ( const char *pname, unsigned level )
|
||||
*/
|
||||
void db_init_event_freelists (void)
|
||||
{
|
||||
if (!stopSync) {
|
||||
stopSync = epicsMutexMustCreate();
|
||||
}
|
||||
|
||||
if (!dbevEventUserFreeList) {
|
||||
freeListInitPvt(&dbevEventUserFreeList,
|
||||
sizeof(struct event_user),8);
|
||||
@@ -299,6 +306,9 @@ dbEventCtx db_init_events (void)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Flag will be cleared when event task starts */
|
||||
evUser->pendexit = TRUE;
|
||||
|
||||
evUser->firstque.evUser = evUser;
|
||||
evUser->firstque.writelock = epicsMutexCreate();
|
||||
if (!evUser->firstque.writelock)
|
||||
@@ -313,6 +323,9 @@ dbEventCtx db_init_events (void)
|
||||
evUser->lock = epicsMutexCreate();
|
||||
if (!evUser->lock)
|
||||
goto fail;
|
||||
evUser->pexitsem = epicsEventCreate(epicsEventEmpty);
|
||||
if (!evUser->pexitsem)
|
||||
goto fail;
|
||||
|
||||
evUser->flowCtrlMode = FALSE;
|
||||
evUser->extraLaborBusy = FALSE;
|
||||
@@ -327,6 +340,8 @@ fail:
|
||||
epicsEventDestroy (evUser->ppendsem);
|
||||
if(evUser->pflush_sem)
|
||||
epicsEventDestroy (evUser->pflush_sem);
|
||||
if(evUser->pexitsem)
|
||||
epicsEventDestroy (evUser->pexitsem);
|
||||
freeListFree(dbevEventUserFreeList,evUser);
|
||||
return NULL;
|
||||
}
|
||||
@@ -347,6 +362,7 @@ DBCORE_API void db_cleanup_events(void)
|
||||
dbevFieldLogFreeList = NULL;
|
||||
}
|
||||
|
||||
/* intentionally leak stopSync to avoid possible shutdown races */
|
||||
/*
|
||||
* DB_CLOSE_EVENTS()
|
||||
*
|
||||
@@ -368,15 +384,31 @@ void db_close_events (dbEventCtx ctx)
|
||||
* hazardous to the system's health.
|
||||
*/
|
||||
epicsMutexMustLock ( evUser->lock );
|
||||
evUser->pendexit = TRUE;
|
||||
if(!evUser->pendexit) { /* event task running */
|
||||
evUser->pendexit = TRUE;
|
||||
epicsMutexUnlock ( evUser->lock );
|
||||
|
||||
/* notify the waiting task */
|
||||
epicsEventSignal(evUser->ppendsem);
|
||||
/* wait for task to exit */
|
||||
epicsEventMustWait(evUser->pexitsem);
|
||||
epicsThreadMustJoin(evUser->taskid);
|
||||
|
||||
epicsMutexMustLock ( evUser->lock );
|
||||
}
|
||||
|
||||
epicsMutexUnlock ( evUser->lock );
|
||||
|
||||
/* notify the waiting task */
|
||||
epicsEventSignal(evUser->ppendsem);
|
||||
epicsMutexMustLock (stopSync);
|
||||
|
||||
if(evUser->taskid)
|
||||
epicsThreadMustJoin(evUser->taskid);
|
||||
/* evUser has been deleted by the worker */
|
||||
epicsEventDestroy(evUser->pexitsem);
|
||||
epicsEventDestroy(evUser->ppendsem);
|
||||
epicsEventDestroy(evUser->pflush_sem);
|
||||
epicsMutexDestroy(evUser->lock);
|
||||
|
||||
epicsMutexUnlock (stopSync);
|
||||
|
||||
freeListFree(dbevEventUserFreeList, evUser);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -553,7 +585,7 @@ void db_cancel_event (dbEventSubscription event)
|
||||
/*
|
||||
* flag the event as canceled by NULLing out the callback handler
|
||||
*
|
||||
* make certain that the event isnt being accessed while
|
||||
* make certain that the event isn't being accessed while
|
||||
* its call back changes
|
||||
*/
|
||||
LOCKEVQUE (pevent->ev_que);
|
||||
@@ -779,7 +811,7 @@ static void db_queue_event_log (evSubscrip *pevent, db_field_log *pLog)
|
||||
pevent->nreplace++;
|
||||
/*
|
||||
* the event task has already been notified about
|
||||
* this so we dont need to post the semaphore
|
||||
* this so we don't need to post the semaphore
|
||||
*/
|
||||
firstEventFlag = 0;
|
||||
}
|
||||
@@ -812,7 +844,7 @@ static void db_queue_event_log (evSubscrip *pevent, db_field_log *pLog)
|
||||
UNLOCKEVQUE (ev_que);
|
||||
|
||||
/*
|
||||
* its more efficent to notify the event handler
|
||||
* its more efficient to notify the event handler
|
||||
* only after the event is ready and the lock
|
||||
* is off in case it runs at a higher priority
|
||||
* than the caller here.
|
||||
@@ -854,6 +886,8 @@ unsigned int caEventMask
|
||||
if ( (dbChannelField(pevent->chan) == (void *)pField || pField==NULL) &&
|
||||
(caEventMask & pevent->select)) {
|
||||
db_field_log *pLog = db_create_event_log(pevent);
|
||||
if(pLog)
|
||||
pLog->mask = caEventMask & pevent->select;
|
||||
pLog = dbChannelRunPreChain(pevent->chan, pLog);
|
||||
if (pLog) db_queue_event_log(pevent, pLog);
|
||||
}
|
||||
@@ -942,7 +976,7 @@ static int event_read ( struct event_que *ev_que )
|
||||
* Next event pointer can be used by event tasks to determine
|
||||
* if more events are waiting in the queue
|
||||
*
|
||||
* Must remove the lock here so that we dont deadlock if
|
||||
* Must remove the lock here so that we don't deadlock if
|
||||
* this calls dbGetField() and blocks on the record lock,
|
||||
* dbPutField() is in progress in another task, it has the
|
||||
* record lock, and it is calling db_post_events() waiting
|
||||
@@ -1063,18 +1097,17 @@ static void event_task (void *pParm)
|
||||
}
|
||||
}
|
||||
|
||||
epicsEventDestroy(evUser->ppendsem);
|
||||
epicsEventDestroy(evUser->pflush_sem);
|
||||
epicsMutexDestroy(evUser->lock);
|
||||
|
||||
if (dbevEventUserFreeList)
|
||||
freeListFree(dbevEventUserFreeList, evUser);
|
||||
else
|
||||
fprintf(stderr, "%s exiting but dbevEventUserFreeList already NULL\n",
|
||||
__FUNCTION__);
|
||||
|
||||
taskwdRemove(epicsThreadGetIdSelf());
|
||||
|
||||
/* use stopSync to ensure pexitsem is not destroy'd
|
||||
* until epicsEventSignal() has returned.
|
||||
*/
|
||||
epicsMutexMustLock (stopSync);
|
||||
|
||||
epicsEventSignal(evUser->pexitsem);
|
||||
|
||||
epicsMutexUnlock(stopSync);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1114,6 +1147,7 @@ int db_start_events (
|
||||
epicsMutexUnlock ( evUser->lock );
|
||||
return DB_EVENT_ERROR;
|
||||
}
|
||||
evUser->pendexit = FALSE;
|
||||
epicsMutexUnlock ( evUser->lock );
|
||||
return DB_EVENT_OK;
|
||||
}
|
||||
@@ -1142,9 +1176,6 @@ void db_event_flow_ctrl_mode_on (dbEventCtx ctx)
|
||||
* notify the event handler task
|
||||
*/
|
||||
epicsEventSignal(evUser->ppendsem);
|
||||
#ifdef DEBUG
|
||||
printf("fc on %lu\n", tickGet());
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1161,9 +1192,6 @@ void db_event_flow_ctrl_mode_off (dbEventCtx ctx)
|
||||
* notify the event handler task
|
||||
*/
|
||||
epicsEventSignal (evUser->ppendsem);
|
||||
#ifdef DEBUG
|
||||
printf("fc off %lu\n", tickGet());
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -234,7 +234,7 @@ static const iocshArg dbtgfArg0 = { "record name",iocshArgString};
|
||||
static const iocshArg * const dbtgfArgs[1] = {&dbtgfArg0};
|
||||
static const iocshFuncDef dbtgfFuncDef = {"dbtgf",1,dbtgfArgs,
|
||||
"Database Test Get Field.\n"
|
||||
"Get field with different DBR_* types"};
|
||||
"Get field with different DBR_* types\n"};
|
||||
static void dbtgfCallFunc(const iocshArgBuf *args) { dbtgf(args[0].sval);}
|
||||
|
||||
/* dbtpf */
|
||||
@@ -283,7 +283,7 @@ static const iocshArg * const dbtpnArgs[2] = {&dbtpnArg0,&dbtpnArg1};
|
||||
static const iocshFuncDef dbtpnFuncDef = {"dbtpn",2,dbtpnArgs,
|
||||
"Database Put Notify\n"
|
||||
"Without value, begin async. processing and get\n"
|
||||
"With value, begin put, process, and get"};
|
||||
"With value, begin put, process, and get\n"};
|
||||
static void dbtpnCallFunc(const iocshArgBuf *args)
|
||||
{ dbtpn(args[0].sval,args[1].sval);}
|
||||
|
||||
|
||||
@@ -371,7 +371,7 @@ typedef struct lset {
|
||||
* Implementations must write a trailing nil to msgbuf whenever
|
||||
* @code msgbuf!=NULL && msgbuflen>0 @endcode .
|
||||
*
|
||||
* @since UNRELEASED
|
||||
* @since 7.0.6
|
||||
*/
|
||||
long (*getAlarmMsg)(const struct link *plink, epicsEnum16 *status,
|
||||
epicsEnum16 *severity, char *msgbuf, size_t msgbuflen);
|
||||
@@ -381,7 +381,7 @@ typedef struct lset {
|
||||
* Equivalent of getTimeStamp() and also copy out time tag.
|
||||
* ptag may be NULL.
|
||||
*
|
||||
* @since Added after UNRELEASED
|
||||
* @since Added after 7.0.6
|
||||
*/
|
||||
long (*getTimeStampTag)(const struct link *plink, epicsTimeStamp *pstamp, epicsUTag *ptag);
|
||||
} lset;
|
||||
@@ -428,14 +428,14 @@ DBCORE_API long dbGetAlarm(const struct link *plink, epicsEnum16 *status,
|
||||
/** Get link alarm and message string.
|
||||
* To ensure the complete message string is copied, ensure @code msgbuflen >= sizeof (dbCommon::amsg) @endcode .
|
||||
* A trailing nil will be added whenever @code msgbuflen > 0 @endcode .
|
||||
* @since UNRELEASED
|
||||
* @since 7.0.6
|
||||
*/
|
||||
DBCORE_API long dbGetAlarmMsg(const struct link *plink, epicsEnum16 *status,
|
||||
epicsEnum16 *severity, char *msgbuf, size_t msgbuflen);
|
||||
#define dbGetAlarmMsg(LINK, STAT, SEVR, BUF, BUFLEN) dbGetAlarmMsg(LINK, STAT, SEVR, BUF, BUFLEN)
|
||||
DBCORE_API long dbGetTimeStamp(const struct link *plink,
|
||||
epicsTimeStamp *pstamp);
|
||||
/** @since UNRELEASED */
|
||||
/** @since 7.0.6 */
|
||||
DBCORE_API long dbGetTimeStampTag(const struct link *plink,
|
||||
epicsTimeStamp *pstamp, epicsUTag *ptag);
|
||||
#define dbGetTimeStampTag(LINK, STAMP, TAG) dbGetTimeStampTag(LINK, STAMP, TAG)
|
||||
|
||||
@@ -613,8 +613,10 @@ long dbtpn(char *pname, char *pvalue)
|
||||
ptpnInfo = dbCalloc(1, sizeof(tpnInfo));
|
||||
ptpnInfo->ppn = ppn;
|
||||
ptpnInfo->callbackDone = epicsEventCreate(epicsEventEmpty);
|
||||
strncpy(ptpnInfo->buffer, pvalue, 80);
|
||||
ptpnInfo->buffer[79] = 0;
|
||||
if (pvalue) {
|
||||
strncpy(ptpnInfo->buffer, pvalue, sizeof(ptpnInfo->buffer));
|
||||
ptpnInfo->buffer[sizeof(ptpnInfo->buffer)-1] = 0;
|
||||
}
|
||||
|
||||
ppn->usrPvt = ptpnInfo;
|
||||
epicsThreadCreate("dbtpn", epicsThreadPriorityHigh,
|
||||
|
||||
@@ -130,7 +130,7 @@ DBCORE_API int dbNotifyDump(void);
|
||||
* if a process request is issued and also calls the client callbacks.
|
||||
*
|
||||
* A process request is issued if any of the following is true.
|
||||
* 1) The requester has issued a processs request and record is passive.
|
||||
* 1) The requester has issued a process request and record is passive.
|
||||
* 2) The requester is doing a put, the record is passive, and either
|
||||
* a) The field description is process passive.
|
||||
* b) The field is PROC.
|
||||
@@ -156,7 +156,7 @@ DBCORE_API int dbNotifyDump(void);
|
||||
* As soon as a record completes processing the field is set NULL
|
||||
* ppnr pointer to processNotifyRecord, which is a private structure
|
||||
* owned by dbNotify.
|
||||
* dbNotify is reponsible for this structure.
|
||||
* dbNotify is responsible for this structure.
|
||||
*
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -110,7 +110,7 @@ extern "C" void putNotifyCompletion ( processNotify *ppn )
|
||||
if ( pNtfy ) {
|
||||
pBlocker->pNotify = 0;
|
||||
// Its necessary to signal the initiators now before we call
|
||||
// the user callback. This is less efficent, and potentially
|
||||
// the user callback. This is less efficient, and potentially
|
||||
// causes more thread context switching, but its probably
|
||||
// unavoidable because its possible that the use callback
|
||||
// might destroy this object.
|
||||
|
||||
@@ -817,7 +817,7 @@ static void periodicTask(void *arg)
|
||||
epicsTimeAddSeconds(&next, delay);
|
||||
if (++overruns >= 10 &&
|
||||
epicsTimeDiffInSeconds(&now, &reported) > report_delay) {
|
||||
errlogPrintf("\ndbScan warning from '%s' scan thread:\n"
|
||||
errlogPrintf("\ndbScan " ERL_WARNING " from '%s' scan thread:\n"
|
||||
"\tScan processing averages %.3f seconds (%.3f .. %.3f).\n"
|
||||
"\tOver-runs have now happened %u times in a row.\n"
|
||||
"\tTo fix this, move some records to a slower scan rate.\n",
|
||||
|
||||
@@ -1300,7 +1300,7 @@ static void dbpr_insert_msg(TAB_BUFFER *pMsgBuff,size_t len,int tab_size)
|
||||
current_len = strlen(pMsgBuff->out_buff);
|
||||
tot_line = current_len + len;
|
||||
|
||||
/* flush buffer if overflow would occor */
|
||||
/* flush buffer if overflow would occur */
|
||||
if (tot_line > MAXLINE)
|
||||
dbpr_msg_flush(pMsgBuff, tab_size);
|
||||
|
||||
|
||||
@@ -266,7 +266,7 @@ done:
|
||||
void testdbPutArrFieldOk(const char* pv, short dbrType, unsigned long count, const void *pbuf)
|
||||
{
|
||||
dbChannel *chan = dbChannelCreate(pv);
|
||||
long status;
|
||||
long status = -1;
|
||||
|
||||
if(!chan || (status=dbChannelOpen(chan))) {
|
||||
testFail("Channel error (%p, %ld) : %s", chan, status, pv);
|
||||
@@ -289,7 +289,7 @@ void testdbGetArrFieldEqual(const char* pv, short dbfType, long nRequest, unsign
|
||||
const long vSize = dbValueSize(dbfType);
|
||||
const long nStore = vSize * nRequest;
|
||||
long status = S_dbLib_recNotFound;
|
||||
char *gbuf, *gstore;
|
||||
char *gbuf, *gstore = NULL;
|
||||
const char *pbuf = pbufraw;
|
||||
|
||||
if(!chan || (status=dbChannelOpen(chan))) {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
\*************************************************************************/
|
||||
|
||||
/** @file dbUnitTest.h
|
||||
* @brief Helpers for unitests of process database
|
||||
* @brief Helpers for unittests of process database
|
||||
* @author Michael Davidsaver, Ralph Lange
|
||||
*
|
||||
* @see @ref dbunittest
|
||||
@@ -99,7 +99,7 @@ DBCORE_API void testdbVGetFieldEqual(const char* pv, short dbrType, va_list ap);
|
||||
/** Assert that a dbPutField() array operation will complete successfully.
|
||||
*
|
||||
* @param pv a PV name, possibly including filter expression
|
||||
* @param a DBF_\* type code (cf. dbfType in dbFldTypes.h)
|
||||
* @param dbrType a DBF_\* type code (cf. dbfType in dbFldTypes.h)
|
||||
* @param count Number of elements in pbuf array
|
||||
* @param pbuf Array of values to write
|
||||
*
|
||||
@@ -114,7 +114,7 @@ DBCORE_API void testdbPutArrFieldOk(const char* pv, short dbrType, unsigned long
|
||||
|
||||
/**
|
||||
* @param pv PV name string
|
||||
* @param dbfType One of the DBF_* macros from dbAccess.h
|
||||
* @param dbfType One of the DBF_\* macros from dbAccess.h
|
||||
* @param nRequest Number of elements to request from pv
|
||||
* @param pbufcnt Number of elements pointed to be pbuf
|
||||
* @param pbuf Expected value buffer
|
||||
@@ -149,7 +149,7 @@ DBCORE_API void testMonitorDestroy(testMonitor*);
|
||||
*/
|
||||
DBCORE_API void testMonitorWait(testMonitor*);
|
||||
/** Return the number of monitor events which have occured since create,
|
||||
* or a pervious reset (called reset=1).
|
||||
* or a previous reset (called reset=1).
|
||||
* Calling w/ reset=0 only returns the count.
|
||||
* Calling w/ reset=1 resets the count to zero and ensures that the next
|
||||
* wait will block unless subsequent events occur. Returns the previous
|
||||
|
||||
@@ -27,7 +27,7 @@ DBCORE_API extern volatile int interruptAccept;
|
||||
|
||||
|
||||
/*
|
||||
* Adaptors for db_access users
|
||||
* Adapters for db_access users
|
||||
*/
|
||||
DBCORE_API struct dbChannel * dbChannel_create(const char *pname);
|
||||
DBCORE_API int dbChannel_get(struct dbChannel *chan,
|
||||
|
||||
@@ -318,7 +318,7 @@ void recGblGetTimeStampSimm(void *pvoid, const epicsEnum16 simm, struct link *si
|
||||
} else {
|
||||
if (simm != menuSimmNO) {
|
||||
if (siol && !dbLinkIsConstant(siol)) {
|
||||
if (dbGetTimeStamp(siol, &prec->time))
|
||||
if (dbGetTimeStampTag(siol, &prec->time, &prec->utag))
|
||||
errlogPrintf("recGblGetTimeStampSimm: dbGetTimeStamp (sim mode) failed, %s.SIOL = %s\n",
|
||||
prec->name, siol->value.pv_link.pvname);
|
||||
return;
|
||||
|
||||
@@ -29,7 +29,7 @@ extern "C" {
|
||||
*
|
||||
* Covers addition of dbCommon::amsg, recGblSetSevrMsg(), lset::getAlarmMsg()
|
||||
*
|
||||
* @since UNRELEASED
|
||||
* @since 7.0.6
|
||||
*/
|
||||
#define HAS_ALARM_MESSAGE 1
|
||||
|
||||
|
||||
@@ -101,10 +101,6 @@ static int yyreset(void)
|
||||
")" return(yytext[0]);
|
||||
"," return(yytext[0]);
|
||||
|
||||
{doublequote}({stringchar}|{escape})*{newline} { /* bad string */
|
||||
yyerrorAbort("Newline in string, closing quote missing");
|
||||
}
|
||||
|
||||
<JSON>"null" return jsonNULL;
|
||||
<JSON>"true" return jsonTRUE;
|
||||
<JSON>"false" return jsonFALSE;
|
||||
@@ -130,6 +126,20 @@ static int yyreset(void)
|
||||
|
||||
<INITIAL,JSON>{whitespace} ;
|
||||
|
||||
|
||||
/* Error patterns */
|
||||
|
||||
{doublequote}({stringchar}|{escape})*{newline} {
|
||||
yyerrorAbort("Newline in string, closing quote missing");
|
||||
}
|
||||
|
||||
<JSON>{doublequote}({stringchar}|{escape})*{doublequote} {
|
||||
yyerrorAbort("Bad character in JSON string");
|
||||
}
|
||||
<JSON>{singlequote}({stringchar}|{escape})*{singlequote} {
|
||||
yyerrorAbort("Bad character in JSON string");
|
||||
}
|
||||
|
||||
<INITIAL,JSON>. {
|
||||
char message[40];
|
||||
YY_BUFFER_STATE *dummy=0;
|
||||
|
||||
@@ -37,7 +37,11 @@
|
||||
#include "special.h"
|
||||
#include "iocInit.h"
|
||||
|
||||
|
||||
/* This file is included from dbYacc.y
|
||||
* Duplicate some declarations to avoid warnings from analysis tools which don't know about this.
|
||||
*/
|
||||
static int yyerror(char *str);
|
||||
static long pvt_yy_parse(void);
|
||||
|
||||
/*global declarations*/
|
||||
char *makeDbdDepends=0;
|
||||
@@ -99,8 +103,8 @@ static char *my_buffer_ptr=NULL;
|
||||
static MAC_HANDLE *macHandle = NULL;
|
||||
typedef struct inputFile{
|
||||
ELLNODE node;
|
||||
char *path;
|
||||
char *filename;
|
||||
const char *path;
|
||||
const char *filename;
|
||||
FILE *fp;
|
||||
int line_num;
|
||||
}inputFile;
|
||||
@@ -155,7 +159,7 @@ static void *getLastTemp(void)
|
||||
return(ptempListNode->item);
|
||||
}
|
||||
|
||||
static char *dbOpenFile(DBBASE *pdbbase,const char *filename,FILE **fp)
|
||||
const char *dbOpenFile(DBBASE *pdbbase,const char *filename,FILE **fp)
|
||||
{
|
||||
ELLLIST *ppathList = (ELLLIST *)pdbbase->pathPvt;
|
||||
dbPathNode *pdbPathNode;
|
||||
@@ -223,8 +227,10 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
|
||||
epicsPrintf("dbReadCOM: Parser stack dirty %d\n", ellCount(&tempList));
|
||||
}
|
||||
|
||||
if (getIocState() != iocVoid)
|
||||
return -2;
|
||||
if (getIocState() != iocVoid) {
|
||||
status = -2;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if(*ppdbbase == 0) *ppdbbase = dbAllocBase();
|
||||
pdbbase = *ppdbbase;
|
||||
@@ -269,7 +275,7 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
|
||||
if (!pinputFile->filename || !fp1) {
|
||||
errPrintf(0, __FILE__, __LINE__,
|
||||
"dbRead opening file %s",pinputFile->filename);
|
||||
free(pinputFile->filename);
|
||||
free((char*)pinputFile->filename);
|
||||
free(pinputFile);
|
||||
status = -1;
|
||||
goto cleanup;
|
||||
@@ -277,6 +283,7 @@ static long dbReadCOM(DBBASE **ppdbbase,const char *filename, FILE *fp,
|
||||
pinputFile->fp = fp1;
|
||||
} else {
|
||||
pinputFile->fp = fp;
|
||||
fp = NULL;
|
||||
}
|
||||
pinputFile->line_num = 0;
|
||||
pinputFileNow = pinputFile;
|
||||
@@ -332,6 +339,8 @@ cleanup:
|
||||
if(my_buffer) free((void *)my_buffer);
|
||||
my_buffer = NULL;
|
||||
freeInputFileList();
|
||||
if(fp)
|
||||
fclose(fp);
|
||||
return(status);
|
||||
}
|
||||
|
||||
@@ -1063,7 +1072,7 @@ int dbRecordNameValidate(const char *name)
|
||||
}
|
||||
|
||||
for(; *pos; i++, pos++) {
|
||||
char c = *pos;
|
||||
unsigned char c = *pos;
|
||||
if(i==0) {
|
||||
/* first character restrictions */
|
||||
if(c=='-' || c=='+' || c=='[' || c=='{') {
|
||||
@@ -1072,8 +1081,8 @@ int dbRecordNameValidate(const char *name)
|
||||
}
|
||||
/* any character restrictions */
|
||||
if(c < ' ') {
|
||||
errlogPrintf("Warning: Record/Alias name '%s' should not contain non-printable 0x%02u\n",
|
||||
name, (unsigned)c);
|
||||
errlogPrintf("Warning: Record/Alias name '%s' should not contain non-printable 0x%02x\n",
|
||||
name, c);
|
||||
|
||||
} else if(c==' ' || c=='\t' || c=='"' || c=='\'' || c=='.' || c=='$') {
|
||||
epicsPrintf("Error: Bad character '%c' in Record/Alias name \"%s\"\n",
|
||||
|
||||
@@ -441,6 +441,9 @@ void dbFreeBase(dbBase *pdbbase)
|
||||
DBENTRY dbentry;
|
||||
long status;
|
||||
|
||||
if(!pdbbase)
|
||||
return;
|
||||
|
||||
dbInitEntry(pdbbase,&dbentry);
|
||||
status = dbFirstRecordType(&dbentry);
|
||||
while(!status) {
|
||||
@@ -677,7 +680,7 @@ long dbAddPath(DBBASE *pdbbase,const char *path)
|
||||
if (!path) return(0); /* Empty path strings are ignored */
|
||||
/* care is taken to properly deal with white space
|
||||
* 1) preceding and trailing white space is removed from paths
|
||||
* 2) white space inbetween path separator counts as an empty name
|
||||
* 2) white space in between path separator counts as an empty name
|
||||
* (see below)
|
||||
*/
|
||||
expectingPath = FALSE;
|
||||
@@ -710,8 +713,8 @@ long dbAddPath(DBBASE *pdbbase,const char *path)
|
||||
|
||||
/*
|
||||
* len is always nonzero because we found something that
|
||||
* 1) isnt white space
|
||||
* 2) isnt a path separator
|
||||
* 1) isn't white space
|
||||
* 2) isn't a path separator
|
||||
*/
|
||||
len = (plast - path) + 1;
|
||||
if (dbAddOnePath (pdbbase, path, (unsigned) len)) return (-1);
|
||||
@@ -722,7 +725,7 @@ long dbAddPath(DBBASE *pdbbase,const char *path)
|
||||
}
|
||||
|
||||
/*
|
||||
* an empty name at beginning, middle, or end of a path string that isnt
|
||||
* an empty name at beginning, middle, or end of a path string that isn't
|
||||
* empty means current directory
|
||||
*/
|
||||
if (expectingPath||sawMissingPath) {
|
||||
@@ -2274,8 +2277,8 @@ long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo)
|
||||
len -= (parm - pstr);
|
||||
}
|
||||
|
||||
/* generalized extraction of ID charactor and integer pairs (eg. "#C15 S14") */
|
||||
ret = sscanf(pinfo->target, "# %c%d %c%d %c%d %c%d %c%d %c",
|
||||
/* generalized extraction of ID character and integer pairs (eg. "#C15 S14") */
|
||||
ret = sscanf(pinfo->target, "# %c%i %c%i %c%i %c%i %c%i %c",
|
||||
&pinfo->hwid[0], &pinfo->hwnums[0],
|
||||
&pinfo->hwid[1], &pinfo->hwnums[1],
|
||||
&pinfo->hwid[2], &pinfo->hwnums[2],
|
||||
@@ -2333,11 +2336,11 @@ long dbParseLink(const char *str, short ftype, dbLinkInfo *pinfo)
|
||||
}
|
||||
|
||||
pinfo->ltype = PV_LINK;
|
||||
pstr = strchr(pstr, ' '); /* find start of link modifiers (can't be seperated by tabs) */
|
||||
pstr = strchr(pstr, ' '); /* find start of link modifiers (can't be separated by tabs) */
|
||||
if (pstr) {
|
||||
*pstr++ = '\0'; /* isolate modifiers. pinfo->target is PV name only for re-use in struct pv_link */
|
||||
|
||||
/* Space seperation of modifiers isn't required, and other chars are ignored.
|
||||
/* Space separation of modifiers isn't required, and other chars are ignored.
|
||||
* Order of comparisons resolves ambiguity by checking for
|
||||
* longer matches first.
|
||||
* eg. "QQCPPXMSITT" is pvlOptCPP|pvlOptMSI
|
||||
|
||||
@@ -57,8 +57,26 @@ DBCORE_API void dbCopyEntryContents(DBENTRY *pfrom,
|
||||
|
||||
DBCORE_API extern int dbBptNotMonotonic;
|
||||
|
||||
/** \brief Open .dbd or .db file and read definitions.
|
||||
* \param ppdbbase The database. Typically the "pdbbase" global
|
||||
* \param filename Filename to read/search. May be absolute, or relative.
|
||||
* \param path If !NULL, search path when filename is relative, of for 'include' statements.
|
||||
* Split by ':' or ';' (cf. OSI_PATH_LIST_SEPARATOR)
|
||||
* \param substitutions If !NULL, macro definitions like "NAME=VAL,OTHER=SOME"
|
||||
* \return 0 on success
|
||||
*/
|
||||
DBCORE_API long dbReadDatabase(DBBASE **ppdbbase,
|
||||
const char *filename, const char *path, const char *substitutions);
|
||||
/** \brief Read definitions from already opened .dbd or .db file.
|
||||
* \param ppdbbase The database. Typically the "&pdbbase" global
|
||||
* \param fp FILE* from which to read definitions. Will always be fclose()'d
|
||||
* \param path If !NULL, search path when filename is relative, of for 'include' statements.
|
||||
* Split by ':' or ';' (cf. OSI_PATH_LIST_SEPARATOR)
|
||||
* \param substitutions If !NULL, macro definitions like "NAME=VAL,OTHER=SOME"
|
||||
* \return 0 on success
|
||||
*
|
||||
* \note This function will always close the provided 'fp'.
|
||||
*/
|
||||
DBCORE_API long dbReadDatabaseFP(DBBASE **ppdbbase,
|
||||
FILE *fp, const char *path, const char *substitutions);
|
||||
DBCORE_API long dbPath(DBBASE *pdbbase, const char *path);
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
#ifndef INCdbStaticPvth
|
||||
#define INCdbStaticPvth 1
|
||||
|
||||
#include "dbCoreAPI.h"
|
||||
#include "dbStaticLib.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@@ -40,6 +43,9 @@ void dbMsgPrint(DBENTRY *pdbentry, const char *fmt, ...) EPICS_PRINTF_STYLE(2,3)
|
||||
|
||||
void dbPutStringSuggest(DBENTRY *pdbentry, const char *pstring);
|
||||
|
||||
DBCORE_API
|
||||
const char *dbOpenFile(DBBASE *pdbbase,const char *filename,FILE **fp);
|
||||
|
||||
struct jlink;
|
||||
|
||||
typedef struct dbLinkInfo {
|
||||
|
||||
@@ -374,7 +374,7 @@ static int yyerror(char *str)
|
||||
else
|
||||
epicsPrintf("Error");
|
||||
if (!yyFailed) { /* Only print this stuff once */
|
||||
epicsPrintf(" at or before \"%s\"", yytext);
|
||||
epicsPrintf(" at or before '%s'", yytext);
|
||||
dbIncludePrint();
|
||||
yyFailed = TRUE;
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ typedef struct typed_dset {
|
||||
long (*init_record)(struct dbCommon *prec);
|
||||
/** Called when SCAN="I/O Intr" on startup, or after SCAN is changed.
|
||||
*
|
||||
* Caller must assign the third arguement (IOCSCANPVT*). eg.
|
||||
* Caller must assign the third argument (IOCSCANPVT*). eg.
|
||||
@code
|
||||
struct mpvt {
|
||||
IOSCANPVT drvlist;
|
||||
@@ -173,7 +173,7 @@ DBCORE_API void dbInitDevSup(struct devSup *pdevSup, dset *pdset);
|
||||
#define S_dev_badOutType (M_devSup| 9) /*Bad OUT link type*/
|
||||
#define S_dev_badInitRet (M_devSup|11) /*Bad init_rec return value */
|
||||
#define S_dev_badBus (M_devSup|13) /*Illegal bus type*/
|
||||
#define S_dev_badCard (M_devSup|15) /*Illegal or nonexistant module*/
|
||||
#define S_dev_badCard (M_devSup|15) /*Illegal or nonexistent module*/
|
||||
#define S_dev_badSignal (M_devSup|17) /*Illegal signal*/
|
||||
#define S_dev_NoInit (M_devSup|19) /*No init*/
|
||||
#define S_dev_Conflict (M_devSup|21) /*Multiple records accessing same signal*/
|
||||
|
||||
@@ -180,7 +180,7 @@ union value {
|
||||
struct vmeio vmeio; /* vme io point */
|
||||
struct camacio camacio; /* camac io point */
|
||||
struct rfio rfio; /* CEBAF RF buffer interface */
|
||||
struct abio abio; /* allen-bradley io point */
|
||||
struct abio abio; /* Allen-Bradley io point */
|
||||
struct gpibio gpibio;
|
||||
struct bitbusio bitbusio;
|
||||
struct instio instio; /* instrument io link */
|
||||
|
||||
@@ -21,14 +21,14 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*NOTE Do NOT add aditional definitions with out modifying dbLexRoutines.c */
|
||||
/*NOTE Do NOT add additional definitions with out modifying dbLexRoutines.c */
|
||||
/* types 1-99 are global. Record specific must start with 100 */
|
||||
#define SPC_NOMOD 1 /*Field must not be modified*/
|
||||
#define SPC_DBADDR 2 /*db_name_to_addr must call cvt_dbaddr*/
|
||||
#define SPC_SCAN 3 /*A scan related field is being changed*/
|
||||
#define SPC_ALARMACK 5 /*Special Alarm Acknowledgement*/
|
||||
#define SPC_AS 6 /* Access Security*/
|
||||
#define SPC_ATTRIBUTE 7 /* psuedo field, i.e. attribute field*/
|
||||
#define SPC_ATTRIBUTE 7 /* pseudo field, i.e. attribute field*/
|
||||
/* useful when record support must be notified of a field changing value*/
|
||||
#define SPC_MOD 100
|
||||
/* used by all records that support a reset field*/
|
||||
|
||||
@@ -317,7 +317,7 @@ static void makeSubstitutions(inputData * const inputPvt,
|
||||
pstart = ++p;
|
||||
/*Look for end quote*/
|
||||
while (*p && (*p != '"')) {
|
||||
/*allow escape for embeded quote*/
|
||||
/*allow escape for embedded quote*/
|
||||
if ((p[0] == '\\') && p[1] == '"') {
|
||||
p += 2;
|
||||
continue;
|
||||
@@ -1028,7 +1028,7 @@ static tokenType subGetNextToken(subFile *psubFile)
|
||||
subFileErrPrint(psubFile, "Strings must be on single line\n");
|
||||
abortExit(1);
|
||||
}
|
||||
/*allow escape for embeded quote*/
|
||||
/*allow escape for embedded quote*/
|
||||
if ((p[0] == '\\') && p[1] == '"') {
|
||||
*pto++ = *p++;
|
||||
*pto++ = *p++;
|
||||
|
||||
@@ -97,7 +97,7 @@ typedef struct rsrv_put_notify {
|
||||
/*
|
||||
* casCalloc()
|
||||
*
|
||||
* (dont drop below some max block threshold)
|
||||
* (don't drop below some max block threshold)
|
||||
*/
|
||||
static void *casCalloc(size_t count, size_t size)
|
||||
{
|
||||
@@ -341,7 +341,7 @@ static int bad_tcp_cmd_action ( caHdrLargeArray *mp, void *pPayload,
|
||||
log_header ( pCtx, client, mp, pPayload, 0 );
|
||||
|
||||
/*
|
||||
* by default, clients dont recover
|
||||
* by default, clients don't recover
|
||||
* from this
|
||||
*/
|
||||
SEND_LOCK (client);
|
||||
@@ -503,7 +503,7 @@ static void read_reply ( void *pArg, struct dbChannel *dbch,
|
||||
cid = ECA_NORMAL;
|
||||
|
||||
/* If the client has requested a zero element count we interpret this as a
|
||||
* request for all avaiable elements. In this case we initialise the
|
||||
* request for all available elements. In this case we initialize the
|
||||
* header with the maximum element size specified by the database. */
|
||||
autosize = pevext->msg.m_count == 0;
|
||||
item_count =
|
||||
@@ -870,7 +870,7 @@ static int host_name_action ( caHdrLargeArray *mp, void *pPayload,
|
||||
}
|
||||
|
||||
/*
|
||||
* user name will not change if there isnt enough memory
|
||||
* user name will not change if there isn't enough memory
|
||||
*/
|
||||
pMalloc = malloc(size);
|
||||
if(!pMalloc){
|
||||
@@ -949,7 +949,7 @@ static int client_name_action ( caHdrLargeArray *mp, void *pPayload,
|
||||
}
|
||||
|
||||
/*
|
||||
* user name will not change if there isnt enough memory
|
||||
* user name will not change if there isn't enough memory
|
||||
*/
|
||||
pMalloc = malloc(size);
|
||||
if(!pMalloc){
|
||||
@@ -1016,7 +1016,7 @@ unsigned cid
|
||||
* NOTE: This detects the case where the PV id wraps
|
||||
* around and we attempt to have two resources on the same id.
|
||||
* The lock is applied here because on some architectures the
|
||||
* ++ operator isnt atomic.
|
||||
* ++ operator isn't atomic.
|
||||
*/
|
||||
LOCK_CLIENTQ;
|
||||
|
||||
@@ -1245,8 +1245,8 @@ static int claim_ciu_action ( caHdrLargeArray *mp,
|
||||
return RSRV_OK;
|
||||
}
|
||||
|
||||
DLOG ( 2, ("CAS: claim_ciu_action found '%s', type %d, count %d\n",
|
||||
pName, dbChannelCAType(dbch), dbChannelElements(dbch)) );
|
||||
DLOG ( 2, ("CAS: claim_ciu_action found '%s', type %d, count %ld\n",
|
||||
pName, dbChannelExportCAType(dbch), dbChannelElements(dbch)) );
|
||||
|
||||
pciu = casCreateChannel (
|
||||
client,
|
||||
@@ -1436,7 +1436,7 @@ static void write_notify_reply ( struct client * pClient )
|
||||
msgtmp.m_available, 0 );
|
||||
if ( localStatus != ECA_NORMAL ) {
|
||||
/*
|
||||
* inability to aquire buffer space
|
||||
* inability to acquire buffer space
|
||||
* Indicates corruption
|
||||
*/
|
||||
errlogPrintf("CA server corrupted - put call back(s) discarded\n");
|
||||
@@ -1570,7 +1570,7 @@ static int rsrvExpandPutNotify (
|
||||
|
||||
if ( sizeNeeded > pNotify->valueSize ) {
|
||||
/*
|
||||
* try to use the union embeded in the free list
|
||||
* try to use the union embedded in the free list
|
||||
* item, but allocate a random sized block if they
|
||||
* writing a vector.
|
||||
*/
|
||||
@@ -1625,7 +1625,7 @@ void rsrvFreePutNotify ( client *pClient,
|
||||
epicsMutexUnlock ( pClient->putNotifyLock );
|
||||
|
||||
/*
|
||||
* if any possiblity that the put notify is
|
||||
* if any possibility that the put notify is
|
||||
* outstanding then cancel it
|
||||
*/
|
||||
if ( busyTmp ) {
|
||||
@@ -1736,7 +1736,7 @@ static int write_notify_action ( caHdrLargeArray *mp, void *pPayload,
|
||||
if ( ! pciu->pPutNotify ) {
|
||||
/*
|
||||
* send error and go to next request
|
||||
* if there isnt enough memory left
|
||||
* if there isn't enough memory left
|
||||
*/
|
||||
log_header ( "no memory to initiate put notify",
|
||||
client, mp, pPayload, 0 );
|
||||
@@ -1874,7 +1874,7 @@ static int event_add_action (caHdrLargeArray *mp, void *pPayload, struct client
|
||||
* messages sent by the server).
|
||||
*/
|
||||
|
||||
DLOG ( 3, ("event_add_action: db_post_single_event (0x%X)\n",
|
||||
DLOG ( 3, ("event_add_action: db_post_single_event (%p)\n",
|
||||
pevext->pdbev) );
|
||||
db_post_single_event(pevext->pdbev);
|
||||
|
||||
@@ -2144,7 +2144,7 @@ int rsrv_version_reply ( struct client *client )
|
||||
SEND_LOCK ( client );
|
||||
/*
|
||||
* sequence number is specified zero when we copy in the
|
||||
* header because we dont know it until we receive a datagram
|
||||
* header because we don't know it until we receive a datagram
|
||||
* from the client
|
||||
*/
|
||||
status = cas_copy_in_header ( client, CA_PROTO_VERSION,
|
||||
@@ -2191,7 +2191,7 @@ static int search_reply_udp ( caHdrLargeArray *mp, void *pPayload, struct client
|
||||
|
||||
/* Exit quickly if channel not on this node */
|
||||
if (dbChannelTest(pName)) {
|
||||
DLOG ( 2, ( "CAS: Lookup for channel \"%s\" failed\n", pPayLoad ) );
|
||||
DLOG ( 2, ( "CAS: Lookup for channel \"%s\" failed\n", pName ) );
|
||||
return RSRV_OK;
|
||||
}
|
||||
|
||||
@@ -2210,7 +2210,7 @@ static int search_reply_udp ( caHdrLargeArray *mp, void *pPayload, struct client
|
||||
* starting with V4.4 the count field is used (abused)
|
||||
* to store the minor version number of the client.
|
||||
*
|
||||
* New versions dont alloc the channel in response
|
||||
* New versions don't alloc the channel in response
|
||||
* to a search request.
|
||||
* For these, allocation has been moved to claim_ciu_action().
|
||||
*
|
||||
@@ -2278,14 +2278,14 @@ static int search_reply_tcp (
|
||||
|
||||
/* Exit quickly if channel not on this node */
|
||||
if (dbChannelTest(pName)) {
|
||||
DLOG ( 2, ( "CAS: Lookup for channel \"%s\" failed\n", pPayLoad ) );
|
||||
DLOG ( 2, ( "CAS: Lookup for channel \"%s\" failed\n", pName ) );
|
||||
if (mp->m_dataType == DOREPLY)
|
||||
search_fail_reply ( mp, pPayload, client );
|
||||
return RSRV_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* stop further use of server if memory becomes scarse
|
||||
* stop further use of server if memory becomes scarce
|
||||
*/
|
||||
spaceAvailOnFreeList = freeListItemsAvail ( rsrvChanFreeList ) > 0
|
||||
&& freeListItemsAvail ( rsrvEventFreeList ) > reasonableMonitorSpace;
|
||||
@@ -2397,7 +2397,7 @@ int camessage ( struct client *client )
|
||||
|
||||
assert(pCaBucket);
|
||||
|
||||
/* drain remnents of large messages that will not fit */
|
||||
/* drain remnants of large messages that will not fit */
|
||||
if ( client->recvBytesToDrain ) {
|
||||
if ( client->recvBytesToDrain >= client->recv.cnt ) {
|
||||
client->recvBytesToDrain -= client->recv.cnt;
|
||||
@@ -2410,7 +2410,7 @@ int camessage ( struct client *client )
|
||||
}
|
||||
}
|
||||
|
||||
DLOG ( 2, ( "CAS: Parsing %d(decimal) bytes\n", recv->cnt ) );
|
||||
DLOG ( 2, ( "CAS: Parsing %d(decimal) bytes\n", client->recv.cnt ) );
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
@@ -2472,7 +2472,7 @@ int camessage ( struct client *client )
|
||||
}
|
||||
|
||||
/*
|
||||
* disconnect clients that dont send 8 byte
|
||||
* disconnect clients that don't send 8 byte
|
||||
* aligned payloads
|
||||
*/
|
||||
if ( msgsize & 0x7 ) {
|
||||
|
||||
@@ -50,7 +50,7 @@ void camsgtask ( void *pParm )
|
||||
int status;
|
||||
|
||||
/*
|
||||
* allow message to batch up if more are comming
|
||||
* allow message to batch up if more are coming
|
||||
*/
|
||||
status = socket_ioctl (client->sock, FIONREAD, &check_nchars);
|
||||
if (status < 0) {
|
||||
@@ -58,7 +58,7 @@ void camsgtask ( void *pParm )
|
||||
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
errlogPrintf("CAS: FIONREAD error: %s\n",
|
||||
errlogPrintf("CAS: FIONREAD " ERL_ERROR ": %s\n",
|
||||
sockErrBuf);
|
||||
cas_send_bs_msg(client, TRUE);
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ void cas_send_bs_msg ( struct client *pclient, int lock_needed )
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
errlogPrintf ("CAS: Socket shutdown error: %s\n",
|
||||
errlogPrintf ("CAS: Socket shutdown " ERL_ERROR ": %s\n",
|
||||
sockErrBuf );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ static void req_server (void *pParm)
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
errlogPrintf("CAS: Client accept error: %s (%d)\n",
|
||||
errlogPrintf("CAS: Client accept " ERL_ERROR ": %s (%d)\n",
|
||||
sockErrBuf, (int)addLen );
|
||||
epicsThreadSleep(15.0);
|
||||
continue;
|
||||
@@ -131,7 +131,7 @@ int tryBind(SOCKET sock, const osiSockAddr* addr, const char *name)
|
||||
{
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
errlogPrintf ( "CAS: %s bind error: %s\n",
|
||||
errlogPrintf ( "CAS: %s bind " ERL_ERROR ": %s\n",
|
||||
name, sockErrBuf );
|
||||
epicsThreadSuspendSelf ();
|
||||
}
|
||||
@@ -196,7 +196,7 @@ SOCKET* rsrv_grab_tcp(unsigned short *port)
|
||||
char sockErrBuf[64];
|
||||
epicsSocketConvertErrnoToString (
|
||||
sockErrBuf, sizeof ( sockErrBuf ) );
|
||||
errlogPrintf ( "CAS: getsockname error: %s\n",
|
||||
errlogPrintf ( "CAS: getsockname " ERL_ERROR ": %s\n",
|
||||
sockErrBuf );
|
||||
epicsThreadSuspendSelf ();
|
||||
ok = 0;
|
||||
@@ -545,7 +545,7 @@ void rsrv_init (void)
|
||||
beacon_startStopEvent = epicsEventMustCreate(epicsEventEmpty);
|
||||
castcp_ctl = ctlPause;
|
||||
|
||||
/* Thread priorites
|
||||
/* Thread priorities
|
||||
* Now starting per interface
|
||||
* TCP Listener: epicsThreadPriorityCAServerLow-2
|
||||
* Name receiver: epicsThreadPriorityCAServerLow-4
|
||||
@@ -576,12 +576,12 @@ void rsrv_init (void)
|
||||
|
||||
if ( sport != ca_server_port ) {
|
||||
ca_server_port = sport;
|
||||
errlogPrintf ( "cas warning: Configured TCP port was unavailable.\n");
|
||||
errlogPrintf ( "cas warning: Using dynamically assigned TCP port %hu,\n",
|
||||
errlogPrintf ( "cas " ERL_WARNING ": Configured TCP port was unavailable.\n");
|
||||
errlogPrintf ( "cas " ERL_WARNING ": Using dynamically assigned TCP port %hu,\n",
|
||||
ca_server_port );
|
||||
errlogPrintf ( "cas warning: but now two or more servers share the same UDP port.\n");
|
||||
errlogPrintf ( "cas warning: Depending on your IP kernel this server may not be\n" );
|
||||
errlogPrintf ( "cas warning: reachable with UDP unicast (a host's IP in EPICS_CA_ADDR_LIST)\n" );
|
||||
errlogPrintf ( "cas " ERL_WARNING ": but now two or more servers share the same UDP port.\n");
|
||||
errlogPrintf ( "cas " ERL_WARNING ": Depending on your IP kernel this server may not be\n" );
|
||||
errlogPrintf ( "cas " ERL_WARNING ": reachable with UDP unicast (a host's IP in EPICS_CA_ADDR_LIST)\n" );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1204,7 +1204,7 @@ void destroy_tcp_client ( struct client *client )
|
||||
assert ( ! status );
|
||||
|
||||
/*
|
||||
* wait for extra labor in progress to comple
|
||||
* wait for extra labor in progress to complete
|
||||
*/
|
||||
db_flush_extra_labor_event ( client->evuser );
|
||||
}
|
||||
@@ -1229,7 +1229,7 @@ struct client * create_client ( SOCKET sock, int proto )
|
||||
size_t spaceNeeded;
|
||||
|
||||
/*
|
||||
* stop further use of server if memory becomes scarse
|
||||
* stop further use of server if memory becomes scarce
|
||||
*/
|
||||
spaceAvailOnFreeList = freeListItemsAvail ( rsrvClientFreeList ) > 0
|
||||
&& freeListItemsAvail ( rsrvSmallBufFreeListTCP ) > 0;
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
* Improvements
|
||||
* ------------
|
||||
* .01
|
||||
* Dont send channel found message unless there is memory, a task slot,
|
||||
* Don't send channel found message unless there is memory, a task slot,
|
||||
* and a TCP socket available. Send a diagnostic instead.
|
||||
* Or ... make the timeout shorter? This is only a problem if
|
||||
* they persist in trying to make a connection after getting no
|
||||
@@ -269,9 +269,9 @@ void cast_server(void *pParm)
|
||||
}
|
||||
|
||||
/*
|
||||
* allow messages to batch up if more are comming
|
||||
* allow messages to batch up if more are coming
|
||||
*/
|
||||
nchars = 0; /* supress purify warning */
|
||||
nchars = 0; /* suppress purify warning */
|
||||
status = socket_ioctl(recv_sock, FIONREAD, &nchars);
|
||||
if (status<0) {
|
||||
errlogPrintf ("CA cast server: Unable to fetch N characters pending\n");
|
||||
|
||||
@@ -94,7 +94,7 @@ void rsrv_online_notify_task(void *pParm)
|
||||
|
||||
epicsSocketConvertErrorToString(sockErrBuf, sizeof(sockErrBuf), err);
|
||||
ipAddrToDottedIP(&pAddr->addr.ia, sockDipBuf, sizeof(sockDipBuf));
|
||||
errlogPrintf ( "CAS: CA beacon send to %s error: %s\n",
|
||||
errlogPrintf ( "CAS: CA beacon send to %s " ERL_ERROR ": %s\n",
|
||||
sockDipBuf, sockErrBuf);
|
||||
|
||||
lastError[i] = err;
|
||||
|
||||
@@ -239,7 +239,7 @@ void initializePutNotifyFreeList (void);
|
||||
unsigned rsrvSizeOfPutNotify ( struct rsrv_put_notify *pNotify );
|
||||
|
||||
/*
|
||||
* inclming protocol maintetnance
|
||||
* incoming protocol maintenance
|
||||
*/
|
||||
void casExpandRecvBuffer ( struct client *pClient, ca_uint32_t size );
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ static long init_record(dbCommon *pcommon)
|
||||
{
|
||||
long status=0;
|
||||
|
||||
/* dont convert */
|
||||
/* don't convert */
|
||||
status=2;
|
||||
return status;
|
||||
|
||||
|
||||
@@ -108,6 +108,7 @@ static long add_record(dbCommon *pcommon)
|
||||
|
||||
recGblRecordError(status, (void *)prec,
|
||||
"devSiSoftCallback (add_record) linked record not found");
|
||||
free(pdevPvt);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <chfPlugin.h>
|
||||
#include <recGbl.h>
|
||||
#include <epicsExit.h>
|
||||
#include <db_field_log.h>
|
||||
#include <dbAccess.h>
|
||||
#include <epicsExport.h>
|
||||
|
||||
typedef struct myStruct {
|
||||
@@ -81,8 +81,8 @@ static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) {
|
||||
status = dbFastGetConvertRoutine[pfl->field_type][DBR_DOUBLE]
|
||||
(localAddr.pfield, (void*) &val, &localAddr);
|
||||
if (!status) {
|
||||
send = 0;
|
||||
recGblCheckDeadband(&my->last, val, my->hyst, &send, 1);
|
||||
send = pfl->mask & ~(DBE_VALUE|DBE_LOG);
|
||||
recGblCheckDeadband(&my->last, val, my->hyst, &send, pfl->mask & (DBE_VALUE|DBE_LOG));
|
||||
if (send && my->mode == 1) {
|
||||
my->hyst = val * my->cval/100.;
|
||||
}
|
||||
|
||||
@@ -736,6 +736,10 @@ The choices can be found by following the link to the menuFtype definition.
|
||||
|
||||
These fields specify how many array elements the input value fields may hold.
|
||||
|
||||
Note that access to the C<NOT> field from C code must use the field name in
|
||||
upper case, e.g. C<< prec->NOT >> since the lower-case C<not> is a reserved
|
||||
word in C++ and cannot be used as an identifier.
|
||||
|
||||
=fields NOA, NOB, NOC, NOD, NOE, NOF, NOG, NOH, NOI, NOJ, NOK, NOL, NOM, NON, NOO, NOP, NOQ, NOR, NOS, NOT, NOU
|
||||
|
||||
=cut
|
||||
|
||||
@@ -162,7 +162,7 @@ static long process(struct dbCommon *pcommon)
|
||||
prec->udf = FALSE;
|
||||
|
||||
/* Update the timestamp before writing output values so it
|
||||
* will be uptodate if any downstream records fetch it via TSEL */
|
||||
* will be up to date if any downstream records fetch it via TSEL */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
@@ -357,7 +357,7 @@ static long writeValue(aaoRecord *prec)
|
||||
case menuYesNoYES: {
|
||||
recGblSetSevr(prec, SIMM_ALARM, prec->sims);
|
||||
if (prec->pact || (prec->sdly < 0.)) {
|
||||
/* Device suport is responsible for buffer
|
||||
/* Device support is responsible for buffer
|
||||
which might be write-only so we may not be
|
||||
allowed to call dbPutLink on it.
|
||||
Maybe also device support has an advanced
|
||||
|
||||
@@ -32,9 +32,10 @@ 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.
|
||||
circumstances the record will be processed.
|
||||
These fields are described in L<Scan Fields|dbCommonRecord/Scan Fields>.
|
||||
|
||||
=fields SCAN, PHAS, EVNT, PRIO, PINI
|
||||
|
||||
=head3 Write Parameters
|
||||
|
||||
@@ -43,8 +44,9 @@ writes its data. The OUT field determines where the array analog output writes i
|
||||
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.
|
||||
be a hardware address. See L<Address
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
||||
for information on the format of hardware addresses and database links.
|
||||
|
||||
=head4 Fields related to array writing
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
#undef GEN_SIZE_OFFSET
|
||||
#include "epicsExport.h"
|
||||
|
||||
/* Hysterisis for alarm filtering: 1-1/e */
|
||||
/* Hysteresis for alarm filtering: 1-1/e */
|
||||
#define THRESHOLD 0.6321
|
||||
|
||||
/* Create RSET - Record Support Entry Table*/
|
||||
|
||||
@@ -45,8 +45,9 @@ hardware address information that the device support uses to determine where the
|
||||
input data should come from.
|
||||
The format for the INP field value depends on the device support layer that is
|
||||
selected by the DTYP field.
|
||||
See L<Address Specification|...> for a description of the various hardware
|
||||
address formats supported.
|
||||
See L<Address
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
||||
for a description of the various hardware address formats supported.
|
||||
|
||||
=head3 Units Conversion
|
||||
|
||||
@@ -157,6 +158,10 @@ They do not affect the functioning of the record at all.
|
||||
|
||||
=over
|
||||
|
||||
=item *
|
||||
NAME is the record's name, and can be useful when the PV name that a client
|
||||
knows is an alias for the record.
|
||||
|
||||
=item *
|
||||
DESC is a string that is usually used to briefly describe the record.
|
||||
|
||||
@@ -175,7 +180,10 @@ DOUBLE fields.
|
||||
|
||||
=back
|
||||
|
||||
=fields DESC, EGU, HOPR, LOPR, PREC
|
||||
See L<Fields Common to All Record Types|dbCommonRecord/Operator Display
|
||||
Parameters> for more about the record name (NAME) and description (DESC) fields.
|
||||
|
||||
=fields NAME, DESC, EGU, HOPR, LOPR, PREC
|
||||
|
||||
=head3 Alarm Limits
|
||||
|
||||
@@ -198,6 +206,11 @@ 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.
|
||||
|
||||
See L<Alarm Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#alarm-specification>
|
||||
for a complete explanation of record alarms and of the standard fields.
|
||||
L<Alarm Fields|dbCommonRecord/Alarm Fields> lists other fields related
|
||||
to alarms that are common to all record types.
|
||||
|
||||
=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST, AFTC, LALM
|
||||
|
||||
=head3 Monitor Parameters
|
||||
|
||||
@@ -188,7 +188,7 @@ static long process(struct dbCommon *pcommon)
|
||||
if(!status) convert(prec, value);
|
||||
prec->udf = isnan(prec->val);
|
||||
/* Update the timestamp before writing output values so it
|
||||
* will be uptodate if any downstream records fetch it via TSEL */
|
||||
* will be up to date if any downstream records fetch it via TSEL */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -161,9 +161,9 @@ The analog output record sends its desired output to the address in the
|
||||
OUT field. For analog outputs that write their values to devices, the
|
||||
OUT field must specify the address of the I/O card. In addition, the
|
||||
DTYP field must contain the name of the device support module. Be aware
|
||||
that the address format differs according to the I/O bus used. See
|
||||
Address Specification for information on the format of hardware
|
||||
addresses.
|
||||
that the address format differs according to the I/O bus used. See L<Address
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
||||
for information on the format of hardware 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
|
||||
@@ -308,7 +308,7 @@ for more information on simulation mode and its fields.
|
||||
interest(1)
|
||||
}
|
||||
field(DOL,DBF_INLINK) {
|
||||
prompt("Desired Output Loc")
|
||||
prompt("Desired Output Link")
|
||||
promptgroup("40 - Input")
|
||||
interest(1)
|
||||
}
|
||||
|
||||
@@ -37,6 +37,8 @@ The binary input record has the standard fields for specifying under what
|
||||
circumstances the record will be processed.
|
||||
These fields are described in L<Scan Fields|dbCommonRecord/Scan Fields>.
|
||||
|
||||
=fields SCAN, PHAS, EVNT, PRIO, PINI
|
||||
|
||||
=head3 Read and Convert Parameters
|
||||
|
||||
The read and convert fields determine where the binary input gets its
|
||||
@@ -44,14 +46,15 @@ input from and how to convert the raw signal to engineering units. The INP
|
||||
field contains the address from where device support retrieves the value.
|
||||
If the binary input record gets its value from hardware, the address of the
|
||||
card must be entered in the INP field, and the name of the device support
|
||||
module must be entered in the DTYP field. See L<Address Specification> for
|
||||
information on the format of the hardware address. Be aware that the format
|
||||
differs between types of cards.
|
||||
module must be entered in the DTYP field. See L<Address
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
||||
for information on the format of the hardware address.
|
||||
|
||||
For records that specify C<Soft Channel> or C<Raw Soft Channel> device
|
||||
support routines, the INP field can be a channel or a database link, or a
|
||||
constant. If a constant, VAL can be changed directly by dbPuts. See
|
||||
L<Address Specification> for information on the format of database and
|
||||
constant. If a constant, VAL can be changed directly by dbPuts. See L<Address
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
||||
for information on the format of database and
|
||||
channel access addresses. Also, see L<Device Support for Soft Records> in
|
||||
this chapter for information on soft device support.
|
||||
|
||||
@@ -102,9 +105,10 @@ C<MAJOR>. The ZSV field holds the severity for the zero state; OSV, for
|
||||
the one state. COSV causes an alarm whenever the state changes between
|
||||
0 and 1 and the severity is configured as MINOR or MAJOR.
|
||||
|
||||
See L<Alarm Specification> for a complete explanation of the discrete alarm
|
||||
states. L<Alarm Fields|dbCommonRecord/Alarm Fields> lists other fields related to alarms that are
|
||||
common to all record types.
|
||||
See L<Alarm Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#alarm-specification>
|
||||
for a complete explanation of record alarms and of the standard fields.
|
||||
L<Alarm Fields|dbCommonRecord/Alarm Fields> lists other fields related
|
||||
to alarms that are common to all record types.
|
||||
|
||||
=fields ZSV, OSV, COSV
|
||||
|
||||
|
||||
@@ -211,7 +211,7 @@ static long process(struct dbCommon *pcommon)
|
||||
} else prec->rval = (epicsUInt32)prec->val;
|
||||
|
||||
/* Update the timestamp before writing output values so it
|
||||
* will be uptodate if any downstream records fetch it via TSEL */
|
||||
* will be up to date if any downstream records fetch it via TSEL */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -15,29 +15,6 @@ values into other records via database or channel access links. This record
|
||||
can implement both latched and momentary binary outputs depending on how
|
||||
the HIGH field is configured.
|
||||
|
||||
=head2 Parameter Fields
|
||||
|
||||
The binary output's fields fall into the following categories:
|
||||
|
||||
=over 1
|
||||
|
||||
=item *
|
||||
scan parameters
|
||||
|
||||
=item *
|
||||
convert and write parameters
|
||||
|
||||
=item *
|
||||
operator display parameters
|
||||
|
||||
=item *
|
||||
alarm parameters
|
||||
|
||||
=item *
|
||||
run-time parameters
|
||||
|
||||
=back
|
||||
|
||||
=recordtype bo
|
||||
|
||||
=cut
|
||||
@@ -47,13 +24,10 @@ recordtype(bo) {
|
||||
=head3 Scan Parameters
|
||||
|
||||
The binary output record has the standard fields for specifying under what
|
||||
circumstances the record will be processed. The fields are listed in
|
||||
circumstances the record will be processed.
|
||||
These fields are described in L<Scan Fields|dbCommonRecord/Scan Fields>.
|
||||
|
||||
L<Scan Fields|dbCommonRecord/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.
|
||||
|
||||
=fields SCAN
|
||||
=fields SCAN, PHAS, EVNT, PRIO, PINI
|
||||
|
||||
=head3 Desired Output Parameters
|
||||
|
||||
@@ -65,14 +39,14 @@ output mode select (OMSL) field, which can have two possible values:
|
||||
C<losed_loop> or C<supervisory>. If C<supervisory> is specified, the value
|
||||
in the VAL field can be set 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 (DOL) field which can be a
|
||||
address specified in the Desired Output Link (DOL) field which can be a
|
||||
database link or a channel access link, but not a constant. To achieve
|
||||
continuous control, a database link to a control algorithm record should be
|
||||
entered in the DOL field.
|
||||
|
||||
L<Address Specification> presents more information on database addresses
|
||||
and links. L<Scanning Specification> explaines the effect of database
|
||||
linkage on scanning.
|
||||
See L<Address
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
||||
for information on hardware addresses and links.
|
||||
|
||||
=fields DOL, OMSL
|
||||
|
||||
@@ -130,15 +104,17 @@ The OUT field specifies where the binary output record writes its output.
|
||||
It must specify the address of an I/O card if the record sends its output
|
||||
to hardware, and the DTYP field must contain the corresponding device
|
||||
support module. Be aware that the address format differs according to the
|
||||
I/O bus used. See L<Address Specification> for information on the format of
|
||||
hardware addresses.
|
||||
I/O bus used. See L<Address
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
||||
for information on the format of hardware addresses.
|
||||
|
||||
Otherwise, if the record is configured to use the soft device support
|
||||
modules, then it can be either a database link, a channel access link, or a
|
||||
constant. Be aware that nothing will be written when OUT is a constant. See
|
||||
L<Address Specification> for information on the format of the database and
|
||||
channel access addresses. Also, see L<Device Support For Soft Records> in
|
||||
this chapter for more on output to other records.
|
||||
Otherwise, if the record is configured to use the soft device support modules,
|
||||
then it can be either a database link, a channel access link, or a constant. Be
|
||||
aware that nothing will be written when OUT is a constant. See L<Address
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
||||
for information on the format of the database and channel access addresses.
|
||||
Also, see L<Device Support For Soft Records> in this chapter for more on output
|
||||
to other records.
|
||||
|
||||
=head3 Operator Display Parameters
|
||||
|
||||
@@ -243,7 +219,7 @@ for more information on simulation mode and its fields.
|
||||
menu(menuOmsl)
|
||||
}
|
||||
field(DOL,DBF_INLINK) {
|
||||
prompt("Desired Output Loc")
|
||||
prompt("Desired Output Link")
|
||||
promptgroup("40 - Input")
|
||||
interest(1)
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
#undef GEN_SIZE_OFFSET
|
||||
#include "epicsExport.h"
|
||||
|
||||
/* Hysterisis for alarm filtering: 1-1/e */
|
||||
/* Hysteresis for alarm filtering: 1-1/e */
|
||||
#define THRESHOLD 0.6321
|
||||
|
||||
/* Create RSET - Record Support Entry Table */
|
||||
|
||||
@@ -28,8 +28,9 @@ recordtype(calc) {
|
||||
|
||||
The Calc record has the standard fields for specifying under what
|
||||
circumstances the record will be processed.
|
||||
These fields are listed in L<Scan Fields|dbCommonRecord/Scan Fields>.
|
||||
These fields are described in L<Scan Fields|dbCommonRecord/Scan Fields>.
|
||||
|
||||
=fields SCAN, PHAS, EVNT, PRIO, PINI
|
||||
|
||||
=head3 Read Parameters
|
||||
|
||||
@@ -40,8 +41,9 @@ channel access link. If they are constants, they will be initialized with
|
||||
the value they are configured with and can be changed via C<dbPuts>. They
|
||||
cannot be hardware addresses.
|
||||
|
||||
See L<Address Specification> for information on how to specify database
|
||||
links.
|
||||
See L<Address
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
||||
for information on how to specify database links.
|
||||
|
||||
=fields INPA, INPB, INPC, INPD, INPE, INPF, INPG, INPH, INPI, INPJ, INPK, INPL
|
||||
|
||||
@@ -453,9 +455,12 @@ The following alarm parameters which are configured by the user, define the
|
||||
limit alarms for the VAL field and the severity corresponding to those
|
||||
conditions.
|
||||
|
||||
The HYST field defines an alarm deadband for each limit. See L<Alarm Specification>
|
||||
for a complete explanation of alarms of these fields. L<Alarm Fields|dbCommonRecord/Alarm Fields>
|
||||
lists other fields related to alarms that are common to all record types.
|
||||
The HYST field defines an alarm deadband for each limit.
|
||||
|
||||
See L<Alarm Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#alarm-specification>
|
||||
for a complete explanation of record alarms and of the standard fields.
|
||||
L<Alarm Fields|dbCommonRecord/Alarm Fields> lists other fields related
|
||||
to alarms that are common to all record types.
|
||||
|
||||
=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST
|
||||
|
||||
|
||||
@@ -245,7 +245,7 @@ static long process(struct dbCommon *pcommon)
|
||||
|
||||
if ( !pact ) {
|
||||
/* Update the timestamp before writing output values so it
|
||||
* will be uptodate if any downstream records fetch it via TSEL */
|
||||
* will be up to date if any downstream records fetch it via TSEL */
|
||||
recGblGetTimeStamp(prec);
|
||||
}
|
||||
/* check for output link execution */
|
||||
|
||||
@@ -535,13 +535,13 @@ the user and which describes the values being operated upon. The string is
|
||||
retrieved whenever the routine C<get_units()> is called. The EGU string is
|
||||
solely for an operator's sake and does not have to be used.
|
||||
|
||||
The HOPR and LOPR fields on;y refer to the limits if the VAL, HIHI, HIGH,
|
||||
The HOPR and LOPR fields only refer to the limits of the VAL, HIHI, HIGH,
|
||||
LOW, and LOLO fields. PREC controls the precision of the VAL field.
|
||||
|
||||
=head4 Menu calcoutINAV
|
||||
|
||||
The INAV-INLV fields indicate the status of the link to the PVs specified
|
||||
in the INPA-INPL fields, respectfully. These field can have four possible
|
||||
in the INPA-INPL fields respectively. These fields can have four possible
|
||||
values:
|
||||
|
||||
=menu calcoutINAV
|
||||
@@ -568,7 +568,7 @@ The OUTV field indicates the status of the OUT link. If has the same
|
||||
possible values as the INAV-INLV fields.
|
||||
|
||||
The CLCV and OLCV fields indicate the validity of the expression in the
|
||||
CALC and OCAL fields respectfully. If the expression in invalid, the field
|
||||
CALC and OCAL fields respectively. If the expression in invalid, the field
|
||||
is set to one.
|
||||
|
||||
The DLYA field is set to one during the delay specified in ODLY.
|
||||
@@ -590,10 +590,12 @@ The following alarm parameters, which are configured by the user, define the
|
||||
limit alarms for the VAL field and the severity corresponding to those
|
||||
conditions.
|
||||
|
||||
The HYST field defines an alarm deadband for each limit. See
|
||||
L<Alarm Specification> for a complete explanation of alarms and these
|
||||
fields. C<Alarm Fields> lists other fields related to alarms that are
|
||||
common to all record types.
|
||||
The HYST field defines an alarm deadband for each limit.
|
||||
|
||||
See L<Alarm Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#alarm-specification>
|
||||
for a complete explanation of record alarms and of the standard fields.
|
||||
L<Alarm Fields|dbCommonRecord/Alarm Fields> lists other fields related
|
||||
to alarms that are common to all record types.
|
||||
|
||||
=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST
|
||||
|
||||
@@ -1218,7 +1220,7 @@ honors the alarm hysteresis factor (HYST). Thus the value must change by at
|
||||
least HYST before the alarm status and severity changes.
|
||||
|
||||
=item 4.
|
||||
Determine if the Output Execution Option (OOPT) is met. If it met, either
|
||||
Determine if the Output Execution Option (OOPT) is met. If met, either
|
||||
execute the output link (and output event) immediately (if ODLY = 0), or
|
||||
schedule a callback after the specified interval. See the explanation for
|
||||
the C<execOutput()> routine below.
|
||||
|
||||
@@ -67,11 +67,12 @@ The record-specific fields are described below, grouped by functionality.
|
||||
=head3 Scanning Parameters
|
||||
|
||||
The compression record has the standard fields for specifying under what
|
||||
circumstances the record will be processed. These fields are listed in
|
||||
circumstances the record will be processed. Since the compression record
|
||||
supports no direct interfaces to hardware, its SCAN field cannot be set to C<<<
|
||||
I/O Intr >>>.
|
||||
These fields are described in L<Scan Fields|dbCommonRecord/Scan Fields>.
|
||||
|
||||
L<Scan Fields|dbCommonRecord/Scan Fields>. In addition, L<Scanning Specification>
|
||||
explains how these fields are used. Since the compression record supports no
|
||||
direct interfaces to hardware, its SCAN field cannot specify C<<< I/O Intr >>>.
|
||||
=fields SCAN, PHAS, EVNT, PRIO, PINI
|
||||
|
||||
=head3 Algorithms and Related Parameters
|
||||
|
||||
@@ -88,9 +89,11 @@ The following fields determine what channel to read and how to compress the data
|
||||
|
||||
As stated above, the ALG field specifies which algorithm to be performed on the data.
|
||||
|
||||
The INP should be a database or channel access link. Though INP can be a constant,
|
||||
the data compression algorithms are supported only when INP is a database link. See
|
||||
L<Address Specification> for information on specifying links.
|
||||
The INP should be a database or channel access link. Though INP can be a
|
||||
constant, the data compression algorithms are supported only when INP is a
|
||||
database link. See L<Address
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
||||
for information on specifying links.
|
||||
|
||||
|
||||
IHIL and ILIL can be set to provide an initial value filter on the input array.
|
||||
|
||||
@@ -43,7 +43,7 @@ originates, i.e., the data which is to be fowarded to the records in its
|
||||
output links. The output mode select (OMSL) field determines whether the
|
||||
output originates from another record or from run-time database access.
|
||||
When set to C<closed_loop>, the desired output is retrieved from the link
|
||||
specified in the desired output (DOL) field, which can specify either a
|
||||
specified in the Desired Output Link (DOL) field, which can specify either a
|
||||
database or a channel access link, and placed into the VAL field. When set
|
||||
to C<supervisory>, the desired output can be written to the VAL field via
|
||||
dbPuts at run-time.
|
||||
@@ -59,8 +59,9 @@ undergoes no conversions before it is sent out to the output links.
|
||||
=head3 Write Parameters
|
||||
|
||||
The OUTA-OUTH fields specify where VAL is to be sent. Each field that is to
|
||||
forward data must specify an address to another record. See
|
||||
L<Address Specification> for information on specifying links.
|
||||
forward data must specify an address to another record. See L<Address
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
||||
for information on specifying links.
|
||||
|
||||
The SELL, SELM, and SELN fields specify which output links are to be
|
||||
used.
|
||||
@@ -71,42 +72,57 @@ SELM is a menu, with three choices:
|
||||
|
||||
=menu dfanoutSELM
|
||||
|
||||
If SELM=="All", then all output links are used, and the values of
|
||||
If SELM is C<All>, then all output links are used, and the values of
|
||||
SELL and SELN are ignored.
|
||||
|
||||
If SELM=="Specified", then the value of SELN is used to specify a single
|
||||
If SELM is C<Specified>, then the value of SELN is used to specify a single
|
||||
link which will be used. If SELN==0, then no link will be used; if SELN==1,
|
||||
then OUTA will be used, and so on.
|
||||
|
||||
SELN can either have its value set directly, or have its values retrieved
|
||||
from another EPICS PV. If SELL is a valid PV link, then SELN will be set to
|
||||
the values of the linked PV.
|
||||
SELN can either have its value set directly, or have it retrieved from
|
||||
another EPICS PV. If SELL is a valid PV link, then SELN will be read from
|
||||
the linked PV.
|
||||
|
||||
If SELM=="Mask", then SELN will be treated as a bit mask. If bit one of
|
||||
SELN is set, then OUTA will be used, if bit two is set, OUTB will be used.
|
||||
Thus if SELN==5, OUTC and OUTA will be used.
|
||||
If SELM is C<Mask>, then SELN will be treated as a bit mask. If bit zero
|
||||
(the LSB) of SELN is set, then OUTA will be written to; if bit one is set,
|
||||
OUTB will be written to, and so on. Thus when SELN==5, both OUTC and OUTA
|
||||
will be written to.
|
||||
|
||||
=fields OUTA, OUTB, OUTC, OUTD, OUTE, OUTF, OUTG, OUTH
|
||||
=fields SELL, SELM, SELN, OUTA, OUTB, OUTC, OUTD, OUTE, OUTF, OUTG, OUTH
|
||||
|
||||
=head3 Operator Display Parameters
|
||||
|
||||
These parameters are used to present meaningful data to the operator. They
|
||||
display the value and other parameters of the data fanout record either
|
||||
textually or graphically.
|
||||
These parameters are used to present meaningful data to the operator.
|
||||
They do not affect the functioning of the record at all.
|
||||
|
||||
The EGU field can contain a string of up to 16 characters describing the
|
||||
value on the VAL field.
|
||||
=over
|
||||
|
||||
The HOPR and LOPR fields determine the upper and lower display limits for
|
||||
graphic displays and the upper and lower control limits for control
|
||||
displays. They apply to the VAL, HIHI, HIGH, LOW, and LOLO fields. The
|
||||
record support routines C<get_graphic_double()> and C<get_control_double()>
|
||||
retrieve HOPR and LOPR.
|
||||
=item *
|
||||
NAME is the record's name, and can be useful when the PV name that a client
|
||||
knows is an alias for the record.
|
||||
|
||||
=item *
|
||||
DESC is a string that is usually used to briefly describe the record.
|
||||
|
||||
=item *
|
||||
EGU is a string of up to 16 characters naming the engineering units that the VAL
|
||||
field represents.
|
||||
|
||||
=item *
|
||||
The HOPR and LOPR fields set the upper and lower display limits for the VAL,
|
||||
HIHI, HIGH, LOW, and LOLO fields.
|
||||
|
||||
=item *
|
||||
The PREC field determines the floating point precision (i.e. the number of
|
||||
digits to show after the decimal point) with which to display VAL and the other
|
||||
DOUBLE fields.
|
||||
|
||||
=back
|
||||
|
||||
See L<Fields Common to All Record Types|dbCommonRecord/Operator Display
|
||||
Parameters> for more on the record name (NAME) and description (DESC) fields.
|
||||
Parameters> for more about the record name (NAME) and description (DESC) fields.
|
||||
|
||||
=fields EGU, HOPR, LOPR, NAME, DESC
|
||||
=fields NAME, DESC, EGU, HOPR, LOPR, PREC
|
||||
|
||||
=head3 Alarm Parameters
|
||||
|
||||
@@ -119,9 +135,10 @@ in the corresponding field (HHSV, LLSV, HSV, LSV) and can be either
|
||||
NO_ALARM, MINOR, or MAJOR. In the hysteresis field (HYST) can be entered a
|
||||
number which serves as the deadband on the limit alarms.
|
||||
|
||||
See L<Alarm Specification> for a complete explanation of alarms and these
|
||||
fields. L<Alarm Fields|dbCommonRecord/Alarm Fields> lists other fields related to alarms that are
|
||||
common to all record types.
|
||||
See L<Alarm Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#alarm-specification>
|
||||
for a complete explanation of record alarms and of the standard fields.
|
||||
L<Alarm Fields|dbCommonRecord/Alarm Fields> lists other fields related
|
||||
to alarms that are common to all record types.
|
||||
|
||||
=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST
|
||||
|
||||
@@ -211,7 +228,7 @@ hysteresis factors for monitor callbacks.
|
||||
interest(1)
|
||||
}
|
||||
field(DOL,DBF_INLINK) {
|
||||
prompt("Desired Output Loc")
|
||||
prompt("Desired Output Link")
|
||||
promptgroup("40 - Input")
|
||||
interest(1)
|
||||
}
|
||||
|
||||
@@ -37,10 +37,10 @@ recordtype(event) {
|
||||
=head3 Scan Parameters
|
||||
|
||||
The event record has the standard fields for specifying under what circumstances
|
||||
it will be processed. If the SCAN field specifies C<I/O Intr>, then device
|
||||
support will provide an interrupt handler, posting an event number when an I/O
|
||||
interrupt occurs.
|
||||
These fields are listed in L<Scan Fields|dbCommonRecord/Scan Fields>.
|
||||
it will be processed.
|
||||
These fields are described in L<Scan Fields|dbCommonRecord/Scan Fields>.
|
||||
|
||||
=fields SCAN, PHAS, EVNT, PRIO, PINI
|
||||
|
||||
=head3 Event Number Parameters
|
||||
|
||||
@@ -73,8 +73,9 @@ The device support routines use the address in this record to obtain input. For
|
||||
records that provide an interrupt handler, the INP field should specify the
|
||||
address of the I/O card, and the DTYP field should specify a valid device
|
||||
support module. Be aware that the address format differs according to the card
|
||||
type used. See L<Address Specification> for information on the format of
|
||||
hardware addresses and specifying links.
|
||||
type used. See L<Address
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
||||
for information on the format of hardware addresses and specifying links.
|
||||
|
||||
For soft records, the INP field can be a constant, a database link, or a channel
|
||||
access link. For soft records, the DTYP field should specify C<Soft Channel>.
|
||||
|
||||
@@ -160,7 +160,7 @@ static long init_record(struct dbCommon *pcommon, int pass)
|
||||
prec->bptr = calloc(prec->nelm, sizeof(epicsUInt32));
|
||||
}
|
||||
|
||||
/* calulate width of array element */
|
||||
/* calculate width of array element */
|
||||
prec->wdth = (prec->ulim - prec->llim) / prec->nelm;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
#undef GEN_SIZE_OFFSET
|
||||
#include "epicsExport.h"
|
||||
|
||||
/* Hysterisis for alarm filtering: 1-1/e */
|
||||
/* Hysteresis for alarm filtering: 1-1/e */
|
||||
#define THRESHOLD 0.6321
|
||||
/* Create RSET - Record Support Entry Table*/
|
||||
#define report NULL
|
||||
@@ -359,16 +359,16 @@ static void checkAlarms(int64inRecord *prec, epicsTimeStamp *timeLast)
|
||||
}
|
||||
|
||||
/* DELTA calculates the absolute difference between its arguments
|
||||
* expressed as an unsigned 32-bit integer */
|
||||
* expressed as an unsigned 64-bit integer */
|
||||
#define DELTA(last, val) \
|
||||
((epicsUInt32) ((last) > (val) ? (last) - (val) : (val) - (last)))
|
||||
((epicsUInt64) ((last) > (val) ? (last) - (val) : (val) - (last)))
|
||||
|
||||
static void monitor(int64inRecord *prec)
|
||||
{
|
||||
unsigned short monitor_mask = recGblResetAlarms(prec);
|
||||
|
||||
if (prec->mdel < 0 ||
|
||||
DELTA(prec->mlst, prec->val) > (epicsUInt32) prec->mdel) {
|
||||
DELTA(prec->mlst, prec->val) > (epicsUInt64) prec->mdel) {
|
||||
/* post events for value change */
|
||||
monitor_mask |= DBE_VALUE;
|
||||
/* update last value monitored */
|
||||
@@ -376,7 +376,7 @@ static void monitor(int64inRecord *prec)
|
||||
}
|
||||
|
||||
if (prec->adel < 0 ||
|
||||
DELTA(prec->alst, prec->val) > (epicsUInt32) prec->adel) {
|
||||
DELTA(prec->alst, prec->val) > (epicsUInt64) prec->adel) {
|
||||
/* post events for archive value change */
|
||||
monitor_mask |= DBE_LOG;
|
||||
/* update last archive value monitored */
|
||||
|
||||
@@ -146,7 +146,7 @@ static long process(dbCommon *pcommon)
|
||||
if (!status) convert(prec,value);
|
||||
|
||||
/* Update the timestamp before writing output values so it
|
||||
* will be uptodate if any downstream records fetch it via TSEL */
|
||||
* will be up to date if any downstream records fetch it via TSEL */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -154,7 +154,7 @@ monitoring deadband functionality.
|
||||
interest(1)
|
||||
}
|
||||
field(DOL,DBF_INLINK) {
|
||||
prompt("Desired Output Loc")
|
||||
prompt("Desired Output Link")
|
||||
promptgroup("40 - Input")
|
||||
interest(1)
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
#undef GEN_SIZE_OFFSET
|
||||
#include "epicsExport.h"
|
||||
|
||||
/* Hysterisis for alarm filtering: 1-1/e */
|
||||
/* Hysteresis for alarm filtering: 1-1/e */
|
||||
#define THRESHOLD 0.6321
|
||||
/* Create RSET - Record Support Entry Table*/
|
||||
#define report NULL
|
||||
|
||||
@@ -148,7 +148,7 @@ static long process(struct dbCommon *pcommon)
|
||||
if (!status) convert(prec,value);
|
||||
|
||||
/* Update the timestamp before writing output values so it
|
||||
* will be uptodate if any downstream records fetch it via TSEL */
|
||||
* will be up to date if any downstream records fetch it via TSEL */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -38,10 +38,10 @@ The record must specify where the desired output originates, i.e., the 32 bit
|
||||
integer value it is to write. The output mode select (OMSL) field determines
|
||||
whether the output originates from another record or from database access. When
|
||||
set to C<<< closed_loop >>>, the desired output is retrieved from the link
|
||||
specified in the desired output (DOL) field (which can specify either a database
|
||||
or channel access link) and placed into the VAL field. When set to C<<<
|
||||
supervisory >>>, the desired output can be written into the VAL field via dpPuts
|
||||
at run-time.
|
||||
specified in the Desired Output Link (DOL) field (which can specify either a
|
||||
database or channel access link) and placed into the VAL field. When set to
|
||||
C<<< supervisory >>>, the desired output can be written into the VAL field via
|
||||
dpPuts at run-time.
|
||||
|
||||
A third type of value for the DOL field is a constant in which case, when the
|
||||
record is initialized, the VAL field will be initialized with this constant
|
||||
@@ -68,8 +68,9 @@ For soft records, the OUT output link can be a constant, a database link, or a
|
||||
channel access link. If the link is a constant, the result is no output. The
|
||||
DTYP field must then specify the C<<< Soft Channel >>> device support routine.
|
||||
|
||||
See L<Address Specification> for information on the format of hardware addresses
|
||||
and database links.
|
||||
See L<Address
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
||||
for information on the format of hardware addresses and database links.
|
||||
|
||||
=fields OUT, DTYP
|
||||
|
||||
@@ -97,7 +98,7 @@ and database links.
|
||||
interest(1)
|
||||
}
|
||||
field(DOL,DBF_INLINK) {
|
||||
prompt("Desired Output Loc")
|
||||
prompt("Desired Output Link")
|
||||
promptgroup("40 - Input")
|
||||
interest(1)
|
||||
}
|
||||
@@ -172,13 +173,17 @@ record's output. The IVOA field specifies the action to take in this case.
|
||||
|
||||
The limit alarms are configured by the user in the HIHI, LOLO, HIGH, and LOW
|
||||
fields using floating-point values. For each of these fields, there is a
|
||||
corresponding severity field which can be either NO_ALARM, MINOR, or MAJOR. The
|
||||
HYST field contains the alarm deadband around each limit alarm.
|
||||
corresponding severity field which can be either NO_ALARM, MINOR, or MAJOR.
|
||||
|
||||
See L<Alarm Specification> for a complete explanation of alarms and
|
||||
these fields. For an explanation of the IVOA and IVOV fields, see L<Output
|
||||
Records>. L<Alarm Fields|dbCommonRecord/Alarm Fields> lists the fields related to
|
||||
alarms that are common to all record types.
|
||||
The HYST field sets an alarm deadband around each limit alarm.
|
||||
|
||||
For an explanation of the IVOA and IVOV fields, see
|
||||
L<Invalid Output Action Fields|dbCommonOutput/Invalid Output Action Fields>.
|
||||
|
||||
See L<Alarm Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#alarm-specification>
|
||||
for a complete explanation of record alarms and of the standard fields.
|
||||
L<Alarm Fields|dbCommonRecord/Alarm Fields> lists other fields related
|
||||
to alarms that are common to all record types.
|
||||
|
||||
=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST, IVOA, IVOV
|
||||
|
||||
|
||||
@@ -31,21 +31,21 @@ These fields are listed in L<Scan Fields|dbCommonRecord/Scan Fields>.
|
||||
|
||||
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 output mode select (OMSL) field, which can have two possible values:
|
||||
C<closed_loop> or C<supervisory>. If C<closed_loop> is specified, the VAL
|
||||
field's value is fetched from the address specified in the Desired Output Link
|
||||
field (DOL) which can be either a database link or a channel access link. 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.
|
||||
|
||||
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>.
|
||||
DOL can also be a constant instead of a link, in which case VAL is initialized
|
||||
to the constant value. Most simple string constants are likely to be interpreted
|
||||
as a CA link name though. To initialize a string output record it is simplest
|
||||
to set the VAL field directly; alternatively use a JSON constant link type in
|
||||
the DOL field.
|
||||
|
||||
=fields VAL, SIZV, DOL, OMSL
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ an array of 32 unsigned characters, each representing a bit of the word.
|
||||
These fields (B0-B9, BA-BF, B10-B19, B1A-B1F) are set to 1 if the corresponding
|
||||
bit is set, and 0 if not.
|
||||
|
||||
This record's operation is similar to that of the multi-bit binary input record,
|
||||
This record's operation is similar to that of the
|
||||
L<multi-bit binary input record|mbbiRecord>,
|
||||
and it has many fields in common with it. This record also has two available
|
||||
soft device support modules: C<Soft Channel> and C<Raw Soft Channel>.
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
#undef GEN_SIZE_OFFSET
|
||||
#include "epicsExport.h"
|
||||
|
||||
/* Hysterisis for alarm filtering: 1-1/e */
|
||||
/* Hysteresis for alarm filtering: 1-1/e */
|
||||
#define THRESHOLD 0.6321
|
||||
|
||||
/* Create RSET - Record Support Entry Table*/
|
||||
@@ -177,7 +177,7 @@ static long process(struct dbCommon *pcommon)
|
||||
|
||||
if (prec->sdef) {
|
||||
pstate_values = &(prec->zrvl);
|
||||
prec->val = 65535; /* Initalize to unknown state*/
|
||||
prec->val = 65535; /* Initialize to unknown state*/
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (*pstate_values == rval) {
|
||||
prec->val = i;
|
||||
|
||||
@@ -413,9 +413,12 @@ The change of state severity (COSV) field triggers an alarm when any change of
|
||||
state occurs, if set to MAJOR or MINOR.
|
||||
|
||||
The other fields, when set to MAJOR or MINOR, trigger an alarm when VAL equals
|
||||
the corresponding state. See the See L<Alarm Specification> for a complete
|
||||
explanation of discrete alarms and these fields. L<Alarm Fields|dbCommonRecord/Alarm Fields> lists other
|
||||
fields related to a alarms that are common to all record types.
|
||||
the corresponding state.
|
||||
|
||||
See L<Alarm Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#alarm-specification>
|
||||
for a complete explanation of record alarms and of the standard fields.
|
||||
L<Alarm Fields|dbCommonRecord/Alarm Fields> lists other fields related
|
||||
to alarms that are common to all record types.
|
||||
|
||||
=fields UNSV, COSV, ZRSV, ONSV, TWSV, THSV, FRSV, FVSV, SXSV, SVSV, EISV, NISV, TESV, ELSV, TVSV, TTSV, FTSV, FFSV
|
||||
|
||||
|
||||
@@ -88,6 +88,14 @@ static long writeValue(mbboDirectRecord *);
|
||||
|
||||
#define NUM_BITS 32
|
||||
|
||||
static
|
||||
void bitsFromVAL(mbboDirectRecord *prec)
|
||||
{
|
||||
unsigned i;
|
||||
for(i=0; i<NUM_BITS; i++)
|
||||
(&prec->b0)[i] = !!(prec->val&(1u<<i));
|
||||
}
|
||||
|
||||
static long init_record(struct dbCommon *pcommon, int pass)
|
||||
{
|
||||
struct mbboDirectRecord *prec = (struct mbboDirectRecord *)pcommon;
|
||||
@@ -131,16 +139,21 @@ static long init_record(struct dbCommon *pcommon, int pass)
|
||||
status = 0;
|
||||
}
|
||||
|
||||
if (!prec->udf &&
|
||||
prec->omsl == menuOmslsupervisory) {
|
||||
/* Set initial B0 - B1F from VAL */
|
||||
epicsUInt32 val = prec->val;
|
||||
if (!prec->udf)
|
||||
bitsFromVAL(prec);
|
||||
else {
|
||||
/* Did user set any of the B0-B1F fields? */
|
||||
epicsUInt8 *pBn = &prec->b0;
|
||||
epicsUInt32 val = 0, bit = 1;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_BITS; i++) {
|
||||
*pBn++ = !! (val & 1);
|
||||
val >>= 1;
|
||||
for (i = 0; i < NUM_BITS; i++, bit <<= 1)
|
||||
if (*pBn++)
|
||||
val |= bit;
|
||||
|
||||
if (val) { /* Yes! */
|
||||
prec->val = val;
|
||||
prec->udf = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,29 +187,18 @@ static long process(struct dbCommon *pcommon)
|
||||
}
|
||||
prec->val = val;
|
||||
}
|
||||
else if (prec->omsl == menuOmslsupervisory) {
|
||||
epicsUInt8 *pBn = &prec->b0;
|
||||
epicsUInt32 val = 0;
|
||||
epicsUInt32 bit = 1;
|
||||
int i;
|
||||
|
||||
/* Construct VAL from B0 - B1F */
|
||||
for (i = 0; i < NUM_BITS; i++, bit <<= 1)
|
||||
if (*pBn++)
|
||||
val |= bit;
|
||||
prec->val = val;
|
||||
}
|
||||
else if (prec->udf) {
|
||||
recGblSetSevr(prec, UDF_ALARM, prec->udfs);
|
||||
recGblSetSevrMsg(prec, UDF_ALARM, prec->udfs, "UDFS");
|
||||
goto CONTINUE;
|
||||
}
|
||||
|
||||
prec->udf = FALSE;
|
||||
bitsFromVAL(prec);
|
||||
/* Convert VAL to RVAL */
|
||||
convert(prec);
|
||||
|
||||
/* Update the timestamp before writing output values so it
|
||||
* will be uptodate if any downstream records fetch it via TSEL */
|
||||
* will be up to date if any downstream records fetch it via TSEL */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
@@ -234,6 +236,9 @@ CONTINUE:
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
/* update bits to reflect any change made by dset */
|
||||
bitsFromVAL(prec);
|
||||
|
||||
monitor(prec);
|
||||
|
||||
/* Wrap up */
|
||||
@@ -255,60 +260,37 @@ static long special(DBADDR *paddr, int after)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!after)
|
||||
return 0;
|
||||
|
||||
switch (paddr->special) {
|
||||
case SPC_MOD: /* Bn field modified */
|
||||
if (prec->omsl == menuOmslsupervisory) {
|
||||
/* Adjust VAL corresponding to the bit changed */
|
||||
epicsUInt8 *pBn = (epicsUInt8 *) paddr->pfield;
|
||||
epicsUInt32 bit = 1 << (pBn - &prec->b0);
|
||||
|
||||
if (*pBn)
|
||||
prec->val |= bit;
|
||||
else
|
||||
prec->val &= ~bit;
|
||||
|
||||
prec->udf = FALSE;
|
||||
convert(prec);
|
||||
if(after==0 && fieldIndex >= mbboDirectRecordB0 && fieldIndex <= mbboDirectRecordB1F) {
|
||||
if(prec->omsl == menuOmslclosed_loop) {
|
||||
/* To avoid confusion, reject changes to bit fields while in closed loop.
|
||||
* Not a 100% solution as confusion can still arise if dset overwrites VAL.
|
||||
*/
|
||||
return S_db_noMod;
|
||||
}
|
||||
break;
|
||||
|
||||
case SPC_RESET: /* OMSL field modified */
|
||||
if (prec->omsl == menuOmslclosed_loop) {
|
||||
/* Construct VAL from B0 - B1F */
|
||||
epicsUInt8 *pBn = &prec->b0;
|
||||
epicsUInt32 val = 0, bit = 1;
|
||||
int i;
|
||||
} else if(after==1 && fieldIndex >= mbboDirectRecordB0 && fieldIndex <= mbboDirectRecordB1F) {
|
||||
/* Adjust VAL corresponding to the bit changed */
|
||||
epicsUInt8 *pBn = (epicsUInt8 *) paddr->pfield;
|
||||
epicsUInt32 bit = 1 << (pBn - &prec->b0);
|
||||
|
||||
for (i = 0; i < NUM_BITS; i++, bit <<= 1)
|
||||
if (*pBn++)
|
||||
val |= bit;
|
||||
prec->val = val;
|
||||
/* Because this is !(VAL and PP), dbPut() will always post a monitor on this B* field
|
||||
* after we return. We must keep track of this change separately from MLST to handle
|
||||
* situations where VAL and B* are changed prior to next monitor(). eg. by dset to
|
||||
* reflect bits actually written. This is the role of OBIT.
|
||||
*/
|
||||
|
||||
if (*pBn) {
|
||||
prec->val |= bit;
|
||||
prec->obit |= bit;
|
||||
} else {
|
||||
prec->val &= ~bit;
|
||||
prec->obit &= ~bit;
|
||||
}
|
||||
else if (prec->omsl == menuOmslsupervisory) {
|
||||
/* Set B0 - B1F from VAL and post monitors */
|
||||
epicsUInt32 val = prec->val;
|
||||
epicsUInt8 *pBn = &prec->b0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_BITS; i++, pBn++, val >>= 1) {
|
||||
epicsUInt8 oBn = *pBn;
|
||||
|
||||
*pBn = !! (val & 1);
|
||||
if (oBn != *pBn)
|
||||
db_post_events(prec, pBn, DBE_VALUE | DBE_LOG);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
recGblDbaddrError(S_db_badChoice, paddr, "mbboDirect: special");
|
||||
return S_db_badChoice;
|
||||
prec->udf = FALSE;
|
||||
convert(prec);
|
||||
}
|
||||
|
||||
prec->udf = FALSE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -330,8 +312,21 @@ static void monitor(mbboDirectRecord *prec)
|
||||
events |= DBE_VALUE | DBE_LOG;
|
||||
prec->mlst = prec->val;
|
||||
}
|
||||
if (events)
|
||||
if (events) {
|
||||
db_post_events(prec, &prec->val, events);
|
||||
}
|
||||
{
|
||||
unsigned i;
|
||||
epicsUInt32 bitsChanged = prec->obit ^ (epicsUInt32)prec->val;
|
||||
|
||||
for(i=0; i<NUM_BITS; i++) {
|
||||
/* post bit when value or alarm severity changes */
|
||||
if((events&~(DBE_VALUE|DBE_LOG)) || (bitsChanged&(1u<<i))) {
|
||||
db_post_events(prec, (&prec->b0)+i, events | DBE_VALUE | DBE_LOG);
|
||||
}
|
||||
}
|
||||
prec->obit = prec->val;
|
||||
}
|
||||
|
||||
events |= DBE_VALUE | DBE_LOG;
|
||||
if (prec->oraw != prec->rval) {
|
||||
|
||||
@@ -9,11 +9,14 @@
|
||||
|
||||
=title Multi-Bit Binary Output Direct Record (mbboDirect)
|
||||
|
||||
The mbboDirect record performs the opposite function to that of the mbbiDirect
|
||||
record. It accumulates bits (in the fields B0 - BF) as unsigned characters, and
|
||||
converts them to a word which is then written out to hardware. If a bit field is
|
||||
non-zero, it is interpreted as a binary 1. On the other hand, if it is zero, it
|
||||
is interpreted as a binary 0.
|
||||
The mbboDirect record performs roughly the opposite function to that of the
|
||||
L<mbbiDirect record|mbbiDirectRecord>.
|
||||
|
||||
It can accept boolean values in its 32 bit fields (B0-B9, BA-BF, B10-B19 and
|
||||
B1A-B1F), and converts them to a 32-bit signed integer in VAL which is provided
|
||||
to the device support. A zero value in a bit field becomes a zero bit in VAL, a
|
||||
non-zero value in a bit field becomes a one bit in VAL, with B0 being the least
|
||||
signficant bit and B1F the MSB/sign bit.
|
||||
|
||||
=recordtype mbboDirect
|
||||
|
||||
@@ -31,50 +34,86 @@ The mbboDirect record has the standard fields for specifying under what
|
||||
circumstances it will be processed.
|
||||
These fields are listed in L<Scan Fields|dbCommonRecord/Scan Fields>.
|
||||
|
||||
=fields SCAN, PHAS, EVNT, PRIO, PINI
|
||||
|
||||
=head3 Desired Output Parameters
|
||||
|
||||
The mbboDirect record, like all output records, must specify where its output
|
||||
originates. The output mode select field (OMSL) determines whether the output
|
||||
originates from another record or from database access. When set to C<<<
|
||||
closed_loop >>>, the desired output is retrieved from the link specified in the
|
||||
desired output (DOL) field--which can specify either a database or channel
|
||||
access link--and placed into the VAL field. When set to C<<< supervisory >>>,
|
||||
the DOL field is ignored and the current value of VAL is used. The desired
|
||||
output can be written into the VAL field via dpPuts at run-time when the record
|
||||
is in C<<< supervisory >>> mode. DOL can also be a constant, in which case VAL
|
||||
is initialized to the constant value. Note that OMSL cannot be C<<< closed_loop
|
||||
>>> when DOL is a constant.
|
||||
Like all output records, the mbboDirect record must specify where its output
|
||||
should originate when it gets processed. The Output Mode SeLect field (OMSL)
|
||||
determines whether the output value should be read from another record or not.
|
||||
When set to C<<< closed_loop >>>, a 32-bit integer value (the "desired output")
|
||||
will be read from a link specified in the Desired Output Link (DOL) field and
|
||||
placed into the VAL field.
|
||||
|
||||
VAL is then converted to RVAL in the routine described in the next section.
|
||||
However, the C<<< Soft Channel >>> device support module for the mbboDirect
|
||||
record writes the VAL field's value without any conversion.
|
||||
When OMSL is set to C<<< supervisory >>>, the DOL field is ignored during
|
||||
processing and the contents of VAL are used. A value to be output may thus be
|
||||
written direcly into the VAL field from elsewhere as long as the record is in
|
||||
C<<< supervisory >>> mode.
|
||||
|
||||
=fields OMSL, DOL, VAL
|
||||
|
||||
=head4 Bit Fields
|
||||
|
||||
The fields B0 through BF and B10 through B1F provide an alternative way to set
|
||||
the individual bits of the VAL field when the record is in C<<< supervisory >>>
|
||||
mode. Writing to one of these fields will then modify the corresponding bit in
|
||||
VAL, and writing to VAL will update these bit fields from that value.
|
||||
|
||||
The VAL field is signed so it can be accessed through Channel Access as an
|
||||
integer; if it were made unsigned (a C<DBF_ULONG>) its representation through
|
||||
Channel Access would become a C<double>, which could cause problems with some
|
||||
client programs.
|
||||
|
||||
Prior to the EPICS 7.0.6.1 release the individual bit fields were not updated
|
||||
while the record was in C<<< closed_loop >>> mode with VAL being set from the
|
||||
DOL link, and writing to the bit fields in that mode could cause the record to
|
||||
process but the actual field values would not affect VAL at all. Changing the
|
||||
OMSL field from C<<< closed_loop >>> to C<<< supervisory >>> would set the bit
|
||||
fields from VAL at that time and trigger a monitor event for the bits that
|
||||
changed at that time. At record initialization if VAL is defined and the OMSL
|
||||
field is C<<< supervisory >>> the bit fields would be set from VAL.
|
||||
|
||||
From EPICS 7.0.6.1 the bit fields get updated from VAL during record processing
|
||||
and monitors are triggered on them in either mode. Attempts to write to the bit
|
||||
fields while in C<<< closed_loop >>> mode will be rejected by the C<special()>
|
||||
routine which may trigger an error from the client that wrote to them. During
|
||||
initialization if the record is still undefined (UDF) after DOL has been read
|
||||
and the device support initialized but at least one of the B0-B1F fields is
|
||||
non-zero, the VAL field will be set from those fields and UDF will be cleared.
|
||||
|
||||
=fields B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, BA, BB, BC, BD, BE, BF, B10, B11, B12, B13, B14, B15, B16, B17, B18, B19, B1A, B1B, B1C, B1D, B1E, B1F
|
||||
|
||||
=head3 Convert and Write Parameters
|
||||
|
||||
For records that are to write values to hardware devices, the OUT output link
|
||||
must contain the address of the I/O card, and the DTYP field must specify
|
||||
the proper device support module. Be aware that the address format differs
|
||||
according to the I/O bus used. See L<Address Specification> for information
|
||||
on the format of hardware addresses.
|
||||
according to the I/O bus used. See L<Address
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#address-specification>
|
||||
for information on the format of hardware addresses.
|
||||
|
||||
If the mbboDirect record does not use the C<<< Soft Channel >>> device support
|
||||
module, then VAL is converted to RVAL, and RVAL is the actual 16-bit word sent
|
||||
out. RVAL is set equal to VAL and then shifted left by the number of bits
|
||||
specified in the SHFT field (the SHFT value is set by device support and is not
|
||||
configurable by the user). RVAL is then sent out to the location specified in
|
||||
the OUT field.
|
||||
During record processing VAL is converted into RVAL, which is the actual 32-bit
|
||||
word to be sent out. RVAL is set to VAL shifted left by the number of bits
|
||||
specified in the SHFT field (SHFT is normally set by device support). RVAL is
|
||||
then sent out to the location specified in the OUT field.
|
||||
|
||||
For mbboDirect records that specify a database link, a channel access link, or a
|
||||
constant, the DTYP field must specify either one of two soft device support
|
||||
routines--{Soft Channel} or C<<< Raw Soft Channel >>>. The difference between
|
||||
the two is that C<<< Soft Channel >>> writes the desired output value from VAL
|
||||
directly to the output link while C<<< Raw Soft Channel >>> writes the value
|
||||
from RVAL to the output link after it has undergone the conversion described
|
||||
above.
|
||||
The fields NOBT and MASK can be used by device support to force some of the
|
||||
output bits written by that support to be zero. By default all 32 bits can be
|
||||
sent, but the NOBT field can be set to specify a smaller number of contiguous
|
||||
bits, or MASK can specify a non-contiguous set of bits. When setting MASK it is
|
||||
often necessary to set NOBT to a non-zero value as well, although in this case
|
||||
the actual value of NOBT may be ignored by the device support. If a device
|
||||
support sets the SHFT field it will also left-shift the value of MASK at the
|
||||
same time.
|
||||
|
||||
=fields OUT, RVAL, SHFT, B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, BA, BB, BC, BD, BE, BF
|
||||
For mbboDirect records writing to a link instead of to hardware, the DTYP field
|
||||
must select one of the soft device support routines C<<< Soft Channel >>> or
|
||||
C<<< Raw Soft Channel >>>. The C<<< Soft Channel >>> support writes the contents
|
||||
of the VAL field to the output link. The C<<< Raw Soft Channel >>> support
|
||||
allows SHFT to be set in the DB file, and sends the result of ANDing the shifted
|
||||
MASK with the RVAL field's value.
|
||||
|
||||
=fields OUT, RVAL, SHFT, MASK, NOBT
|
||||
|
||||
=head3 Operator Display Parameters
|
||||
|
||||
@@ -104,7 +143,6 @@ Parameters> for more on the record name (NAME) and description (DESC) fields.
|
||||
field(OMSL,DBF_MENU) {
|
||||
prompt("Output Mode Select")
|
||||
promptgroup("50 - Output")
|
||||
special(SPC_RESET)
|
||||
pp(TRUE)
|
||||
interest(1)
|
||||
menu(menuOmsl)
|
||||
@@ -116,7 +154,7 @@ Parameters> for more on the record name (NAME) and description (DESC) fields.
|
||||
interest(1)
|
||||
}
|
||||
field(DOL,DBF_INLINK) {
|
||||
prompt("Desired Output Loc")
|
||||
prompt("Desired Output Link")
|
||||
promptgroup("40 - Input")
|
||||
interest(1)
|
||||
}
|
||||
@@ -154,6 +192,11 @@ Parameters> for more on the record name (NAME) and description (DESC) fields.
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(OBIT,DBF_LONG) {
|
||||
prompt("Last Bit mask Monitored")
|
||||
special(SPC_NOMOD)
|
||||
interest(3)
|
||||
}
|
||||
field(SHFT,DBF_USHORT) {
|
||||
prompt("Shift")
|
||||
promptgroup("50 - Output")
|
||||
@@ -166,11 +209,13 @@ These parameters are used by the run-time code for processing the mbbo Direct
|
||||
record.
|
||||
|
||||
MASK is used by device support routine to read the hardware register. Record
|
||||
support sets low order NOBT bits. Device support can shift this value.
|
||||
support sets the low order NOBT bits of MASK at initialization, and device
|
||||
support is allowed to shift this value.
|
||||
|
||||
MLST holds the value when the last monitor for value change was triggered.
|
||||
OBIT has a similar role for bits held in the B0-B1F fields.
|
||||
|
||||
=fields NOBT, ORAW, MASK, MLST
|
||||
=fields NOBT, ORAW, MASK, MLST, OBIT
|
||||
|
||||
=head3 Simulation Mode Parameters
|
||||
|
||||
@@ -242,17 +287,21 @@ for more information on simulation mode and its fields.
|
||||
=head3 Alarm Parameters
|
||||
|
||||
The possible alarm conditions for mbboDirect records are the SCAN, READ, and
|
||||
INVALID alarms. The SCAN and READ alarms are not configurable by the user since
|
||||
they are always of MAJOR severity. See L<Alarm Specification> for a complete
|
||||
explanation of Scan and Read alarms.
|
||||
INVALID alarms.
|
||||
|
||||
The IVOA field specifies an action to take when the INVALID alarm is triggered.
|
||||
The IVOA field specifies an action to take when an INVALID alarm is triggered.
|
||||
There are three possible actions: C<<< Continue normally >>>, C<<< Don't drive
|
||||
outputs >>>, or C<<< Set output to IVOV >>>. When C<<< Set output to IVOV >>> is
|
||||
specified and a INVALID alarm is triggered, the record will write the value in
|
||||
the IVOV field to output. See L<Invalid Output Action Fields|dbCommonOutput/Invalid Output Action Fields> for more
|
||||
information. L<Alarm Fields|dbCommonRecord/Alarm Fields> lists the fields related to
|
||||
alarms that are common to all record types.
|
||||
the IVOV field to the output.
|
||||
|
||||
See L<Invalid Output Action Fields|dbCommonOutput/Invalid Output Action Fields>
|
||||
for more information about IVOA and IVOV.
|
||||
|
||||
See L<Alarm Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#alarm-specification>
|
||||
for a complete explanation of record alarms and of the standard fields.
|
||||
L<Alarm Fields|dbCommonRecord/Alarm Fields> lists other fields related
|
||||
to alarms that are common to all record types.
|
||||
|
||||
=fields IVOA, IVOV
|
||||
|
||||
|
||||
@@ -151,7 +151,7 @@ static long init_record(struct dbCommon *pcommon, int pass)
|
||||
epicsUInt32 *pstate_values = &prec->zrvl;
|
||||
int i;
|
||||
|
||||
prec->val = 65535; /* initalize to unknown state */
|
||||
prec->val = 65535; /* initialize to unknown state */
|
||||
for (i = 0; i < 16; i++) {
|
||||
if (*pstate_values == rval) {
|
||||
prec->val = i;
|
||||
@@ -217,7 +217,7 @@ static long process(struct dbCommon *pcommon)
|
||||
convert(prec);
|
||||
|
||||
/* Update the timestamp before writing output values so it
|
||||
* will be uptodate if any downstream records fetch it via TSEL */
|
||||
* will be up to date if any downstream records fetch it via TSEL */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -198,7 +198,7 @@ for more information on simulation mode and its fields.
|
||||
#=write Yes
|
||||
}
|
||||
field(DOL,DBF_INLINK) {
|
||||
prompt("Desired Output Loc")
|
||||
prompt("Desired Output Link")
|
||||
promptgroup("40 - Input")
|
||||
interest(1)
|
||||
}
|
||||
|
||||
@@ -25,7 +25,9 @@ recordtype(printf) {
|
||||
|
||||
The printf record has the standard fields for specifying under what
|
||||
circumstances it will be processed.
|
||||
These fields are listed in L<Scan Fields|dbCommonRecord/Scan Fields>.
|
||||
These fields are described in L<Scan Fields|dbCommonRecord/Scan Fields>.
|
||||
|
||||
=fields SCAN, PHAS, EVNT, PRIO, PINI
|
||||
|
||||
=head3 String Generation Parameters
|
||||
|
||||
@@ -144,7 +146,8 @@ 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.
|
||||
Specification|https://docs.epics-controls.org/en/latest/guides/EPICS_Process_Database_Concepts.html#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
|
||||
|
||||
@@ -79,7 +79,7 @@ for each desired output link. Only those that are defined are used.
|
||||
When the sequence record is processed, it uses a selection algorithm similar to
|
||||
that of the selection record to decide which links to process.The select
|
||||
mechanism field (SELM) has three algorithms to choose from: C<<< All >>>,
|
||||
C<<<Specified >>> or C<<< Mask >>>.
|
||||
C<<< Specified >>> or C<<< Mask >>>.
|
||||
|
||||
=head4 Record fields related to the Selection Algorithm
|
||||
|
||||
@@ -102,24 +102,26 @@ process can be dynamically changed by the record pointed by SELL.
|
||||
|
||||
B<SELN - Link Selection>
|
||||
|
||||
When B<C<SELM = Specified>> this is the index number of the link that will be
|
||||
processed, used in combination with the C<OFFS> field:
|
||||
When B<SELM> has the value C<Specified> the B<SELN> field sets the index number
|
||||
of the link that will be processed, after adding the B<OFFS> field:
|
||||
|
||||
SELN = SELN + OFFS
|
||||
=over
|
||||
|
||||
LNKI<n> where I<n> = C<SELN + OFFS>
|
||||
|
||||
I<(By default, the OFFS is initalized to ZERO)>
|
||||
=back
|
||||
|
||||
When B<C<SELM = Mask>> this field is the bitmask that will be used to determine
|
||||
which links will be processed by the seq record,
|
||||
in combination with the C<SHFT> field:
|
||||
I<(If not set, the OFFS field is ZERO)>
|
||||
|
||||
When B<SELM> has the value C<Mask> the B<SELN> field provides the bitmask that
|
||||
determines which links will be processed, after shifting by B<SHFT> bits:
|
||||
|
||||
if (SHFT >= 0)
|
||||
SELN = SELN << -SHFT
|
||||
bits = SELN >> SHFT
|
||||
else
|
||||
SELN = SELN >> SHFT
|
||||
bits = SELN << -SHFT
|
||||
|
||||
I<(By default, the SHFT is initalized to -1)>
|
||||
I<(If not set, the SHFT field is -1 so bits from SELN are shifted left by 1)>
|
||||
|
||||
=head4 B<Note about SHFT and OFFS fields>
|
||||
|
||||
@@ -131,7 +133,7 @@ The SHFT and OFFS fields were introduced to keep compatibility of old databases
|
||||
that used seq records with links indexed from one.
|
||||
|
||||
B<To use the DO0, DOL0, LNK0, DLY0 fields when SELM = Mask, the SHFT field must
|
||||
be set to ZERO>
|
||||
be explicitly set to ZERO>
|
||||
|
||||
=head4 Selection Algorithms Description
|
||||
|
||||
@@ -208,29 +210,37 @@ Routine process implements the following algorithm:
|
||||
=item 1.
|
||||
|
||||
First, PACT is set to TRUE, and the link selection is fetched. Depending on the
|
||||
selection mechanism, the link selection output links are processed in order from
|
||||
LNK0 to LNKF. When LNKI<x> is processed, the corresponding DLYI<x> value is
|
||||
used to generate a delay via watchdog timer.
|
||||
selection mechanism chosen, the appropriate set of link groups will be
|
||||
processed. If multiple link groups need to be processed they are done in
|
||||
increasing numerical order, from LNK0 to LNKF.
|
||||
|
||||
=item 2.
|
||||
|
||||
After DLYI<x> seconds have expired, the input value is fetched from DOI<x> (if
|
||||
DOLI<x> is constant) or DOLI<x> (if DOLI<x> is a database link or channel
|
||||
access link) and written to LNKI<x>.
|
||||
When LNKI<x> is to be processed, the corresponding DLYI<x> value is first used
|
||||
to generate the requested time delay, using the IOC's Callback subsystem to
|
||||
perform subsequent operations. This means that although PACT remains TRUE, the
|
||||
lockset that the sequence record belongs to will be unlocked for the duration of
|
||||
the delay time (an unlock occurs even when the delay is zero).
|
||||
|
||||
=item 3.
|
||||
|
||||
When all links are completed, an asynchronous completion call back to dbProcess
|
||||
is made (see the Application Developer's Guide for more information on
|
||||
asynchronous processing.)
|
||||
After DLYI<x> seconds have expired, the value in DOI<x> is saved locally and a
|
||||
new value is read into DOI<x> through the link DOLI<x> (if the link is valid).
|
||||
Next the record's timestamp is set, and the value in DOI<x> is written through
|
||||
the LNKI<x> output link. If the value of DOI<x> was changed when it was read in
|
||||
a monitor event is triggered on that field.
|
||||
|
||||
=item 4.
|
||||
|
||||
Then UDF is set to FALSE.
|
||||
If any link groups remain to be processed, the next group is selected and the
|
||||
operations for that group are executed again from step 2 above.
|
||||
|
||||
If the last link group has been processed, UDF is set to FALSE and the record's
|
||||
timestamp is set.
|
||||
|
||||
=item 5.
|
||||
|
||||
Monitors are checked.
|
||||
Monitors are posted on VAL and SELN.
|
||||
|
||||
=item 6.
|
||||
|
||||
@@ -238,12 +248,11 @@ The forward link is scanned, PACT is set FALSE, and the process routine returns.
|
||||
|
||||
=back
|
||||
|
||||
For the delay mechanism to operate properly, the record is processed
|
||||
For the delay mechanism to operate properly, the record is normally processed
|
||||
asynchronously. The only time the record will not be processed asynchronously is
|
||||
when there are no non-NULL output links selected (i.e. when it has nothing to
|
||||
do.) The processing of the links is done via callback tasks at the priority set
|
||||
in the PRIO field in dbCommon (see the Application Developer's Guide for more
|
||||
information on call
|
||||
if it has nothing to do, because no link groups or only empty link groups are
|
||||
selected for processing (groups where both DOLI<x> and LNKI<x> are unset or
|
||||
contain only a constant value).
|
||||
|
||||
=cut
|
||||
|
||||
|
||||
@@ -148,7 +148,7 @@ static long process(struct dbCommon *pcommon)
|
||||
}
|
||||
|
||||
/* Update the timestamp before writing output values so it
|
||||
* will be uptodate if any downstream records fetch it via TSEL */
|
||||
* will be up to date if any downstream records fetch it via TSEL */
|
||||
recGblGetTimeStampSimm(prec, prec->simm, NULL);
|
||||
|
||||
if (prec->nsev < INVALID_ALARM )
|
||||
|
||||
@@ -65,8 +65,8 @@ 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
|
||||
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
|
||||
field's value is obtained from the address specified in the Desired Output
|
||||
Link field (DOL) which can be either a database link or a channel access
|
||||
link.
|
||||
|
||||
DOL can also be a constant, in which case VAL will be initialized to the
|
||||
@@ -80,7 +80,7 @@ cannot be C<<< closed_loop >>>.
|
||||
=cut
|
||||
|
||||
field(DOL,DBF_INLINK) {
|
||||
prompt("Desired Output Loc")
|
||||
prompt("Desired Output Link")
|
||||
promptgroup("40 - Input")
|
||||
interest(1)
|
||||
}
|
||||
|
||||
@@ -139,6 +139,7 @@ static long process(struct dbCommon *pcommon)
|
||||
if (!pact && prec->pact)
|
||||
return 0;
|
||||
|
||||
prec->pact = TRUE;
|
||||
prec->udf = FALSE;
|
||||
recGblGetTimeStampSimm(prec, prec->simm, &prec->siol);
|
||||
|
||||
|
||||
@@ -120,9 +120,18 @@ at run-time.
|
||||
VAL references the array where the waveform 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. It is reset to 0 when the device is rearmed. The BUSY field
|
||||
indicates if the device is armed but has not yet been digitized.
|
||||
The NORD field indicates the number of elements that were read into the array.
|
||||
|
||||
The BUSY field permits asynchronous device support to collect array elements
|
||||
sequentially in multiple read cycles which may call the record's C<process()>
|
||||
method many times before completing a read operation. Such a device would set
|
||||
BUSY to TRUE along with setting PACT at the start of acquisition (it could also
|
||||
set NORD to 0 and use it to keep track of how many elements have been received).
|
||||
After receiving the last element the C<read_wf()> routine would clear BUSY which
|
||||
informs the record's C<process()> method that the read has finished. Note that
|
||||
CA clients that perform gets of the VAL field can see partially filled arrays
|
||||
when this type of device support is used, so the BUSY field is almost never used
|
||||
today.
|
||||
|
||||
=fields VAL, BPTR, NORD, BUSY
|
||||
|
||||
@@ -367,14 +376,14 @@ Other: Error.
|
||||
=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_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 to the number of items in the array.
|
||||
other records and store them in the VAL field. If INP is a constant link, then
|
||||
C<read_wf()> does nothing. In this case, the record can be used to hold a fixed
|
||||
set of data or array values written from elsewhere. If INP is a valid link, the
|
||||
new array value is read from that link. NORD is set to the number of items
|
||||
received.
|
||||
|
||||
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 constant, VAL is set from it in the C<init_record()>
|
||||
routine and NORD is also set at that time.
|
||||
|
||||
=cut
|
||||
|
||||
|
||||
@@ -114,7 +114,8 @@ void lazy_dbd(const std::string& dbd_file) {
|
||||
|
||||
if (verbose)
|
||||
std::cout<<"softIoc_registerRecordDeviceDriver(pdbbase)\n";
|
||||
softIoc_registerRecordDeviceDriver(pdbbase);
|
||||
errIf(softIoc_registerRecordDeviceDriver(pdbbase),
|
||||
"Failed to initialize database");
|
||||
registryFunctionAdd("exit", (REGISTRYFUNCTION) exitSubroutine);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ our @ISA = qw(DBD::Base);
|
||||
use Carp;
|
||||
use strict;
|
||||
|
||||
my $warned;
|
||||
|
||||
sub init {
|
||||
my ($this, $name) = @_;
|
||||
$this->SUPER::init($name, "breakpoint table");
|
||||
@@ -20,6 +22,20 @@ sub init {
|
||||
return $this;
|
||||
}
|
||||
|
||||
# Override, breaktable names don't have to be strict
|
||||
sub identifier {
|
||||
my ($this, $id, $what) = @_;
|
||||
confess "DBD::Breaktable::identifier: $what undefined!"
|
||||
unless defined $id;
|
||||
if ($id !~ m/^$RXname$/) {
|
||||
my @message;
|
||||
push @message, "A $what should contain only letters, digits and these",
|
||||
"special characters: _ - : . [ ] < > ;" unless $warned++;
|
||||
warnContext("Deprecated $what '$id'", @message);
|
||||
}
|
||||
return $id;
|
||||
}
|
||||
|
||||
sub add_point {
|
||||
my ($this, $raw, $eng) = @_;
|
||||
confess "DBD::Breaktable::add_point: Raw value undefined!"
|
||||
|
||||
Reference in New Issue
Block a user