diff --git a/Makefile b/Makefile index 8e7762c..367c1d3 100644 --- a/Makefile +++ b/Makefile @@ -13,6 +13,7 @@ REQUIRED+=stream # DB files to include in the release TEMPLATES += db/channels.db +TEMPLATES += db/time.db TEMPLATES += db/gating_channels.db TEMPLATES += db/daq_4ch.db TEMPLATES += db/daq_8ch.db diff --git a/db/channels.db b/db/channels.db index 892d237..df3b66b 100644 --- a/db/channels.db +++ b/db/channels.db @@ -8,38 +8,206 @@ # CHANNEL - the number associated with the measurment channel ################################################################################ -# Status Variables +# Channel Specific -# Trigger a change in status as clearing -record(bo, "$(INSTR)$(NAME):T$(CHANNEL)") +# Updated by READALL, at POLL_FREQ frequency +record(int64in, "$(INSTR)$(NAME):CH$(CHANNEL)") { - field(DESC, "Trigger Clearing Status") - field(VAL, 1) - field(OUT, "$(INSTR)$(NAME):S$(CHANNEL) PP") + field(DESC, "DAQ CH$(CHANNEL) Counts") + field(EGU, "cts") + field(FLNK, "$(INSTR)$(NAME):CH$(CHANNEL)_POLL") } -# Trigger a change in status as value returned to 0 -record(seq, "$(INSTR)$(NAME):O$(CHANNEL)") +record(ai, "$(INSTR)$(NAME):CH$(CHANNEL)_RATE") { - field(DESC, "Trigger Returned to 0 Status") - field(LNK0, "$(INSTR)$(NAME):S$(CHANNEL) PP") - field(DO0, 0) - field(SELM, "Specified") - field(SELL, "$(INSTR)$(NAME):M$(CHANNEL).VAL") + field(DESC, "Rate of DAQ CH$(CHANNEL)") + field(INP, "@$(PROTO) readRate($(INSTR)$(NAME):, $(CHANNEL)) $(ASYN_PORT)") + field(DTYP, "stream") + field(EGU, "cts/sec") + field(SCAN, "1 second") } -# Current Status of Channel, i.e. is it ready to count? -record(bi, "$(INSTR)$(NAME):S$(CHANNEL)") +record(ao, "$(INSTR)$(NAME):CH$(CHANNEL)_THRESH") { - field(DESC, "Channel Status") - field(VAL, 0) - field(ZNAM, "OK") - field(ONAM, "CLEARING") + # Rate for this channel only applies, if + # $(INSTR)$(NAME):THRESHOLD-MONITOR == $(CHANNEL) + field(DESC, "Sets min rate for counting to proceed") + field(OMSL, "supervisory") + field(OROC, "0") + field(OUT, "@$(PROTO) setMinRate($(INSTR)$(NAME):, $(CHANNEL)) $(ASYN_PORT)") + field(DTYP, "stream") + field(EGU, "cts/sec") } ################################################################################ -# Count Commands +# Poll Loop +record(dfanout, "$(INSTR)$(NAME):CH$(CHANNEL)_POLL") +{ + field(DESC, "Channel $(CHANNEL) poll sequence") + field(SELM, "All") + field(OMSL, "closed_loop") + field(DOL, 1) + field(OUTA, "$(INSTR)$(NAME):CH$(CHANNEL)_HWCS.PROC") + field(OUTB, "$(INSTR)$(NAME):CH$(CHANNEL)_STS_RAW.PROC") + field(OUTC, "$(INSTR)$(NAME):CH$(CHANNEL)_REACHED.PROC") +} + +################################################################################ +# Clearing Channel Counts + +record(bi, "$(INSTR)$(NAME):CH$(CHANNEL)_CLEARED") +{ + field(DESC, "are hw counts being cleared") + field(VAL, 0) + field(ZNAM, "Cleared") + field(ONAM, "Clearing") +} + +# Trigger a change in status as value returned to 0 +record(seq, "$(INSTR)$(NAME):CH$(CHANNEL)_HWCS") +{ + field(DESC, "Trigger returned to 0 status") + field(SELM, "Specified") + field(SELL, "$(INSTR)$(NAME):CH$(CHANNEL).VAL") + field(DO0, 0) + field(LNK0, "$(INSTR)$(NAME):CH$(CHANNEL)_CLEARED PP") +} + +record(dfanout, "$(INSTR)$(NAME):CH$(CHANNEL)_CLEAR") +{ + field(DESC, "Clears the current channel count") + field(SELM, "All") + field(OMSL, "closed_loop") + field(DOL, 1) + field(OUTA, "$(INSTR)$(NAME):CH$(CHANNEL)_CLEARED PP PP") + field(OUTB, "$(INSTR)$(NAME):CH$(CHANNEL)_HWC.PROC PP") +} + +record(longout, "$(INSTR)$(NAME):CH$(CHANNEL)_HWC") +{ + field(DESC, "Clear in Hardware") + field(DTYP, "stream") + field(OMSL, "closed_loop") + field(DOL, "$(INSTR)$(NAME):CH$(CHANNEL)_BM NPP") + field(OUT, "@$(PROTO) clearChannel($(INSTR)$(NAME):) $(ASYN_PORT)") +} + +################################################################################ +# Determining Channel Status + +record(calc, "$(INSTR)$(NAME):CH$(CHANNEL)_STS_RAW") +{ + field(DESC, "Raw Channel Status") + field(INPA, "$(INSTR)$(NAME):STATUS NPP") + field(INPB, "$(INSTR)$(NAME):CH$(CHANNEL)_CLEARED NPP") + field(INPC, "$(INSTR)$(NAME):CH$(CHANNEL)_SET NPP") + field(CALC, "A == 1 || B || C") + field(FLNK, "$(INSTR)$(NAME):CH$(CHANNEL)_STS") +} + +# Current Status of Channel, i.e. is it ready for a new operation? +record(mbbi, "$(INSTR)$(NAME):CH$(CHANNEL)_STS") +{ + field(DESC, "Channel Status") + field(INP, "$(INSTR)$(NAME):CH$(CHANNEL)_STS_RAW NPP MS") + field(ZRVL, "0") + field(ZRST, "Idle") + field(ONVL, "1") + field(ONST, "Busy") +} + +################################################################################ +# Channel Preset + +# If set, stop count once preset reached +record(int64in, "$(INSTR)$(NAME):CH$(CHANNEL)_PRESET") +{ + field(DESC, "Monitor Count Preset") + field(VAL, 0) + field(FLNK, "$(INSTR)$(NAME):CH$(CHANNEL)_SETTING") +} + +record(calcout, "$(INSTR)$(NAME):CH$(CHANNEL)_REACHED") +{ + field(DESC, "Stop if preset reached") + field(INPA, "$(INSTR)$(NAME):CH$(CHANNEL) NPP") + field(INPB, "$(INSTR)$(NAME):CH$(CHANNEL)_PRESET NPP") + field(CALC, "B > 0 && A >= B") + field(OOPT, "When Non-zero") + field(OUT, "$(INSTR)$(NAME):STOP.PROC") +} + +################################################################################ +# Setting Channel Preset + +record(bi, "$(INSTR)$(NAME):CH$(CHANNEL)_SET") +{ + field(DESC, "is preset being configured") + field(VAL, 0) + field(ZNAM, "Set") + field(ONAM, "Setting") +} + +record(calcout, "$(INSTR)$(NAME):CH$(CHANNEL)_CHECK_SET") +{ + field(DESC, "Was preset fully configured") + field(SCAN, ".1 second") + field(INPA, "$(INSTR)$(NAME):CH$(CHANNEL)_SET NPP") + field(INPB, "$(INSTR)$(NAME):MONITOR-CHANNEL NPP") + field(INPC, "$(INSTR)$(NAME):MONITOR-CHANNEL_RBV NPP") + field(CALC, "A && ( ($(CHANNEL) # B) || (B = C) )") + field(OOPT, "When Non-zero") + field(DOPT, "Use OCAL") + field(OCAL, "0") + # This is just a delay, as otherwise, Nicos will not see + # the $(INSTR)$(NAME):CH$(CHANNEL)_SET state change + # when not changing which monitor channel the preset + # applies to. Is there a better way? + field(ODLY, .5) + field(OUT, "$(INSTR)$(NAME):CH$(CHANNEL)_SET PP") +} + +record(dfanout, "$(INSTR)$(NAME):CH$(CHANNEL)_SETTING") +{ + field(DESC, "Trigger setting HW preset") + field(SELM, "All") + field(OMSL, "closed_loop") + field(DOL, 1) + field(OUTA, "$(INSTR)$(NAME):CH$(CHANNEL)_SET PP") + field(OUTB, "$(INSTR)$(NAME):CH$(CHANNEL)_IN_HW.PROC PP") +} + +record(calcout, "$(INSTR)$(NAME):CH$(CHANNEL)_IN_HW") +{ + field(DESC, "Possible to configure in HW") + field(INPA, "$(INSTR)$(NAME):PRESET_TYPE NPP") + field(INPB, "$(INSTR)$(NAME):CH$(CHANNEL)_PRESET NPP") + field(INPC, "$(INSTR)$(NAME):MONITOR-CHANNEL.DRVH NPP") + field(CALC, "A=0 && B>0 && $(CHANNEL)<=C") + field(OOPT, "When Non-zero") + field(DOPT, "Use OCAL") + field(OCAL, "1") + field(OUT, "$(INSTR)$(NAME):CH$(CHANNEL)_HW_CONF.PROC") +} + +record(ao, "$(INSTR)$(NAME):CH$(CHANNEL)_HW_CONF") +{ + field(DESC, "Configure in HW") + field(OMSL, "closed_loop") + field(DOL, $(CHANNEL)) + field(OUT, "$(INSTR)$(NAME):MONITOR-CHANNEL PP") + field(FLNK, "$(INSTR)$(NAME):CH$(CHANNEL)_SET_PTYPE PP") +} + +record(ao, "$(INSTR)$(NAME):CH$(CHANNEL)_SET_PTYPE") +{ + field(OMSL, "closed_loop") + field(DOL, 2) + field(OUT, "$(INSTR)$(NAME):PRESET_TYPE PP") +} + +################################################################################ # Unfortunately, clearing the channels is somewhat complicated as a result of # the addition of more channels over time and minimal changes to the underlying interface # @@ -63,49 +231,10 @@ record(bi, "$(INSTR)$(NAME):S$(CHANNEL)") # CC 5 setzt gleichzeitig die Zähler der Channels 1 und 3 zurück # CC 16 ist gleichbedeutend wie CT (Timer zurücksetzen) # CC 511 setzt gleichzeitig die Zähler aller Kanäle (auch des Timers) zurück. - -record(calc, "$(INSTR)$(NAME):BM$(CHANNEL)") +record(calc, "$(INSTR)$(NAME):CH$(CHANNEL)_BM") { field(DESC, "Bit Mask for Channel") field(INPA, $(CHANNEL)) field(CALC, "A > 4 ? 2 ^ A : 2 ^ (A-1)") field(PINI, "YES") } - -record(longout, "$(INSTR)$(NAME):C$(CHANNEL)") -{ - field(DESC, "Clear the current channel count") - field(DTYP, "stream") - field(OMSL, "closed_loop") - field(DOL, "$(INSTR)$(NAME):BM$(CHANNEL) NPP") - field(OUT, "@$(PROTO) clearChannel($(INSTR)$(NAME):) $(ASYN_PORT)") - field(FLNK, "$(INSTR)$(NAME):T$(CHANNEL)") -} - -record(ao,"$(INSTR)$(NAME):THRESH$(CHANNEL)") -{ - field(DESC, "Sets min rate for counting to proceed") - field(OMSL, "supervisory") - field(OROC, "0") - field(OUT, "@$(PROTO) setMinRate($(INSTR)$(NAME):, $(CHANNEL)) $(ASYN_PORT)") - field(DTYP, "stream") -} - -################################################################################ -# Read all monitors values - -record(int64in, "$(INSTR)$(NAME):M$(CHANNEL)") -{ - field(DESC, "DAQ CH$(CHANNEL)") - field(EGU, "cts") - field(FLNK, "$(INSTR)$(NAME):O$(CHANNEL)") -} - -record(ai, "$(INSTR)$(NAME):R$(CHANNEL)") -{ - field(DESC, "Rate of DAQ CH$(CHANNEL)") - field(INP, "@$(PROTO) readRate($(INSTR)$(NAME):, $(CHANNEL)) $(ASYN_PORT)") - field(DTYP, "stream") - field(EGU, "cts/sec") - field(SCAN, "1 second") -} diff --git a/db/daq.proto b/db/daq.proto index 18f9fe0..ff1af45 100644 --- a/db/daq.proto +++ b/db/daq.proto @@ -1,12 +1,12 @@ # # SinqDAQ Protocol File -# +# OutTerminator = CR; InTerminator = CR; -ReadTimeout = 100; -WriteTimeout = 100; -ReplyTimeout = 1000; -LockTimeout = 500; +ReadTimeout = 100; +WriteTimeout = 100; +ReplyTimeout = 1000; +LockTimeout = 500; initialise { out "RMT 1"; # Turn on Remote Control @@ -141,25 +141,25 @@ readRateMonitor{ readAll4 { out "RA"; - in "%(\$1ELAPSED-TIME)f %(\$1M1)d %(\$1M2)d %(\$1M3)d %(\$1M4)d"; + in "%(\$1T)f %(\$1CH1)d %(\$1CH2)d %(\$1CH3)d %(\$1CH4)d"; @mismatch{in "%(\$1MsgTxt)s";} } readAll8 { out "RA"; - in "%(\$1ELAPSED-TIME)f %(\$1M1)d %(\$1M2)d %(\$1M3)d %(\$1M4)d %(\$1M5)d %(\$1M6)d %(\$1M7)d %(\$1M8)d"; + in "%(\$1T)f %(\$1CH1)d %(\$1CH2)d %(\$1CH3)d %(\$1CH4)d %(\$1CH5)d %(\$1CH6)d %(\$1CH7)d %(\$1CH8)d"; @mismatch{in "%(\$1MsgTxt)s";} } readAll10 { out "RA"; - in "%(\$1ELAPSED-TIME)f %(\$1M1)d %(\$1M2)d %(\$1M3)d %(\$1M4)d %(\$1M5)d %(\$1M6)d %(\$1M7)d %(\$1M8)d"; + in "%(\$1T)f %(\$1CH1)d %(\$1CH2)d %(\$1CH3)d %(\$1CH4)d %(\$1CH5)d %(\$1CH6)d %(\$1CH7)d %(\$1CH8)d"; # At least on the sinqtest variant this is broken # requiring channels 9 and 10 to be manually queried out "RC 9"; - in "%(\$1M9)d"; + in "%(\$1CH9)d"; out "RC 10"; - in "%(\$1M10)d"; + in "%(\$1CH10)d"; @mismatch{in "%(\$1MsgTxt)s";} } diff --git a/db/daq_2nd_gen.db b/db/daq_2nd_gen.db index 84c72e5..1cc206d 100644 --- a/db/daq_2nd_gen.db +++ b/db/daq_2nd_gen.db @@ -12,7 +12,7 @@ record(longout, "$(INSTR)$(NAME):MONITOR-CHANNEL") { - field(DESC, "PRESET-COUNT Monitors this channel") + field(DESC, "PRESET_COUNT Monitors this channel") field(DRVL, "1") # Smallest Monitor Channel field(DRVH, "$(CHANNELS)") # Largest Monitor Channel field(DTYP, "stream") @@ -22,15 +22,15 @@ record(longout, "$(INSTR)$(NAME):MONITOR-CHANNEL") record(longin, "$(INSTR)$(NAME):MONITOR-CHANNEL_RBV") { - field(DESC, "PRESET-COUNT Monitors this channel") + field(DESC, "PRESET_COUNT Monitors this channel") field(DTYP, "stream") field(INP, "@$(PROTO) readPresetMonitor($(INSTR)$(NAME):) $(ASYN_PORT)") - field(SCAN, "1 second") - field(FLNK, "$(INSTR)$(NAME):CORRECT-MONITOR-CHANNEL.PROC") + field(SCAN, ".5 second") + field(FLNK, "$(INSTR)$(NAME):CORRECT_MONITOR_CHANNEL.PROC") } # Force back to 1 if it is 0, as 0 has no meaning... -record(seq, "$(INSTR)$(NAME):CORRECT-MONITOR-CHANNEL") +record(seq, "$(INSTR)$(NAME):CORRECT_MONITOR_CHANNEL") { field(SELM, "Specified") field(SELL, "$(INSTR)$(NAME):MONITOR-CHANNEL_RBV.VAL NPP") @@ -38,41 +38,123 @@ record(seq, "$(INSTR)$(NAME):CORRECT-MONITOR-CHANNEL") field(LNK0, "$(INSTR)$(NAME):MONITOR-CHANNEL PP") } -################################################################################ -# Count Commands +record(sel, "$(INSTR)$(NAME):CH_PRESET") +{ + field(DESC, "Monitor threshold to actually use") + field(SELM, "Specified") + field(NVL, "$(INSTR)$(NAME):MONITOR-CHANNEL_RBV.VAL NPP") + # Skip A as it corresponds to 0 + field(INPB, "$(INSTR)$(NAME):CH1_PRESET NPP") + field(INPC, "$(INSTR)$(NAME):CH2_PRESET NPP") + field(INPD, "$(INSTR)$(NAME):CH3_PRESET NPP") + field(INPE, "$(INSTR)$(NAME):CH4_PRESET NPP") + field(INPF, "$(INSTR)$(NAME):CH5_PRESET NPP") + field(INPG, "$(INSTR)$(NAME):CH6_PRESET NPP") + field(INPH, "$(INSTR)$(NAME):CH7_PRESET NPP") + field(INPI, "$(INSTR)$(NAME):CH8_PRESET NPP") + field(INPJ, "$(INSTR)$(NAME):CH9_PRESET NPP") + field(INPK, "$(INSTR)$(NAME):CH10_PRESET NPP") +} +record(dfanout,"$(INSTR)$(NAME):CH_PRESET_CLEAR") +{ + field(DESC, "Clears all channel presets") + field(SELM, "All") + field(OMSL, "closed_loop") + field(DOL, 1) + field(OUTA, "$(INSTR)$(NAME):CH_PRESET_CLEAR1.PROC") + field(OUTB, "$(INSTR)$(NAME):CH_PRESET_CLEAR2.PROC") +} + +record(dfanout,"$(INSTR)$(NAME):CH_PRESET_CLEAR1") +{ + field(SELM, "All") + field(OMSL, "closed_loop") + field(DOL, 0) + field(OUTA, "$(INSTR)$(NAME):CH1_PRESET PP") + field(OUTB, "$(INSTR)$(NAME):CH2_PRESET PP") + field(OUTC, "$(INSTR)$(NAME):CH3_PRESET PP") + field(OUTD, "$(INSTR)$(NAME):CH4_PRESET PP") + field(OUTE, "$(INSTR)$(NAME):CH5_PRESET PP") + field(OUTF, "$(INSTR)$(NAME):CH6_PRESET PP") + field(OUTG, "$(INSTR)$(NAME):CH7_PRESET PP") + field(OUTH, "$(INSTR)$(NAME):CH8_PRESET PP") +} + +record(dfanout,"$(INSTR)$(NAME):CH_PRESET_CLEAR2") +{ + field(SELM, "All") + field(OMSL, "closed_loop") + field(DOL, 0) + field(OUTA, "$(INSTR)$(NAME):CH9_PRESET PP") + field(OUTB, "$(INSTR)$(NAME):CH10_PRESET PP") +} + +record(dfanout,"$(INSTR)$(NAME):CH_CLEAR") +{ + field(DESC, "Clears all channel counts") + field(SELM, "All") + field(OMSL, "closed_loop") + field(DOL, 1) + field(OUTA, "$(INSTR)$(NAME):CH_CLEAR1.PROC PP") + field(OUTB, "$(INSTR)$(NAME):CH_CLEAR2.PROC PP") +} + +record(dfanout,"$(INSTR)$(NAME):CH_CLEAR1") +{ + field(SELM, "All") + field(OMSL, "closed_loop") + field(DOL, 1) + field(OUTA, "$(INSTR)$(NAME):CH1_CLEAR.PROC PP") + field(OUTB, "$(INSTR)$(NAME):CH2_CLEAR.PROC PP") + field(OUTC, "$(INSTR)$(NAME):CH3_CLEAR.PROC PP") + field(OUTD, "$(INSTR)$(NAME):CH4_CLEAR.PROC PP") + field(OUTE, "$(INSTR)$(NAME):CH5_CLEAR.PROC PP") + field(OUTF, "$(INSTR)$(NAME):CH6_CLEAR.PROC PP") + field(OUTG, "$(INSTR)$(NAME):CH7_CLEAR.PROC PP") + field(OUTH, "$(INSTR)$(NAME):CH8_CLEAR.PROC PP") +} + +record(dfanout,"$(INSTR)$(NAME):CH_CLEAR2") +{ + field(SELM, "All") + field(OMSL, "closed_loop") + field(DOL, 1) + field(OUTA, "$(INSTR)$(NAME):CH9_CLEAR.PROC PP") + field(OUTB, "$(INSTR)$(NAME):CH10_CLEAR.PROC PP") +} + +################################################################################ # The hardware stores a separate threshold for each channel, which is somewhat # unintuitive for the user, as only one can actually be made use of at a time. # So, we just write the threshold value to all channels when it is changed. -record(dfanout,"$(INSTR)$(NAME):THRESHOLD-F") +record(dfanout,"$(INSTR)$(NAME):CH_THRESHOLD") +{ + field(DESC, "Sets Channel Lowrate Thresholds") + field(OMSL, "supervisory") + field(SELM, "All") + field(OUTA, "$(INSTR)$(NAME):CH_THRESHOLD1 PP") + field(OUTB, "$(INSTR)$(NAME):CH_THRESHOLD2 PP") +} + +record(dfanout,"$(INSTR)$(NAME):CH_THRESHOLD1") { field(OMSL, "supervisory") field(SELM, "All") - field(OUTA, "$(INSTR)$(NAME):THRESHOLD-F1 PP") - field(OUTB, "$(INSTR)$(NAME):THRESHOLD-F2 PP") + field(OUTA, "$(INSTR)$(NAME):CH1_THRESH PP") + field(OUTB, "$(INSTR)$(NAME):CH2_THRESH PP") + field(OUTC, "$(INSTR)$(NAME):CH3_THRESH PP") + field(OUTD, "$(INSTR)$(NAME):CH4_THRESH PP") + field(OUTE, "$(INSTR)$(NAME):CH5_THRESH PP") + field(OUTF, "$(INSTR)$(NAME):CH6_THRESH PP") + field(OUTG, "$(INSTR)$(NAME):CH7_THRESH PP") + field(OUTH, "$(INSTR)$(NAME):CH8_THRESH PP") } -record(dfanout,"$(INSTR)$(NAME):THRESHOLD-F1") +record(dfanout,"$(INSTR)$(NAME):CH_THRESHOLD2") { field(OMSL, "supervisory") field(SELM, "All") - field(OUTA, "$(INSTR)$(NAME):THRESH1 PP") - field(OUTB, "$(INSTR)$(NAME):THRESH2 PP") - field(OUTC, "$(INSTR)$(NAME):THRESH3 PP") - field(OUTD, "$(INSTR)$(NAME):THRESH4 PP") - field(OUTE, "$(INSTR)$(NAME):THRESH5 PP") - field(OUTF, "$(INSTR)$(NAME):THRESH6 PP") - field(OUTG, "$(INSTR)$(NAME):THRESH7 PP") - field(OUTH, "$(INSTR)$(NAME):THRESH8 PP") + field(OUTA, "$(INSTR)$(NAME):CH9_THRESH PP") + field(OUTB, "$(INSTR)$(NAME):CH10_THRESH PP") } - -record(dfanout,"$(INSTR)$(NAME):THRESHOLD-F2") -{ - field(OMSL, "supervisory") - field(SELM, "All") - field(OUTA, "$(INSTR)$(NAME):THRESH9 PP") - field(OUTB, "$(INSTR)$(NAME):THRESH10 PP") -} - -################################################################################ -# Read all monitors values diff --git a/db/daq_4ch.db b/db/daq_4ch.db index ca34dd5..9a0ce9d 100644 --- a/db/daq_4ch.db +++ b/db/daq_4ch.db @@ -11,7 +11,7 @@ record(longout, "$(INSTR)$(NAME):MONITOR-CHANNEL") { - field(DESC, "PRESET-COUNT Monitors this channel") + field(DESC, "PRESET_COUNT Monitors this channel") field(VAL, 1) field(DRVL, 0) # Smallest Monitor Channel (should really be 1) field(DRVH, 1) # Largest Monitor Channel @@ -20,26 +20,52 @@ record(longout, "$(INSTR)$(NAME):MONITOR-CHANNEL") record(longin, "$(INSTR)$(NAME):MONITOR-CHANNEL_RBV") { - field(DESC, "PRESET-COUNT Monitors this channel") + field(DESC, "PRESET_COUNT Monitors this channel") field(VAL, 1) field(DISP, 1) } -################################################################################ -# Count Commands - -# The hardware stores a separate threshold for each channel, which is somewhat -# unintuitive for the user, as only one can actually be made use of at a time. -# So, we just write the threshold value to all channels when it is changed. -record(dfanout,"$(INSTR)$(NAME):THRESHOLD-F") +record(ai, "$(INSTR)$(NAME):CH_PRESET") { - field(OMSL, "supervisory") + field(DESC, "Monitor threshold to actually use") + field(INP, "$(INSTR)$(NAME):CH1_PRESET NPP") +} + +record(dfanout,"$(INSTR)$(NAME):CH_PRESET_CLEAR") +{ + field(DESC, "Clears all channel presets") field(SELM, "All") - field(OUTA, "$(INSTR)$(NAME):THRESH1 PP") - field(OUTB, "$(INSTR)$(NAME):THRESH2 PP") - field(OUTC, "$(INSTR)$(NAME):THRESH3 PP") - field(OUTD, "$(INSTR)$(NAME):THRESH4 PP") + field(OMSL, "closed_loop") + field(DOL, 0) + field(OUTA, "$(INSTR)$(NAME):CH1_PRESET PP") + field(OUTB, "$(INSTR)$(NAME):CH2_PRESET PP") + field(OUTC, "$(INSTR)$(NAME):CH3_PRESET PP") + field(OUTD, "$(INSTR)$(NAME):CH4_PRESET PP") +} + +record(dfanout,"$(INSTR)$(NAME):CH_CLEAR") +{ + field(DESC, "Clears all channel counts") + field(SELM, "All") + field(OMSL, "closed_loop") + field(DOL, 1) + field(OUTA, "$(INSTR)$(NAME):CH1_CLEAR.PROC PP") + field(OUTB, "$(INSTR)$(NAME):CH2_CLEAR.PROC PP") + field(OUTC, "$(INSTR)$(NAME):CH3_CLEAR.PROC PP") + field(OUTD, "$(INSTR)$(NAME):CH4_CLEAR.PROC PP") } ################################################################################ -# Read all monitors values +# The hardware stores a separate threshold for each channel, which is somewhat +# unintuitive for the user, as only one can actually be made use of at a time. +# So, we just write the threshold value to all channels when it is changed. +record(dfanout,"$(INSTR)$(NAME):CH_THRESHOLD") +{ + field(DESC, "Sets Channel Lowrate Thresholds") + field(OMSL, "supervisory") + field(SELM, "All") + field(OUTA, "$(INSTR)$(NAME):CH1_THRESH PP") + field(OUTB, "$(INSTR)$(NAME):CH2_THRESH PP") + field(OUTC, "$(INSTR)$(NAME):CH3_THRESH PP") + field(OUTD, "$(INSTR)$(NAME):CH4_THRESH PP") +} diff --git a/db/daq_8ch.db b/db/daq_8ch.db index fa49da6..bdb001a 100644 --- a/db/daq_8ch.db +++ b/db/daq_8ch.db @@ -11,7 +11,7 @@ record(longout, "$(INSTR)$(NAME):MONITOR-CHANNEL") { - field(DESC, "PRESET-COUNT Monitors this channel") + field(DESC, "PRESET_COUNT Monitors this channel") field(VAL, 1) field(DRVL, 0) # Smallest Monitor Channel (should really be 1) field(DRVH, 1) # Largest Monitor Channel @@ -20,30 +20,64 @@ record(longout, "$(INSTR)$(NAME):MONITOR-CHANNEL") record(longin, "$(INSTR)$(NAME):MONITOR-CHANNEL_RBV") { - field(DESC, "PRESET-COUNT Monitors this channel") + field(DESC, "PRESET_COUNT Monitors this channel") field(VAL, 1) field(DISP, 1) } -################################################################################ -# Count Commands - -# The hardware stores a separate threshold for each channel, which is somewhat -# unintuitive for the user, as only one can actually be made use of at a time. -# So, we just write the threshold value to all channels when it is changed. -record(dfanout,"$(INSTR)$(NAME):THRESHOLD-F") +record(ai, "$(INSTR)$(NAME):CH_PRESET") { - field(OMSL, "supervisory") + field(DESC, "Monitor threshold to actually use") + field(INP, "$(INSTR)$(NAME):CH1_PRESET NPP") +} + +record(dfanout,"$(INSTR)$(NAME):CH_PRESET_CLEAR") +{ + field(DESC, "Clears all channel presets") field(SELM, "All") - field(OUTA, "$(INSTR)$(NAME):THRESH1 PP") - field(OUTB, "$(INSTR)$(NAME):THRESH2 PP") - field(OUTC, "$(INSTR)$(NAME):THRESH3 PP") - field(OUTD, "$(INSTR)$(NAME):THRESH4 PP") - field(OUTE, "$(INSTR)$(NAME):THRESH5 PP") - field(OUTF, "$(INSTR)$(NAME):THRESH6 PP") - field(OUTG, "$(INSTR)$(NAME):THRESH7 PP") - field(OUTH, "$(INSTR)$(NAME):THRESH8 PP") + field(OMSL, "closed_loop") + field(DOL, 0) + field(OUTA, "$(INSTR)$(NAME):CH1_PRESET PP") + field(OUTB, "$(INSTR)$(NAME):CH2_PRESET PP") + field(OUTC, "$(INSTR)$(NAME):CH3_PRESET PP") + field(OUTD, "$(INSTR)$(NAME):CH4_PRESET PP") + field(OUTE, "$(INSTR)$(NAME):CH5_PRESET PP") + field(OUTF, "$(INSTR)$(NAME):CH6_PRESET PP") + field(OUTG, "$(INSTR)$(NAME):CH7_PRESET PP") + field(OUTH, "$(INSTR)$(NAME):CH8_PRESET PP") +} + +record(dfanout,"$(INSTR)$(NAME):CH_CLEAR") +{ + field(DESC, "Clears all channel counts") + field(SELM, "All") + field(OMSL, "closed_loop") + field(DOL, 1) + field(OUTA, "$(INSTR)$(NAME):CH1_CLEAR.PROC PP") + field(OUTB, "$(INSTR)$(NAME):CH2_CLEAR.PROC PP") + field(OUTC, "$(INSTR)$(NAME):CH3_CLEAR.PROC PP") + field(OUTD, "$(INSTR)$(NAME):CH4_CLEAR.PROC PP") + field(OUTE, "$(INSTR)$(NAME):CH5_CLEAR.PROC PP") + field(OUTF, "$(INSTR)$(NAME):CH6_CLEAR.PROC PP") + field(OUTG, "$(INSTR)$(NAME):CH7_CLEAR.PROC PP") + field(OUTH, "$(INSTR)$(NAME):CH8_CLEAR.PROC PP") } ################################################################################ -# Read all monitors values +# The hardware stores a separate threshold for each channel, which is somewhat +# unintuitive for the user, as only one can actually be made use of at a time. +# So, we just write the threshold value to all channels when it is changed. +record(dfanout,"$(INSTR)$(NAME):CH_THRESHOLD") +{ + field(DESC, "Sets Channel Lowrate Thresholds") + field(OMSL, "supervisory") + field(SELM, "All") + field(OUTA, "$(INSTR)$(NAME):CH1_THRESH PP") + field(OUTB, "$(INSTR)$(NAME):CH2_THRESH PP") + field(OUTC, "$(INSTR)$(NAME):CH3_THRESH PP") + field(OUTD, "$(INSTR)$(NAME):CH4_THRESH PP") + field(OUTE, "$(INSTR)$(NAME):CH5_THRESH PP") + field(OUTF, "$(INSTR)$(NAME):CH6_THRESH PP") + field(OUTG, "$(INSTR)$(NAME):CH7_THRESH PP") + field(OUTH, "$(INSTR)$(NAME):CH8_THRESH PP") +} diff --git a/db/daq_common.db b/db/daq_common.db index f7b68af..4823f71 100644 --- a/db/daq_common.db +++ b/db/daq_common.db @@ -5,6 +5,10 @@ # NAME - the device name, e.g. EL737 # PROTO - Stream device protocol file # ASYN_PORT - Low level Asyn IP Port to EL737 +# POLL_FREQ - Scan string defining main status-loop polling frequency (default .5 second) + +################################################################################ +# Hardware Initialisation # Send initial initialisation commands record(bo, "$(INSTR)$(NAME):INIT-CONF") @@ -22,14 +26,22 @@ record(longout, "$(INSTR)$(NAME):FULL-RESET") field(DTYP, "stream") } -################################################################################ -# Status Variables - -record(stringin, "$(INSTR)$(NAME):MsgTxt") +record(dfanout, "$(INSTR)$(NAME):RESET") { - field(DESC, "Unexpected received response") - field(DTYP, "devDAQStringError") - field(FLNK, "$(INSTR)$(NAME):INVALID-CONFIG") + field(DESC, "Reset internal state") + field(SELM, "All") + field(OMSL, "closed_loop") + field(DOL, "0") + # Internal Count Timer + field(OUTA, "$(INSTR)$(NAME):WAIT_HW PP") + # Time Preset + # field(OUTB, "$(INSTR)$(NAME):T_PRESET PP") + # field(OUTC, "$(INSTR)$(NAME):T_CLEARED PP") + # Monitor Presets + # field(OUTD, "$(INSTR)$(NAME):CH_PRESET_CLEAR PP") + # field(OUTE, "$(INSTR)$(NAME):RESET_MT PP") + # HW Preset Type + # field(OUTF, "$(INSTR)$(NAME):PRESET_TYPE PP") } # We want to recognise the invalid config error message, so that we can rerun @@ -51,37 +63,52 @@ record(seq, "$(INSTR)$(NAME):REINIT-CONF") field(SELL, "$(INSTR)$(NAME):INVALID-CONFIG.VAL") } -# Important! The "$(INSTR)$(NAME):READALL" isn't configure with a SCAN. Instead, -# it must always be triggered after the value of $(INSTR)$(NAME):RAW-STATUS is -# updated, so that it can't be the case that the status changes back from -# counting to idle, without having updated the time and count values. -# -# The status can be interpreted as follows -# -# Bit 0: NC_STAT_P_TIME_C -# Bit 1: NC_STAT_P_COUNT_C -# Bit 2: NC_STAT_RATE_OK_C It appears this should be ignored unless counting -# Bit 3: NC_STAT_PAUSE_C -# -record(mbbiDirect, "$(INSTR)$(NAME):RAW-STATUS") +################################################################################ +# Hardware Box Specific + +record(longin, "$(INSTR)$(NAME):CHANNELS") { - field(DESC, "Raw returned status value") - field(DTYP, "stream") - field(SCAN, ".5 second") - field(INP, "@$(PROTO) readStatus($(INSTR)$(NAME):) $(ASYN_PORT)") - field(FLNK, "$(INSTR)$(NAME):READALL") + field(DESC, "Total Supported Channels") + field(VAL, $(CHANNELS)) + field(DISP, 1) } +record(mbbi, "$(INSTR)$(NAME):PRESET_TYPE") +{ + field(DESC, "Type of Hardware Preset") + field(ZRVL, "0") + field(ZRST, "Unset") + field(ONVL, "1") + field(ONST, "Time") + field(TWVL, "2") + field(TWST, "Monitor") +} + +record(longin, "$(INSTR)$(NAME):WAIT_HW") +{ + field(DESC, "Internal Sent Start Count") +} + +record(stringin, "$(INSTR)$(NAME):MsgTxt") +{ + field(DESC, "Unexpected received response") + field(DTYP, "devDAQStringError") + field(FLNK, "$(INSTR)$(NAME):INVALID-CONFIG") +} + +################################################################################ +# System Status + record(bi, "$(INSTR)$(NAME):COUNTING_TIME") { - field(INP, "$(INSTR)$(NAME):RAW-STATUS.B0 NPP MS") + field(INP, "$(INSTR)$(NAME):RAW_STATUS.B0 NPP MS") field(ZNAM, "DISABLED") field(ONAM, "COUNTING") } record(bi, "$(INSTR)$(NAME):COUNTING_PRESET") { - field(INP, "$(INSTR)$(NAME):RAW-STATUS.B1 NPP MS") + field(INP, "$(INSTR)$(NAME):RAW_STATUS.B1 NPP MS") field(ZNAM, "DISABLED") field(ONAM, "COUNTING") } @@ -89,7 +116,7 @@ record(bi, "$(INSTR)$(NAME):COUNTING_PRESET") record(calc, "$(INSTR)$(NAME):RATE_MAP") { field(DESC, "This bit is not consistent across DAQs") - field(INPA, "$(INSTR)$(NAME):RAW-STATUS.B2 NPP MS") + field(INPA, "$(INSTR)$(NAME):RAW_STATUS.B2 NPP MS") field(CALC, "(A=$(RATE_OKAY_BIT))?0:1") } @@ -102,28 +129,15 @@ record(bi, "$(INSTR)$(NAME):IS_LOWRATE") record(bi, "$(INSTR)$(NAME):IS_PAUSED") { - field(INP, "$(INSTR)$(NAME):RAW-STATUS.B3 NPP MS") + field(INP, "$(INSTR)$(NAME):RAW_STATUS.B3 NPP MS") field(ZNAM, "RUNNING") field(ONAM, "PAUSED") } -record(calc, "$(INSTR)$(NAME):MAP-STATUS") -{ - field(DESC, "Maps Raw Status to State") - field(INPA, "$(INSTR)$(NAME):INVALID-CONFIG NPP MS") - field(INPB, "$(INSTR)$(NAME):RAW-STATUS.UDF NPP MS") # should also be invalid if can't read the status - field(INPC, "$(INSTR)$(NAME):COUNTING_TIME PP MS") - field(INPD, "$(INSTR)$(NAME):COUNTING_PRESET PP MS") - field(INPE, "$(INSTR)$(NAME):IS_LOWRATE PP MS") - field(INPF, "$(INSTR)$(NAME):IS_PAUSED PP MS") - field(CALC, "(A=1||B=1)?4:(F=1)?3:(C=0&&D=0)?0:(E=1)?2:1") - field(FLNK, "$(INSTR)$(NAME):STATUS") -} - record(mbbi, "$(INSTR)$(NAME):STATUS") { field(DESC, "DAQ Status") - field(INP, "$(INSTR)$(NAME):MAP-STATUS NPP MS") + field(INP, "$(INSTR)$(NAME):MAP_STATUS NPP MS") field(ZRVL, "0") field(ZRST, "Idle") field(ONVL, "1") @@ -137,62 +151,18 @@ record(mbbi, "$(INSTR)$(NAME):STATUS") field(FRST, "INVALID") } -record(longin, "$(INSTR)$(NAME):CHANNELS") -{ - field(DESC, "Total Supported Channels") - field(VAL, $(CHANNELS)) - field(DISP, 1) -} - -# Trigger a change in status as clearing -record(bo, "$(INSTR)$(NAME):ETT") -{ - field(DESC, "Trigger Clearing Status") - field(VAL, 1) - field(OUT, "$(INSTR)$(NAME):ETS PP") -} - -# Trigger a change in status as value returned to 0 -record(seq, "$(INSTR)$(NAME):ETO") -{ - field(DESC, "Trigger Returned to 0 Status") - field(LNK0, "$(INSTR)$(NAME):ETS PP") - field(DO0, 0) - field(SELM, "Specified") - field(SELL, "$(INSTR)$(NAME):ELAPSED-TIME.VAL") -} - -# Current Status of Channel, i.e. is it ready to count? -record(bi, "$(INSTR)$(NAME):ETS") -{ - field(DESC, "Channel Status") - field(VAL, 0) - field(ZNAM, "OK") - field(ONAM, "CLEARING") -} - ################################################################################ -# Count Commands +# HW Commands -record(ao,"$(INSTR)$(NAME):PRESET-COUNT") +record(dfanout,"$(INSTR)$(NAME):START") { - field(DESC, "Count until preset reached") - field(DTYP, "stream") - field(OUT, "@$(PROTO) startWithCountPreset$(CHANNELS)($(INSTR)$(NAME):) $(ASYN_PORT)") - field(VAL, 0) - field(PREC, 2) - field(FLNK, "$(INSTR)$(NAME):RAW-STATUS") -} - -record(ao,"$(INSTR)$(NAME):PRESET-TIME") -{ - field(DESC, "Count for specified time") - field(DTYP, "stream") - field(OUT, "@$(PROTO) startWithTimePreset$(CHANNELS)($(INSTR)$(NAME):) $(ASYN_PORT)") - field(VAL, 0) - field(PREC, 2) - field(EGU, "seconds") - field(FLNK, "$(INSTR)$(NAME):RAW-STATUS") + field(DESC, "clear, then trigger count") + field(SELM, "All") + field(OMSL, "closed_loop") + field(DOL, 1) + field(OUTA, "$(INSTR)$(NAME):T_HWC.PROC PP") + field(OUTB, "$(INSTR)$(NAME):CH_CLEAR.PROC PP") + field(FLNK, "$(INSTR)$(NAME):TRIGGER") } record(bo,"$(INSTR)$(NAME):PAUSE") @@ -201,7 +171,7 @@ record(bo,"$(INSTR)$(NAME):PAUSE") field(DTYP, "stream") field(OUT, "@$(PROTO) pauseCount($(INSTR)$(NAME):) $(ASYN_PORT)") field(VAL, "0") - field(FLNK, "$(INSTR)$(NAME):RAW-STATUS") + field(FLNK, "$(INSTR)$(NAME):HW_POLL_SEQ") } record(bo,"$(INSTR)$(NAME):CONTINUE") @@ -210,7 +180,7 @@ record(bo,"$(INSTR)$(NAME):CONTINUE") field(DTYP, "stream") field(OUT, "@$(PROTO) continueCount($(INSTR)$(NAME):) $(ASYN_PORT)") field(VAL, "0") - field(FLNK, "$(INSTR)$(NAME):RAW-STATUS") + field(FLNK, "$(INSTR)$(NAME):HW_POLL_SEQ") } record(longout, "$(INSTR)$(NAME):STOP") @@ -218,9 +188,167 @@ record(longout, "$(INSTR)$(NAME):STOP") field(DESC, "Stop the current counting operation") field(DTYP, "stream") field(OUT, "@$(PROTO) stopCount($(INSTR)$(NAME):) $(ASYN_PORT)") - field(FLNK, "$(INSTR)$(NAME):RAW-STATUS") + field(FLNK, "$(INSTR)$(NAME):HW_POLL_SEQ") } +################################################################################ +# Poll Loop + +record(bo, "$(INSTR)$(NAME):HW_POLL") +{ + field(OMSL, "closed_loop") + field(DOL, 1) + field(SCAN, "$(POLL_FREQ=.5 second)") + field(OUT, "$(INSTR)$(NAME):HW_POLL_SEQ.PROC") +} + +record(dfanout, "$(INSTR)$(NAME):HW_POLL_SEQ") +{ + field(DESC, "Time channel poll sequence") + field(SELM, "All") + field(OMSL, "closed_loop") + field(DOL, 1) + # This order is important, to ensure that the status + # can't change whichout having first updated the time + # and count records to their final values + field(OUTA, "$(INSTR)$(NAME):RAW_STATUS.PROC") + field(OUTB, "$(INSTR)$(NAME):READALL.PROC") + field(OUTC, "$(INSTR)$(NAME):MAP_STATUS.PROC") + field(OUTD, "$(INSTR)$(NAME):STATUS.PROC") + field(OUTE, "$(INSTR)$(NAME):PRESET_TYPE_CLEAR.PROC") + field(OUTF, "$(INSTR)$(NAME):T_PRESET_CLEAR.PROC") + field(OUTG, "$(INSTR)$(NAME):PRESET_CLEAR.PROC") + field(OUTH, "$(INSTR)$(NAME):CLEAR_WAIT_HW.PROC") +} + +# The status can be interpreted as follows +# +# Bit 0: NC_STAT_P_TIME_C +# Bit 1: NC_STAT_P_COUNT_C +# Bit 2: NC_STAT_RATE_OK_C It appears this should be ignored unless counting +# Bit 3: NC_STAT_PAUSE_C +# +record(mbbiDirect, "$(INSTR)$(NAME):RAW_STATUS") +{ + field(DESC, "Raw returned status value") + field(DTYP, "stream") + field(INP, "@$(PROTO) readStatus($(INSTR)$(NAME):) $(ASYN_PORT)") +} + +record(calc, "$(INSTR)$(NAME):MAP_STATUS") +{ + field(DESC, "Maps Raw Status to State") + field(INPA, "$(INSTR)$(NAME):INVALID-CONFIG NPP MS") + field(INPB, "$(INSTR)$(NAME):RAW_STATUS.UDF NPP MS") # should also be invalid if can't read the status + field(INPC, "$(INSTR)$(NAME):COUNTING_TIME PP MS") + field(INPD, "$(INSTR)$(NAME):COUNTING_PRESET PP MS") + field(INPE, "$(INSTR)$(NAME):IS_LOWRATE PP MS") + field(INPF, "$(INSTR)$(NAME):IS_PAUSED PP MS") + field(INPG, "$(INSTR)$(NAME):WAIT_HW NPP MS") + field(CALC, "(A=1||B=1)?4:(F=1)?3:(C=0&&D=0&&G<=0)?0:(E=1)?2:1") +} + +record(calcout, "$(INSTR)$(NAME):PRESET_TYPE_CLEAR") +{ + field(INPA, "$(INSTR)$(NAME):STATUS NPP") + field(CALC, "A") + field(OOPT, "Transition To Zero") + field(DOPT, "Use OCAL") + field(OCAL, "0") + field(OUT, "$(INSTR)$(NAME):PRESET_TYPE PP") +} + +record(calcout, "$(INSTR)$(NAME):T_PRESET_CLEAR") +{ + field(INPA, "$(INSTR)$(NAME):STATUS NPP") + field(CALC, "A") + field(OOPT, "Transition To Zero") + field(DOPT, "Use OCAL") + field(OCAL, "0") + field(OUT, "$(INSTR)$(NAME):T_PRESET PP") +} + +record(calcout, "$(INSTR)$(NAME):PRESET_CLEAR") +{ + field(INPA, "$(INSTR)$(NAME):STATUS NPP") + field(CALC, "A") + field(OOPT, "Transition To Zero") + field(DOPT, "Use OCAL") + field(OCAL, "0") + field(OUT, "$(INSTR)$(NAME):CH_PRESET_CLEAR PP") +} + +record(calcout, "$(INSTR)$(NAME):CLEAR_WAIT_HW") +{ + field(INPA, "$(INSTR)$(NAME):WAIT_HW NPP") + field(INPB, "$(INSTR)$(NAME):COUNTING_TIME NPP MS") + field(INPC, "$(INSTR)$(NAME):COUNTING_PRESET NPP MS") + field(CALC, "A") + field(DOPT, "Use OCAL") + field(OCAL, "(B||C)?0:A-1") + field(OOPT, "When Non-zero") + field(OUT, "$(INSTR)$(NAME):WAIT_HW PP") +} + +################################################################################ +# Count Startup + +record(seq,"$(INSTR)$(NAME):TRIGGER") +{ + field(DESC, "Start count according to PRESET_TYPE") + field(SELM, "Specified") + field(SELL, "$(INSTR)$(NAME):PRESET_TYPE NPP") + field(DO0, 1) + field(LNK0, "$(INSTR)$(NAME):PRESET_SOFT.PROC") + field(DO1, 1) + field(LNK1, "$(INSTR)$(NAME):PRESET_TIME.PROC") + field(DO2, 1) + field(LNK2, "$(INSTR)$(NAME):PRESET_COUNT.PROC") + field(FLNK, "$(INSTR)$(NAME):SET_WAIT_HW") +} + +record(ao, "$(INSTR)$(NAME):PRESET_SOFT") +{ + field(DESC, "Count forever :)") + field(OMSL, "closed_loop") + field(DOL, "15768000") # Half a year :) + field(OUT, "$(INSTR)$(NAME):T_PRESET") + field(FLNK, "$(INSTR)$(NAME):PRESET_TIME") +} + +record(ao,"$(INSTR)$(NAME):PRESET_TIME") +{ + field(DESC, "Count for specified time") + field(DTYP, "stream") + field(OMSL, "closed_loop") + field(DOL, "$(INSTR)$(NAME):T_PRESET NPP") + field(OUT, "@$(PROTO) startWithTimePreset$(CHANNELS)($(INSTR)$(NAME):) $(ASYN_PORT)") + field(PREC, 2) + field(EGU, "seconds") + field(FLNK, "$(INSTR)$(NAME):HW_POLL_SEQ") +} + +record(ao,"$(INSTR)$(NAME):PRESET_COUNT") +{ + field(DESC, "Count until preset reached") + field(DTYP, "stream") + field(OMSL, "closed_loop") + field(DOL, "$(INSTR)$(NAME):CH_PRESET PP") + field(OUT, "@$(PROTO) startWithCountPreset$(CHANNELS)($(INSTR)$(NAME):) $(ASYN_PORT)") + field(PREC, 0) + field(FLNK, "$(INSTR)$(NAME):HW_POLL_SEQ") +} + +record(longout, "$(INSTR)$(NAME):SET_WAIT_HW") +{ + field(OMSL, "closed_loop") + field(DOL, 5) + field(OUT, "$(INSTR)$(NAME):WAIT_HW PP") +} + +################################################################################ +# Hardware Lowrate Threshold + record(ao,"$(INSTR)$(NAME):THRESHOLD") { field(DESC, "Minimum rate for counting to proceed") @@ -231,7 +359,7 @@ record(ao,"$(INSTR)$(NAME):THRESHOLD") field(DRVH, "100000") # Maximum Rate field(OMSL, "supervisory") field(OROC, "0") - field(OUT, "$(INSTR)$(NAME):THRESHOLD-F PP") + field(OUT, "$(INSTR)$(NAME):CH_THRESHOLD PP") } record(ai,"$(INSTR)$(NAME):THRESHOLD_RBV") @@ -260,26 +388,18 @@ record(longin,"$(INSTR)$(NAME):THRESHOLD-MONITOR_RBV") field(DTYP, "stream") field(SCAN, "1 second") field(EGU, "CH") - field(FLNK, "$(INSTR)$(NAME):THRESHOLD-MONITOR-FLNK") + field(FLNK, "$(INSTR)$(NAME):THR_MONITOR_PROCESS") } -record(calcout, "$(INSTR)$(NAME):THRESHOLD-MONITOR-FLNK") +record(calcout, "$(INSTR)$(NAME):THR_MONITOR_PROCESS") { field(DESC, "Only process Threshold when Non-Zero") - field(CALC, "A") field(INPA, "$(INSTR)$(NAME):THRESHOLD-MONITOR_RBV") + field(CALC, "A") field(OOPT, "When Non-zero") field(OUT, "$(INSTR)$(NAME):THRESHOLD_RBV.PROC PP") } -record(longout, "$(INSTR)$(NAME):CT") -{ - field(DESC, "Clear the timer") - field(DTYP, "stream") - field(OUT, "@$(PROTO) clearTimer($(INSTR)$(NAME):) $(ASYN_PORT)") - field(FLNK, "$(INSTR)$(NAME):ETT") -} - ################################################################################ # Read all monitors values @@ -288,12 +408,4 @@ record(ai, "$(INSTR)$(NAME):READALL") field(DESC, "Reads monitors and elapsed time") field(INP, "@$(PROTO) readAll$(CHANNELS)($(INSTR)$(NAME):) $(ASYN_PORT)") field(DTYP, "stream") - field(FLNK, "$(INSTR)$(NAME):MAP-STATUS") -} - -record(ai,"$(INSTR)$(NAME):ELAPSED-TIME") -{ - field(DESC, "DAQ Measured Time") - field(EGU, "sec") - field(FLNK, "$(INSTR)$(NAME):ETO") } diff --git a/db/time.db b/db/time.db new file mode 100644 index 0000000..54a3094 --- /dev/null +++ b/db/time.db @@ -0,0 +1,132 @@ +# EPICS Database for streamdevice specific to time channel +# +# Macros +# INSTR - Prefix +# NAME - the device name, e.g. EL737 +# PROTO - Stream device protocol file +# ASYN_PORT - Low level Asyn IP Port to DAQ + +################################################################################ +# Time Channel Specific + +# Updated by READALL, at POLL_FREQ frequency +record(ai,"$(INSTR)$(NAME):T") +{ + field(DESC, "DAQ Measured Time") + field(EGU, "sec") + field(FLNK, "$(INSTR)$(NAME):T_POLL") +} + +################################################################################ +# Poll Loop + +record(dfanout, "$(INSTR)$(NAME):T_POLL") +{ + field(DESC, "Time channel poll sequence") + field(SELM, "All") + field(OMSL, "closed_loop") + field(DOL, 1) + field(OUTA, "$(INSTR)$(NAME):T_HWCS.PROC") + field(OUTB, "$(INSTR)$(NAME):T_STS_RAW.PROC") + field(OUTC, "$(INSTR)$(NAME):TIME_REACHED.PROC") +} + +################################################################################ +# Clearing Time + +# Current Status of Channel, i.e. is it ready to count? +record(bi, "$(INSTR)$(NAME):T_CLEARED") +{ + field(DESC, "is hw time being cleared") + field(VAL, 0) + field(ZNAM, "Cleared") + field(ONAM, "Clearing") +} + +# Trigger a change in status as value returned to 0 +record(seq, "$(INSTR)$(NAME):T_HWCS") +{ + field(DESC, "Trigger returned to 0 status") + field(LNK0, "$(INSTR)$(NAME):T_CLEARED PP") + field(DO0, 0) + field(SELM, "Specified") + field(SELL, "$(INSTR)$(NAME):T.VAL") +} + +# Trigger a change in status as clearing +record(dfanout, "$(INSTR)$(NAME):T_CLEAR") +{ + field(DESC, "Clears the time channel count") + field(SELM, "All") + field(OMSL, "closed_loop") + field(DOL, 1) + field(OUTA, "$(INSTR)$(NAME):T_CLEARED PP") + field(OUTB, "$(INSTR)$(NAME):T_HWC.PROC PP") +} + +record(longout, "$(INSTR)$(NAME):T_HWC") +{ + field(DESC, "Clear in Hardware") + field(DTYP, "stream") + field(OMSL, "closed_loop") + field(DOL, "1") + field(OUT, "@$(PROTO) clearTimer($(INSTR)$(NAME):) $(ASYN_PORT)") +} + +################################################################################ +# Determining Time Channel Status + +record(calc, "$(INSTR)$(NAME):T_STS_RAW") +{ + field(DESC, "Raw time channel status") + field(INPA, "$(INSTR)$(NAME):STATUS NPP MS") + field(INPB, "$(INSTR)$(NAME):T_CLEARED NPP") + field(CALC, "A == 1 || B") + field(FLNK, "$(INSTR)$(NAME):T_STS") +} + +# Current Status of Channel, i.e. is it ready for a new operation? +record(mbbi, "$(INSTR)$(NAME):T_STS") +{ + field(DESC, "Time channel status") + field(INP, "$(INSTR)$(NAME):T_STS_RAW NPP MS") + field(ZRVL, "0") + field(ZRST, "Idle") + field(ONVL, "1") + field(ONST, "Busy") +} + +################################################################################ +# Time Channel Preset + +# If set, stop count once preset reached +record(int64in, "$(INSTR)$(NAME):T_PRESET") +{ + field(DESC, "Time Preset") + field(VAL, 0) + field(FLNK, "$(INSTR)$(NAME):TIME_SET_PTYPE") +} + +record(calcout, "$(INSTR)$(NAME):TIME_REACHED") +{ + field(DESC, "Stop if preset reached") + field(INPA, "$(INSTR)$(NAME):T NPP") + field(INPB, "$(INSTR)$(NAME):T_PRESET NPP") + field(CALC, "B > 0 && A >= B") + field(OOPT, "When Non-zero") + field(OUT, "$(INSTR)$(NAME):STOP.PROC") +} + +################################################################################ +# Setting Time Channel Preset + +record(calcout, "$(INSTR)$(NAME):TIME_SET_PTYPE") +{ + field(INPA, "$(INSTR)$(NAME):PRESET_TYPE NPP") + field(INPB, "$(INSTR)$(NAME):T_PRESET NPP") + field(CALC, "A=0 && B>0") + field(OOPT, "When Non-zero") + field(DOPT, "Use OCAL") + field(OCAL, "1") + field(OUT, "$(INSTR)$(NAME):PRESET_TYPE PP") +} diff --git a/scripts/daq_2nd_gen.cmd b/scripts/daq_2nd_gen.cmd index f9879cf..8f0d8f1 100644 --- a/scripts/daq_2nd_gen.cmd +++ b/scripts/daq_2nd_gen.cmd @@ -15,6 +15,8 @@ drvAsynIPPortConfigure("ASYN_$(NAME)", "$($(NAME)_DAQ_HOST)", 0, 0, 0) dbLoadRecords("$(sinqDAQ_DB)daq_common.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNELS=10, RATE_OKAY_BIT=$(RATE_OKAY_BIT=0)") dbLoadRecords("$(sinqDAQ_DB)daq_2nd_gen.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNELS=10") +dbLoadRecords("$(sinqDAQ_DB)time.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME)") + # Could also use substitions instead. dbLoadRecords("$(sinqDAQ_DB)channels.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNEL=1") dbLoadRecords("$(sinqDAQ_DB)channels.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNEL=2") diff --git a/scripts/daq_4ch.cmd b/scripts/daq_4ch.cmd index 208dfc1..a896616 100644 --- a/scripts/daq_4ch.cmd +++ b/scripts/daq_4ch.cmd @@ -15,6 +15,8 @@ drvAsynIPPortConfigure("ASYN_$(NAME)", "$($(NAME)_DAQ_HOST)", 0, 0, 0) dbLoadRecords("$(sinqDAQ_DB)daq_common.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNELS=4, RATE_OKAY_BIT=$(RATE_OKAY_BIT=0)") dbLoadRecords("$(sinqDAQ_DB)daq_4ch.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME)") +dbLoadRecords("$(sinqDAQ_DB)time.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME)") + # Could also use substitions instead. dbLoadRecords("$(sinqDAQ_DB)channels.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNEL=1") dbLoadRecords("$(sinqDAQ_DB)channels.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNEL=2") diff --git a/scripts/daq_8ch.cmd b/scripts/daq_8ch.cmd index af2f1be..58dcf57 100644 --- a/scripts/daq_8ch.cmd +++ b/scripts/daq_8ch.cmd @@ -15,6 +15,8 @@ drvAsynIPPortConfigure("ASYN_$(NAME)", "$($(NAME)_DAQ_HOST)", 0, 0, 0) dbLoadRecords("$(sinqDAQ_DB)daq_common.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNELS=8, RATE_OKAY_BIT=$(RATE_OKAY_BIT=0)") dbLoadRecords("$(sinqDAQ_DB)daq_8ch.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME)") +dbLoadRecords("$(sinqDAQ_DB)time.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME)") + # Could also use substitions instead. dbLoadRecords("$(sinqDAQ_DB)channels.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNEL=1") dbLoadRecords("$(sinqDAQ_DB)channels.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNEL=2") diff --git a/sim/daq_sim.py b/sim/daq_sim.py index d4da2ee..1116132 100644 --- a/sim/daq_sim.py +++ b/sim/daq_sim.py @@ -134,7 +134,7 @@ class DAQ: if self.getMonitorCount() >= self.presetcount: self.counts[self.monitor] = self.presetcount if self.presetcount > 0 else self.counts[self.monitor] - self.status = 0 + self.status = 0 else: raise Exception("Invalid State") @@ -191,7 +191,7 @@ class DAQ: def setGate(self, channel, highlow): self.gate[channel - 1] = highlow - + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind((HOST, PORT)) @@ -216,7 +216,7 @@ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: received = '' logger.info(f'RECEIVED: "{received}"') return received - + daq = DAQ(TOTAL_CH) while True: diff --git a/test/test.py b/test/test.py index c7d45ff..af5dce4 100755 --- a/test/test.py +++ b/test/test.py @@ -42,31 +42,36 @@ def get_piped_output(proc): def getState(instr, name): result = run(['caget', f'{instr}{name}:STATUS'], stdout=PIPE) - state = result.stdout.decode('ascii').rstrip().split()[1] + state = result.stdout.decode('ascii').rstrip().split()[1] print(f'Currently in state {state}') return state def getCount(instr, name, ch): - result = run(['caget', f'{instr}{name}:M{ch}'], stdout=PIPE) + result = run(['caget', f'{instr}{name}:CH{ch}'], stdout=PIPE) count = int(result.stdout.decode('ascii').rstrip().split()[1]) - print(f'M{ch} == {count}') + print(f'CH{ch} == {count}') return count def presetTime(instr, name, time): - print(f'Starting count for {time} seconds') - run(['caput', f'{instr}{name}:PRESET-TIME', f'{time}']) + print(f'Setting preset on time channel of {time} seconds') + run(['caput', f'{instr}{name}:T_PRESET', f'{time}']) -def presetCount(instr, name, count): - print(f'Starting count until channel 1 reaches {count}') - run(['caput', f'{instr}{name}:PRESET-COUNT', f'{count}']) +def presetCount(instr, name, channel, count): + print(f'Setting preset on channel {channel} of {count} counts') + run(['caput', f'{instr}{name}:CH{channel}_PRESET', f'{count}']) + +def startCount(instr, name): + print('Starting Count') + run(['caput', f'{instr}{name}:START', '1']) def testCanCount(instr, name): # Check in Idle State assert getState(instr, name) == 'Idle', 'Not in valid state' - + # Start Time Based Count and Check that Status Changes assert getCount(instr, name, 1) == 0, "Erroneous nonzero starting count value" presetTime(instr, name, 5) + startCount(instr, name) time.sleep(1) assert getState(instr, name) == 'Counting', 'Didn\'t start counting' time.sleep(5) @@ -74,8 +79,10 @@ def testCanCount(instr, name): assert getCount(instr, name, 1) > 0, 'No events were counted' # Start Monitor Based Count and Check that Status Changes + presetChannel = 1 presetAmount = 100 - presetCount(instr, name, presetAmount) + presetCount(instr, name, presetChannel, presetAmount) + startCount(instr, name) time.sleep(1) assert getState(instr, name) == 'Counting', 'Didn\'t start counting' assert getCount(instr, name, 1) < presetAmount @@ -99,8 +106,6 @@ def test(instr, name): if 'iocRun: All initialization complete' in line: break # IOC is now running - #time.sleep(20) - print("IOC Initialisation Complete") print("Starting Tests")