From a05f022e441d97dd008ced666309bf87d65005e4 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 1 Oct 2012 17:38:08 -0500 Subject: [PATCH] Reorganize where the POD should be placed The converter now only handles POD from the root DBD object. However there are commands that pull POD out of named sub-objects. This also adds generating tables from menu choices. --- src/ioc/db/Makefile | 1 + src/ioc/db/menuAlarmSevr.dbd | 15 +- src/std/rec/aiRecord.dbd | 809 +++++++++++++++++++++------------ src/std/rec/subArrayRecord.dbd | 2 +- src/std/rec/waveformRecord.dbd | 34 +- src/tools/dbdToHtml.pl | 138 ++++-- 6 files changed, 660 insertions(+), 339 deletions(-) diff --git a/src/ioc/db/Makefile b/src/ioc/db/Makefile index 8788207fe..b6ac6c0f1 100644 --- a/src/ioc/db/Makefile +++ b/src/ioc/db/Makefile @@ -57,6 +57,7 @@ menuGlobal_DBD += menuSimm.dbd DBDINC += $(basename $(menuGlobal_DBD)) DBDINC += dbCommon +HTMLS += $(patsubst %.dbd,%.html,$(menuGlobal_DBD)) dbCore_SRCS += dbLock.c dbCore_SRCS += dbAccess.c diff --git a/src/ioc/db/menuAlarmSevr.dbd b/src/ioc/db/menuAlarmSevr.dbd index ae6661a9e..8287bf86e 100644 --- a/src/ioc/db/menuAlarmSevr.dbd +++ b/src/ioc/db/menuAlarmSevr.dbd @@ -1,12 +1,21 @@ #************************************************************************* -# Copyright (c) 2002 The University of Chicago, as Operator of Argonne +# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne # National Laboratory. # Copyright (c) 2002 The Regents of the University of California, as # Operator of Los Alamos National Laboratory. -# EPICS BASE Versions 3.13.7 -# and higher are distributed subject to a Software License Agreement found +# EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* + +=head1 Menu menuAlarmSevr + +This menu defines the four possible alarm severities that EPICS records can +exhibit. + +=menu menuAlarmSevr + +=cut + menu(menuAlarmSevr) { choice(menuAlarmSevrNO_ALARM,"NO_ALARM") choice(menuAlarmSevrMINOR,"MINOR") diff --git a/src/std/rec/aiRecord.dbd b/src/std/rec/aiRecord.dbd index cc5171cf4..aa75cd3b6 100644 --- a/src/std/rec/aiRecord.dbd +++ b/src/std/rec/aiRecord.dbd @@ -6,101 +6,138 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* -recordtype(ai) { -=head1 Analog Input (ai) +=head1 Analog Input Record (ai) -This record type is normally used to obtain an analog value from -a hardware input and convert it to engineering units. The record -supports linear and break-point conversion to engineering units, -smoothing, alarm limits, alarm filtering, and graphics and control -limits. +This record type is normally used to obtain an analog value from a hardware +input and convert it to engineering units. +The record supports linear and break-point conversion to engineering units, +smoothing, alarm limits, alarm filtering, and graphics and control limits. =head2 Parameter Fields -The record fields are described below grouped by functionality. +The record-specific fields are described below, grouped by functionality. + +=recordtype ai + +=cut + +recordtype(ai) { =head3 Input Specification -These fields control where (if anywhere) the record reads data from -when it is processed: +These fields control where the record will read data from when it is processed: -=fields INP, DTYP +=fields DTYP, INP -I +The DTYP field selects which device support layer should be responsible for +providing input data to the record. +The ai device support layers provided by EPICS Base are documented in the +L section. +External support modules may provide additional device support for this record +type. +If not set explicitly, the DTYP value defaults to the first device support that +is loaded for the record type, which will usually be the C support +that comes with Base. + +The INP link field contains a database or channel access link or provides +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
for a description of the various hardware +address formats supported. =head3 Units Conversion -These fields control how the raw input value gets converted into +These fields control if and how the raw input value gets converted into engineering units: =fields RVAL, ROFF, ASLO, AOFF, LINR, ESLO, EOFF, EGUL, EGUF -These fields are not used if the device support layer reads its -value in engineering units and puts it directly into the VAL field. +These fields are not used if the device support layer reads its value in +engineering units and puts it directly into the VAL field. +This applies to Soft Channel and Async Soft Channel device support, and is also +fairly common for GPIB and similar high-level device interfaces. -If the device support sets the RVAL field, the LINR field controls -how this gets converted into engineering units and placed in the -VAL field as follows: +If the device support sets the RVAL field, the LINR field controls how this gets +converted into engineering units and placed in the VAL field as follows: =over 4 -=item 1. RVAL is converted to a double and ROFF is added to it +=item 1. -=item 2. If ASLO is non-zero the value is multiplied by ASLO +RVAL is converted to a double and ROFF is added to it. -=item 3. AOFF is added +=item 2. -=item 4. If LINR is C the units conversion is finished -after the above steps +If ASLO is non-zero the value is multiplied by ASLO. -=item 5. If LINR is C or C, the value from step 3 -above is multiplied by ESLO and EOFF is added to complete the units -conversion process +=item 3. -=item 6. Any other value for LINR selects a particular breakpoint -table to be used on the value from step 3 above +AOFF is added. + +=item 4. + +If LINR is C the units conversion is finished after the above +steps. + +=item 5. + +If LINR is C or C, the value from step 3 above is multiplied by +ESLO and EOFF is added to complete the units conversion process. + +=item 6. + +Any other value for LINR selects a particular breakpoint table to be used on the +value from step 3 above. =back -The distinction between the C and C settings for the -LINR field are in how the conversion parameters are calculated: +The distinction between the C and C settings for the LINR field +are in how the conversion parameters are calculated: =over 4 =item * -With C conversion the user must set EGUL and EGUF to the -lowest and highest possible engineering units values respectively -that can be converted by the hardware. The device support knows -the range of the raw data and calculates ESLO and EOFF from them. +With C conversion the user must set EGUL and EGUF to the lowest and +highest possible engineering units values respectively that can be converted by +the hardware. +The device support knows the range of the raw data and calculates ESLO and EOFF +from them. =item * -C conversion requires the user to calculate the appropriate -scaling and offset factors and put them directly in ESLO and EOFF. +C conversion requires the user to calculate the appropriate scaling and +offset factors and put them directly in ESLO and EOFF. =back =head3 Smoothing Filter -This filter is usually only used if the device support sets the RVAL -field and the Units Conversion process is used. Device support that -directly sets the VAL field may implement the filter if desired. +This filter is usually only used if the device support sets the RVAL field and +the Units Conversion process is used. +Device support that directly sets the VAL field may implement the filter if +desired. The filter is controlled with a single parameter field: =fields SMOO -The SMOO field should be set to a number between 0 and 1. If set to -zero the filter is not used (no smoothing), while if set to one the -result is infinite smoothing (the VAL field will never change). The -calculation performed is: +The SMOO field should be set to a number between 0 and 1. +If set to zero the filter is not used (no smoothing), while if set to one the +result is infinite smoothing (the VAL field will never change). +The calculation performed is: - VAL = VAL * SMOO + (1 - SMOO) * New Data +=over 4 + +VAL = VAL * SMOO + (1 - SMOO) * New Data + +=back where C was the result from the Units Conversion above. -This implements a first-order infinite impulse response (IIR) -digital filter with z-plane pole at SMOO. The equivalent -continuous-time filter time constant E is given by +This implements a first-order infinite impulse response (IIR) digital filter +with z-plane pole at SMOO. +The equivalent continuous-time filter time constant E is given by =over 4 @@ -113,15 +150,16 @@ where T is the time between record processing. =head3 Undefined Check If after applying the smoothing filter the VAL field contains a NaN -(Not-a-Number) value, the UDF field is set to indicate that the -record value is undefined, which triggers a C with -severity C. +(Not-a-Number) value, the UDF field is set to a non-zero value, indicating that +the record value is undefined, which will trigger a C with severity +C. =fields UDF =head3 Operator Display Parameters These parameters are used to present meaningful data to the operator. +They do not affect the functioning of the record at all. =over 4 @@ -129,271 +167,464 @@ These parameters are used to present meaningful data to the operator. DESC is a string that is usually used to briefly describe the record. =item * -EGU is a string of up to 16 characters giving the units that the -analog input measures. +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 with which -to display VAL. +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 =fields DESC, EGU, HOPR, LOPR, PREC -=head3 Alarm Parameters +=head3 Alarm Limits -... +The user configures limit alarms by putting numerical values into the HIHI, +HIGH, LOW and LOLO fields, and by setting the associated alarm severity in the +corresponding HHSV, HSV, LSV and LLSV menu fields. +The HYST field controls hysteresis to prevent alarm chattering from an input +signal that is close to one of the limits and suffers from significant readout +noise. +The AFTC field sets the time constant on a low-pass filter that delays the +reporting of limit alarms until the signal has been within the alarm range for +that number of seconds (the default AFTC value of zero retains the previous +behavior). -=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST, AFTC +=fields HIHI, HIGH, LOW, LOLO, HHSV, HSV, LSV, LLSV, HYST, AFTC, LALM + +=head3 Monitor Parameters + +These parameters are used to determine when to send monitors placed on the VAL +field. +The monitors are sent when the current value exceeds the last transmitted value +by the appropriate deadband. +If these fields are set to zero, a monitor will be triggered every time the +value changes; if set to -1, a monitor will be sent every time the record is +processed. +The ADEL field sets the deadband for archive monitors (C events), while +the MDEL field controls value monitors (C events). + +The remaining fields are used by the record at run-time to implement the record +monitoring functionality. + +=fields ADEL, MDEL, ALST, MLST, ORAW =cut - include "dbCommon.dbd" - field(VAL,DBF_DOUBLE) { - prompt("Current EGU Value") - promptgroup(GUI_INPUTS) - asl(ASL0) - pp(TRUE) - } - field(INP,DBF_INLINK) { - prompt("Input Specification") - promptgroup(GUI_INPUTS) - interest(1) - } - field(PREC,DBF_SHORT) { - prompt("Display Precision") - promptgroup(GUI_DISPLAY) - interest(1) + include "dbCommon.dbd" + field(VAL,DBF_DOUBLE) { + prompt("Current EGU Value") + promptgroup(GUI_INPUTS) + asl(ASL0) + pp(TRUE) + } + field(INP,DBF_INLINK) { + prompt("Input Specification") + promptgroup(GUI_INPUTS) + interest(1) + } + field(PREC,DBF_SHORT) { + prompt("Display Precision") + promptgroup(GUI_DISPLAY) + interest(1) prop(YES) - } - field(LINR,DBF_MENU) { - prompt("Linearization") - promptgroup(GUI_CONVERT) - special(SPC_LINCONV) - pp(TRUE) - interest(1) - menu(menuConvert) - } - field(EGUF,DBF_DOUBLE) { - prompt("Engineer Units Full") - promptgroup(GUI_CONVERT) - special(SPC_LINCONV) - pp(TRUE) - interest(1) - } - field(EGUL,DBF_DOUBLE) { - prompt("Engineer Units Low") - promptgroup(GUI_CONVERT) - special(SPC_LINCONV) - pp(TRUE) - interest(1) - } - field(EGU,DBF_STRING) { - prompt("Engineering Units") - promptgroup(GUI_DISPLAY) - interest(1) - size(16) + } + field(LINR,DBF_MENU) { + prompt("Linearization") + promptgroup(GUI_CONVERT) + special(SPC_LINCONV) + pp(TRUE) + interest(1) + menu(menuConvert) + } + field(EGUF,DBF_DOUBLE) { + prompt("Engineer Units Full") + promptgroup(GUI_CONVERT) + special(SPC_LINCONV) + pp(TRUE) + interest(1) + } + field(EGUL,DBF_DOUBLE) { + prompt("Engineer Units Low") + promptgroup(GUI_CONVERT) + special(SPC_LINCONV) + pp(TRUE) + interest(1) + } + field(EGU,DBF_STRING) { + prompt("Engineering Units") + promptgroup(GUI_DISPLAY) + interest(1) + size(16) prop(YES) - } - field(HOPR,DBF_DOUBLE) { - prompt("High Operating Range") - promptgroup(GUI_DISPLAY) - interest(1) + } + field(HOPR,DBF_DOUBLE) { + prompt("High Operating Range") + promptgroup(GUI_DISPLAY) + interest(1) prop(YES) - } - field(LOPR,DBF_DOUBLE) { - prompt("Low Operating Range") - promptgroup(GUI_DISPLAY) - interest(1) + } + field(LOPR,DBF_DOUBLE) { + prompt("Low Operating Range") + promptgroup(GUI_DISPLAY) + interest(1) prop(YES) - } - field(AOFF,DBF_DOUBLE) { - prompt("Adjustment Offset") - promptgroup(GUI_CONVERT) - pp(TRUE) - interest(1) - } - field(ASLO,DBF_DOUBLE) { - prompt("Adjustment Slope") - promptgroup(GUI_CONVERT) - pp(TRUE) - interest(1) - initial("1") - } - field(SMOO,DBF_DOUBLE) { - prompt("Smoothing") - promptgroup(GUI_CONVERT) - interest(1) - } - field(HIHI,DBF_DOUBLE) { - prompt("Hihi Alarm Limit") - promptgroup(GUI_ALARMS) - pp(TRUE) - interest(1) + } + field(AOFF,DBF_DOUBLE) { + prompt("Adjustment Offset") + promptgroup(GUI_CONVERT) + pp(TRUE) + interest(1) + } + field(ASLO,DBF_DOUBLE) { + prompt("Adjustment Slope") + promptgroup(GUI_CONVERT) + pp(TRUE) + interest(1) + initial("1") + } + field(SMOO,DBF_DOUBLE) { + prompt("Smoothing") + promptgroup(GUI_CONVERT) + interest(1) + } + field(HIHI,DBF_DOUBLE) { + prompt("Hihi Alarm Limit") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) prop(YES) - } - field(LOLO,DBF_DOUBLE) { - prompt("Lolo Alarm Limit") - promptgroup(GUI_ALARMS) - pp(TRUE) - interest(1) + } + field(LOLO,DBF_DOUBLE) { + prompt("Lolo Alarm Limit") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) prop(YES) - } - field(HIGH,DBF_DOUBLE) { - prompt("High Alarm Limit") - promptgroup(GUI_ALARMS) - pp(TRUE) - interest(1) + } + field(HIGH,DBF_DOUBLE) { + prompt("High Alarm Limit") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) prop(YES) - } - field(LOW,DBF_DOUBLE) { - prompt("Low Alarm Limit") - promptgroup(GUI_ALARMS) - pp(TRUE) - interest(1) + } + field(LOW,DBF_DOUBLE) { + prompt("Low Alarm Limit") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) prop(YES) - } - field(HHSV,DBF_MENU) { - prompt("Hihi Severity") - promptgroup(GUI_ALARMS) - pp(TRUE) - interest(1) + } + field(HHSV,DBF_MENU) { + prompt("Hihi Severity") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) prop(YES) - menu(menuAlarmSevr) - } - field(LLSV,DBF_MENU) { - prompt("Lolo Severity") - promptgroup(GUI_ALARMS) - pp(TRUE) - interest(1) + menu(menuAlarmSevr) + } + field(LLSV,DBF_MENU) { + prompt("Lolo Severity") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) prop(YES) - menu(menuAlarmSevr) - } - field(HSV,DBF_MENU) { - prompt("High Severity") - promptgroup(GUI_ALARMS) - pp(TRUE) - interest(1) + menu(menuAlarmSevr) + } + field(HSV,DBF_MENU) { + prompt("High Severity") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) prop(YES) - menu(menuAlarmSevr) - } - field(LSV,DBF_MENU) { - prompt("Low Severity") - promptgroup(GUI_ALARMS) - pp(TRUE) - interest(1) + menu(menuAlarmSevr) + } + field(LSV,DBF_MENU) { + prompt("Low Severity") + promptgroup(GUI_ALARMS) + pp(TRUE) + interest(1) prop(YES) - menu(menuAlarmSevr) - } - field(HYST,DBF_DOUBLE) { - prompt("Alarm Deadband") - promptgroup(GUI_ALARMS) - interest(1) - } - field(AFTC,DBF_DOUBLE) { - prompt("Alarm Filter Time Constant") - promptgroup(GUI_ALARMS) - interest(1) - } - field(ADEL,DBF_DOUBLE) { - prompt("Archive Deadband") - promptgroup(GUI_DISPLAY) - interest(1) - } - field(MDEL,DBF_DOUBLE) { - prompt("Monitor Deadband") - promptgroup(GUI_DISPLAY) - interest(1) - } - field(LALM,DBF_DOUBLE) { - prompt("Last Value Alarmed") - special(SPC_NOMOD) - interest(3) - } - field(AFVL,DBF_DOUBLE) { - prompt("Alarm Filter Value") - special(SPC_NOMOD) - interest(3) - } - field(ALST,DBF_DOUBLE) { - prompt("Last Value Archived") - special(SPC_NOMOD) - interest(3) - } - field(MLST,DBF_DOUBLE) { - prompt("Last Val Monitored") - special(SPC_NOMOD) - interest(3) - } - field(ESLO,DBF_DOUBLE) { - prompt("Raw to EGU Slope") - promptgroup(GUI_CONVERT) - pp(TRUE) - interest(2) - initial("1") - } - field(EOFF,DBF_DOUBLE) { - prompt("Raw to EGU Offset") - promptgroup(GUI_CONVERT) - pp(TRUE) - interest(2) - } - field(ROFF,DBF_LONG) { - prompt("Raw Offset, obsolete") - pp(TRUE) - interest(2) - } - field(PBRK,DBF_NOACCESS) { - prompt("Ptrto brkTable") - special(SPC_NOMOD) - interest(4) - extra("void * pbrk") - } - field(INIT,DBF_SHORT) { - prompt("Initialized?") - special(SPC_NOMOD) - interest(3) - } - field(LBRK,DBF_SHORT) { - prompt("LastBreak Point") - special(SPC_NOMOD) - interest(3) - } - field(RVAL,DBF_LONG) { - prompt("Current Raw Value") - pp(TRUE) - } - field(ORAW,DBF_LONG) { - prompt("Previous Raw Value") - special(SPC_NOMOD) - interest(3) - } - field(SIOL,DBF_INLINK) { - prompt("Sim Input Specifctn") - promptgroup(GUI_INPUTS) - interest(1) - } - field(SVAL,DBF_DOUBLE) { - prompt("Simulation Value") - } - field(SIML,DBF_INLINK) { - prompt("Sim Mode Location") - promptgroup(GUI_INPUTS) - interest(1) - } - field(SIMM,DBF_MENU) { - prompt("Simulation Mode") - interest(1) - menu(menuSimm) - } - field(SIMS,DBF_MENU) { - prompt("Sim mode Alarm Svrty") - promptgroup(GUI_INPUTS) - interest(2) - menu(menuAlarmSevr) - } + menu(menuAlarmSevr) + } + field(HYST,DBF_DOUBLE) { + prompt("Alarm Deadband") + promptgroup(GUI_ALARMS) + interest(1) + } + field(AFTC,DBF_DOUBLE) { + prompt("Alarm Filter Time Constant") + promptgroup(GUI_ALARMS) + interest(1) + } + field(ADEL,DBF_DOUBLE) { + prompt("Archive Deadband") + promptgroup(GUI_DISPLAY) + interest(1) + } + field(MDEL,DBF_DOUBLE) { + prompt("Monitor Deadband") + promptgroup(GUI_DISPLAY) + interest(1) + } + field(LALM,DBF_DOUBLE) { + prompt("Last Value Alarmed") + special(SPC_NOMOD) + interest(3) + } + field(AFVL,DBF_DOUBLE) { + prompt("Alarm Filter Value") + special(SPC_NOMOD) + interest(3) + } + field(ALST,DBF_DOUBLE) { + prompt("Last Value Archived") + special(SPC_NOMOD) + interest(3) + } + field(MLST,DBF_DOUBLE) { + prompt("Last Val Monitored") + special(SPC_NOMOD) + interest(3) + } + field(ESLO,DBF_DOUBLE) { + prompt("Raw to EGU Slope") + promptgroup(GUI_CONVERT) + pp(TRUE) + interest(2) + initial("1") + } + field(EOFF,DBF_DOUBLE) { + prompt("Raw to EGU Offset") + promptgroup(GUI_CONVERT) + pp(TRUE) + interest(2) + } + field(ROFF,DBF_LONG) { + prompt("Raw Offset, obsolete") + pp(TRUE) + interest(2) + } + field(PBRK,DBF_NOACCESS) { + prompt("Ptrto brkTable") + special(SPC_NOMOD) + interest(4) + extra("void * pbrk") + } + field(INIT,DBF_SHORT) { + prompt("Initialized?") + special(SPC_NOMOD) + interest(3) + } + field(LBRK,DBF_SHORT) { + prompt("LastBreak Point") + special(SPC_NOMOD) + interest(3) + } + field(RVAL,DBF_LONG) { + prompt("Current Raw Value") + pp(TRUE) + } + field(ORAW,DBF_LONG) { + prompt("Previous Raw Value") + special(SPC_NOMOD) + interest(3) + } + +=head3 Simulation Mode + +The record provides several fields to support simulation of absent hardware. +If the SIML field is set it is used to read a value into the SIMM field, which +controls whether simulation is used or not: + +=over 4 + +=item * +SIMM must be zero (C) for the record to request a value from the device +support. + +=item * +If SIMM is C and the SIOL link field is set, a simlated value in +engineering units is read using the link into the SVAL field, from where it will +subsequently be copied into the VAL field. + +=item * +If SIMM is C the SIOL link is still read into SVAL, but is then truncated +and copied into the RVAL field. +The L process described above is then followed to transform +the simulated raw value into engineering units. + +=back + +The SIMS field can be set to give the record an alarm severity while it is in +simulation mode. + +=fields SIML, SIMM, SIOL, SVAL, SIMS + +=cut + + field(SIOL,DBF_INLINK) { + prompt("Sim. Input Specification") + promptgroup(GUI_INPUTS) + interest(1) + } + field(SVAL,DBF_DOUBLE) { + prompt("Simulation Value") + } + field(SIML,DBF_INLINK) { + prompt("Sim. Mode Location") + promptgroup(GUI_INPUTS) + interest(1) + } + field(SIMM,DBF_MENU) { + prompt("Simulation Mode") + interest(1) + menu(menuSimm) + } + field(SIMS,DBF_MENU) { + prompt("Simulation Mode Severity") + promptgroup(GUI_INPUTS) + interest(2) + menu(menuAlarmSevr) + } } + +=head2 Device Support Interface + +The record requires device support to provide an entry table (dset) which +defines the following members: + + typedef struct { + long number; + long (*report)(int level); + long (*init)(int after); + long (*init_record)(aiRecord *prec); + long (*get_ioint_info)(int cmd, aiRecord *prec, IOSCANPVT *piosl); + long (*read_ai)(aiRecord *prec); + long (*special_linconv)(aiRecord *prec, int after); + } aidset; + +The module must set C to at least 6, and provide a pointer to its +C routine; the other function pointers may be C if their +associated functionality is not required for this support layer. +Most device supports also provide an C routine to configure the +record instance and connect it to the hardware or driver support layer, and if +using the record's L features they set C +as well. +The individual routines are described below. + +=head3 Device Support Routines + +=head4 long report(int level) + +This optional routine is called by the IOC command C and is passed the +report level that was requested by the user. +It should print a report on the state of the device support to stdout. +The C parameter may be used to output increasingly more detailed +information at higher levels, or to select different types of information with +different levels. +Level zero should print no more than a small summary. + +=head4 long init(int after) + +This optional routine is called twice at IOC initialization time. +The first call happens before any of the C calls are made, with +the integer parameter C set to 0. +The second call happens after all of the C calls have been made, +with C set to 1. + +=head4 long init_record(aiRecord *prec) + +This optional routine is called by the record initialization code for each ai +record instance that has its DTYP field set to use this device support. +It is normally used to check that the INP address is the expected type and that +it points to a valid device; to allocate any record-specific buffer space and +other memory; and to connect any communication channels needed for the +C routine to work properly. + +If the record type's unit conversion features are used, the C +routine should calculate appropriate values for the ESLO and EOFF fields from +the EGUL and EGUF field values. +This calculation only has to be performed if the record's LINR field is set to +C, but it is not necessary to check that condition first. +This same calculation takes place in the C routine, so the +implementation can usually just call that routine to perform the task. + +=head4 long get_ioint_info(int cmd, aiRecord *prec, IOSCANPVT *piosl) + +This optional routine is called whenever the record's SCAN field is being +changed to or from the value C to find out which I/O Interrupt Scan +list the record should be added to or deleted from. +If this routine is not provided, it will not be possible to set the SCAN field +to the value C at all. + +The C parameter is zero when the record is being added to the scan list, +and one when it is being removed from the list. +The routine must determine which interrupt source the record should be connected +to, which it indicates by the scan list that it points the location at C<*piosl> +to before returning. +It can prevent the SCAN field from being changed at all by returning a non-zero +value to its caller. + +In most cases the device support will create the I/O Interrupt Scan lists that +it returns for itself, by calling C once for +each separate interrupt source. +That API allocates memory and inializes the list, then passes back a pointer to +the new list in the location at C<*piosl>. +When the device support receives notification that the interrupt has occurred, +it announces that to the IOC by calling C +which will arrange for the appropriate records to be processed in a suitable +thread. +The C routine is safe to call from an interrupt service routine +on embedded architectures (vxWorks and RTEMS). + +=head4 long read_ai(aiRecord *prec) + +This essential routine is called whenever the record is processed, and is +responsible for performing (or at least initiating) a read operation for the +addressed device and (eventually) returning its value to the record. + +... PACT and asynchronous processing ... + +... return value ... + +=head4 long special_linconv(aiRecord *prec, int after) + +This optional routine should be provided if the record type's unit conversion +features are used by the device support's C routine returning a +status value of zero. +It is called by the record code whenever any of the the fields LINR, EGUL or +EGUF are modified and LINR has the value C. +The routine must calculate and set the fields EOFF and ESLO appropriately based +on the new values of EGUL and EGUF. + +These calculations can be expressed in terms of the minimum and maximum raw +values that the C routine can put in the RVAL field. +When RVAL is set to I the VAL field will be set to EGUF, and when RVAL +is set to I the VAL field will become EGUL. +The fomulae to use are: + +=over 4 + +EOFF = (I * EGUL E I * EGUF) / +(I E I) + +ESLO = (EGUF E EGUL) / (I E I) + +=back + +Note that the record support sets EOFF to EGUL before calling this routine, +which is a very common case (I is zero). + +=head3 Extended Device Support + +... + +=cut diff --git a/src/std/rec/subArrayRecord.dbd b/src/std/rec/subArrayRecord.dbd index 92c221c59..4a0bfe0c6 100644 --- a/src/std/rec/subArrayRecord.dbd +++ b/src/std/rec/subArrayRecord.dbd @@ -15,7 +15,7 @@ recordtype(subArray) { special(SPC_DBADDR) pp(TRUE) extra("void * val") - #=type See FTVL + #=type Set by FTVL #=read Yes #=write Yes } diff --git a/src/std/rec/waveformRecord.dbd b/src/std/rec/waveformRecord.dbd index 32394971e..143855c22 100644 --- a/src/std/rec/waveformRecord.dbd +++ b/src/std/rec/waveformRecord.dbd @@ -6,11 +6,28 @@ # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. #************************************************************************* + +=head1 Waveform Record (waveform) + +... + +=recordtype waveform + +... + +=cut + menu(waveformPOST) { - choice(waveformPOST_Always,"Always") - choice(waveformPOST_OnChange,"On Change") + choice(waveformPOST_Always,"Always") + choice(waveformPOST_OnChange,"On Change") } + recordtype(waveform) { + +=fields VAL, FTVL, MPST, APST + +=cut + include "dbCommon.dbd" field(VAL,DBF_NOACCESS) { prompt("Value") @@ -18,7 +35,7 @@ recordtype(waveform) { special(SPC_DBADDR) pp(TRUE) extra("void * val") - #=type See FTVL + #=type Set by FTVL #=read Yes #=write Yes } @@ -107,6 +124,17 @@ recordtype(waveform) { interest(2) menu(menuAlarmSevr) } + +=head3 Menu waveformPOST + +... + +=menu waveformPOST + +... + +=cut + field(MPST,DBF_MENU) { prompt("Post Value Monitors") promptgroup(GUI_DISPLAY) diff --git a/src/tools/dbdToHtml.pl b/src/tools/dbdToHtml.pl index 42779a008..1678d3506 100644 --- a/src/tools/dbdToHtml.pl +++ b/src/tools/dbdToHtml.pl @@ -1,6 +1,6 @@ #!/usr/bin/perl #************************************************************************* -# Copyright (c) 2010 UChicago Argonne LLC, as Operator of Argonne +# Copyright (c) 2012 UChicago Argonne LLC, as Operator of Argonne # National Laboratory. # EPICS BASE is distributed subject to a Software License Agreement found # in file LICENSE that is included with this distribution. @@ -8,6 +8,8 @@ # $Id$ +use strict; + use FindBin qw($Bin); use lib "$Bin/../../lib/perl"; @@ -19,6 +21,8 @@ use EPICS::Readfile; use Pod::Simple::HTML; my $tool = 'dbdToHtml'; + +use vars qw($opt_D @opt_I $opt_o); getopts('DI@o:') or die "Usage: $tool [-D] [-I dir] [-o file.html] file.dbd\n"; @@ -44,39 +48,31 @@ if ($opt_D) { # Output dependencies only exit 0; } -open my $out, '>', $opt_o or die "Can't create $opt_o: $!\n"; +open my $out, '>', $opt_o or + die "Can't create $opt_o: $!\n"; -# Grab the Pod text from the root DBD object -my @pod = $dbd->pod; - -my $rtypes = $dbd->recordtypes; - -# Append the processed Pod text from any record types defined -while (my ($rn, $rtyp) = each %{$rtypes}) { - foreach my $_ ($rtyp->pod) { - # Handle our 'fields' Pod directive - if (m/^=fields (.*)/) { - my @names = split /\s*,\s*/, $1; - # Look up every named field - my @fields = map { - my $field = $rtyp->field($_); - print STDERR "Unknown field name '$_' in $infile POD\n" unless $field; - $field; - } @names; - my $html; - # Generate a HTML table row for each field - foreach $field (@fields) { - $html .= $field->htmlTableRow if $field; - } - # Add the complete table - push @pod, podTable($html); - } - else { - # Add other Pod text - push @pod, $_; - } +# Parse the Pod text from the root DBD object +my @pod = map { + # Handle a 'recordtype' Pod directive + if (m/^ =recordtype \s+ (.*)/x) { + my $rn = $1; + my $rtyp = $dbd->recordtype($rn); + die "Unknown recordtype '$rn' in $infile POD directive\n" + unless $rtyp; + rtypeToPod($rtyp, $dbd); } -} + # Handle a 'menu' Pod directive + elsif (m/^ =menu \s+ (.*)/x) { + my $mn = $1; + my $menu = $dbd->menu($mn); + die "Unknown menu '$mn' in $infile POD directive\n" + unless $menu; + menuToPod($menu); + } + else { + $_; + } +} $dbd->pod; my $podHtml = Pod::Simple::HTML->new(); $podHtml->html_css('style.css'); @@ -90,18 +86,70 @@ print $out $html; close $out; -sub podTable { - my $content = shift; - return ("=begin html\n", "\n", +sub menuToPod { + my ($menu) = @_; + my $index = 0; + return "=begin html\n", "\n", "
\n", - "", - "\n", - $content, "
FieldSummaryTypeDCTDefaultReadWriteCA PP
\n", - "\n", "=end html\n"); + "IndexIdentifierChoice String\n", + "\n", + map({choiceTableRow($_, $index++)} $menu->choices), + "\n", + "\n", "=end html\n"; } -sub DBD::Recfield::htmlTableRow { - my $fld = shift; +sub choiceTableRow { + my ($ch, $index) = @_; + my ($id, $name) = @{$ch}; + return '', + $index, + '', + $id, + '', + $name, + "\n"; +} + +sub rtypeToPod { + my ($rtyp, $dbd) = @_; + return map { + # Handle a 'fields' Pod directive + if (m/^ =fields \s+ (.*)/x) { + my @names = split /\s*,\s*/, $1; + # Look up the named fields + my @fields = map { + my $field = $rtyp->field($_); + die "Unknown field name '$_' in $infile POD\n" + unless $field; + $field; + } @names; + # Generate Pod for the table + "=begin html\n", "\n", + "
\n", + "", + "", + "\n", + map({fieldTableRow($_, $dbd)} @fields), + "
FieldSummaryTypeDCTDefaultReadWriteCA PP
\n", + "\n", "=end html\n"; + } + # Handle a 'menu' Pod directive + elsif (m/^ =menu \s+ (.*)/x) { + my $mn = $1; + my $menu = $dbd->menu($mn); + die "Unknown menu '$mn' in $infile POD directive\n" + unless $menu; + menuToPod($menu); + } + else { + # Raw text line + $_; + } + } $rtyp->pod; +} + +sub fieldTableRow { + my ($fld, $dbd) = @_; my $html = ''; $html .= $fld->name; $html .= ''; @@ -111,8 +159,12 @@ sub DBD::Recfield::htmlTableRow { $html .= $type; $html .= ' [' . $fld->attribute('size') . ']' if $type eq 'STRING'; - $html .= ' (' . $fld->attribute('menu') . ')' - if $type eq 'MENU'; + if ($type eq 'MENU') { + my $mn = $fld->attribute('menu'); + my $menu = $dbd->menu($mn); + my $url = $menu ? "#Menu_$mn" : "${mn}.html"; + $html .= " ($mn)"; + } $html .= ''; $html .= $fld->attribute('promptgroup') ? 'Yes' : 'No'; $html .= '';