diff --git a/db/daq_soft_proton.db b/db/daq_soft_proton.db index b56394e..f029240 100644 --- a/db/daq_soft_proton.db +++ b/db/daq_soft_proton.db @@ -25,23 +25,9 @@ # SHUTTER2_PV: PV of a second shutter state will be taken as a gate signal for the protoon current # SHUTTER2_CLOSED_VAL: Value of the shutter PV when the shutter is closed -record(mbbi, "$(INSTR)$(NAME):STATUS") -{ - field(DESC, "DAQ Status") - field(ZRVL, "0") - field(ZRST, "Idle") - field(ONVL, "1") - field(ONST, "Counting") - field(TWVL, "2") - field(TWST, "Low rate") - field(THVL, "3") - field(THST, "Paused") - # 4 should never happen, if it does it means the DAQ reports undocumented statusbits - field(FRVL, "4") - field(FRST, "INVALID") - # We start in idle - field(VAL, 0) -} +################################################################################ +# Count Config +################################################################################ record(longin, "$(INSTR)$(NAME):CHANNELS") { @@ -63,43 +49,44 @@ record(bi, "$(INSTR)$(NAME):IS_LOWRATE") field(ONAM, "GOOD RATE") } +record(longout,"$(INSTR)$(NAME):THRESHOLD-MONITOR") +{ + # Alias to RBV to be compatible with higher level interface + alias("$(INSTR)$(NAME):THRESHOLD-MONITOR_RBV") + field(DESC, "Channel monitored for minimum rate") + field(VAL, "1") # Monitor + field(DRVL, "0") # Smallest Threshold Channel (0 is off) + field(DRVH, "1") # Largest Threshold Channel +} + +record(ao,"$(INSTR)$(NAME):THRESHOLD") +{ + # Alias to RBV to be compatible with higher level interface + alias("$(INSTR)$(NAME):THRESHOLD_RBV") + field(DESC, "Minimum rate for counting to proceed") + field(VAL, "1") # Default Rate + field(DRVL, "1") # Minimum Rate + field(DRVH, "100000") # Maximum Rate + field(OMSL, "supervisory") +} + +record(longout, "$(INSTR)$(NAME):MONITOR-CHANNEL") +{ + alias("$(INSTR)$(NAME):MONITOR-CHANNEL_RBV") + field(DESC, "Count preset channel") + field(VAL, 1) +} + ################################################################################ # Commands ################################################################################ -record(ao, "$(INSTR)$(NAME):PRESET_COUNT") +record(seq, "$(INSTR)$(NAME):START") { - field(DESC, "Count until preset reached") - field(VAL, 0) - field(PREC, 2) - field(FLNK, "$(INSTR)$(NAME):PRESET_COUNT-TRIG") -} - -record(longout, "$(INSTR)$(NAME):PRESET_COUNT-TRIG") -{ - field(DESC, "Count until preset reached") - # Signal count preset as command - field(VAL, 1) - field(OUT, "$(INSTR)$(NAME):COMMAND-TRIG PP") - field(FLNK, "$(INSTR)$(NAME):COUNT-TYPE") -} - -record(ao, "$(INSTR)$(NAME):PRESET_TIME") -{ - field(DESC, "Count for specified time") - field(VAL, 0) - field(PREC, 2) - field(EGU, "seconds") - field(FLNK, "$(INSTR)$(NAME):PRESET_TIME-TRIG") -} - -record(longout, "$(INSTR)$(NAME):PRESET_TIME-TRIG") -{ - field(DESC, "Count until preset time reached") - # Signal count preset as command - field(VAL, 2) - field(OUT, "$(INSTR)$(NAME):COMMAND-TRIG PP") - field(FLNK, "$(INSTR)$(NAME):COUNT-TYPE") + field(DESC, "Start a count") + field(SELM, "All") + field(DO0, 1) + field(LNK0, "$(INSTR)$(NAME):COMMAND-TRIG PP") } record(seq, "$(INSTR)$(NAME):PAUSE") @@ -131,22 +118,7 @@ record(seq, "$(INSTR)$(NAME):FULL-RESET") field(DESC, "Perform full reset") field(SELM, "All") field(DO0, 6) - field(LNK0, "$(INSTR)$(NAME):COMMAND-TRIG PP") -} - -# Emulate Reset elapsed time -# 0. set status to busy -# 1. set elapsed time to 0 -# 2. set status to OK -record(seq, "$(INSTR)$(NAME):T_CLEAR") -{ - field(SELM, "All") - field(LNK0, "$(INSTR)$(NAME):T_STS PP") - field(DO0, 1) - field(LNK1, "$(INSTR)$(NAME):T PP") - field(DO1, 0) - field(LNK2, "$(INSTR)$(NAME):T_STS PP") - field(DO2, 0) + field(LNK0, "$(INSTR)$(NAME):COMMAND-TRIG PP") } # Record is to signal command given by the client to the emulated counter. @@ -159,8 +131,8 @@ record(mbbi, "$(INSTR)$(NAME):COMMAND-TRIG") field(ZRVL, 0) field(ONST, "Count preset command") field(ONVL, 1) - field(TWST, "Time preset command") - field(TWVL, 2) + # field(TWST, "Time preset command") + # field(TWVL, 2) field(THST, "Pause command") field(THVL, 3) field(FRST, "Continue command") @@ -171,53 +143,31 @@ record(mbbi, "$(INSTR)$(NAME):COMMAND-TRIG") field(SXVL, 6) } -# Copy COMMAND-TRIG to memorize what type of count is on-going -record(longin, "$(INSTR)$(NAME):COUNT-TYPE") { - field(INP, "$(INSTR)$(NAME):COMMAND-TRIG.VAL NPP") - field(VAL, 0) +# Identical to FULL-RESET +record(seq, "$(INSTR)$(NAME):RESET") +{ + field(SELM, "All") + field(DO0, 1) + field(LNK0, "$(INSTR)$(NAME):FULL-RESET.PROC PP") } -record(longout,"$(INSTR)$(NAME):THRESHOLD-MONITOR") -{ - # Alias to RBV to be compatible with higher level interface - alias("$(INSTR)$(NAME):THRESHOLD-MONITOR_RBV") - field(DESC, "Channel monitored for minimum rate") - field(VAL, "1") # Monitor - field(DRVL, "0") # Smallest Threshold Channel (0 is off) - field(DRVH, "1") # Largest Threshold Channel -} +################################################################################ +# Poll Loop +################################################################################ -record(ao,"$(INSTR)$(NAME):THRESHOLD") -{ - # Alias to RBV to be compatible with higher level interface - alias("$(INSTR)$(NAME):THRESHOLD_RBV") - field(DESC, "Minimum rate for counting to proceed") - field(VAL, "1") # Default Rate - field(DRVL, "1") # Minimum Rate - field(DRVH, "100000") # Maximum Rate - field(OMSL, "supervisory") -} +# TODO need to reset the presets to 0 after the count -record(ai,"$(INSTR)$(NAME):T") +record(dfanout, "$(INSTR)$(NAME):DB_POLL") { - field(DESC, "DAQ Measured Time") - field(EGU, "sec") -} - -# Current Status of elapsed time -record(bi, "$(INSTR)$(NAME):T_STS") -{ - field(DESC, "Channel Status") - field(VAL, 0) - field(ZNAM, "Idle") - field(ONAM, "Busy") -} - -record(longout, "$(INSTR)$(NAME):MONITOR-CHANNEL") -{ - alias("$(INSTR)$(NAME):MONITOR-CHANNEL_RBV") - field(DESC, "PRESET_COUNT Monitors this channel") - field(VAL, 1) + 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):T_STS_RAW.PROC") + field(OUTB, "$(INSTR)$(NAME):CH1_STS_RAW.PROC") + field(OUTB, "$(INSTR)$(NAME):STATUS.PROC") } # Array Subroutine record which emulates the counterbox functionality @@ -244,11 +194,11 @@ record(aSub, "$(INSTR)$(NAME):EMULATION") field(FTE, "LONG") field(INPF, "$(INSTR)$(NAME):THRESHOLD") field(FTF, "DOUBLE") - field(INPG, "$(INSTR)$(NAME):COUNT-TYPE") - field(FTG, "ULONG") - field(INPH, "$(INSTR)$(NAME):PRESET_COUNT") - field(FTH, "DOUBLE") - field(INPI, "$(INSTR)$(NAME):PRESET_TIME") + # field(INPG, "$(INSTR)$(NAME):COUNT-TYPE") + # field(FTG, "ULONG") + field(INPH, "$(INSTR)$(NAME):CH1_PRESET") + field(FTH, "INT64") + field(INPI, "$(INSTR)$(NAME):T_PRESET") field(FTI, "DOUBLE") # L is last input before EPICS 7.0.10 field(INPJ, "$(INSTR)$(NAME):CH1_RATE-PREV") @@ -257,7 +207,7 @@ record(aSub, "$(INSTR)$(NAME):EMULATION") field(FTL, "DOUBLE") # The first 4 outputs are also mapped as the first 4 inputs - field(OUTA, "$(INSTR)$(NAME):STATUS PP") + field(OUTA, "$(INSTR)$(NAME):RAW_STATUS PP") field(FTVA, "ULONG") field(OUTB, "$(INSTR)$(NAME):CH1 PP") field(FTVB, "INT64") @@ -272,11 +222,96 @@ record(aSub, "$(INSTR)$(NAME):EMULATION") field(OUTG, "$(INSTR)$(NAME):MsgTxt PP") field(FTVG, "CHAR") field(NOVG, 40) + + field(FLNK, "$(INSTR)$(NAME):DB_POLL") } -####################### +record(mbbi, "$(INSTR)$(NAME):RAW_STATUS") +{ + field(DESC, "Raw returned status value") +} + +record(mbbi, "$(INSTR)$(NAME):STATUS") +{ + field(DESC, "DAQ Status") + field(INP, "$(INSTR)$(NAME):RAW_STATUS NPP MS") + field(ZRVL, "0") + field(ZRST, "Idle") + field(ONVL, "1") + field(ONST, "Counting") + field(TWVL, "2") + field(TWST, "Low rate") + field(THVL, "3") + field(THST, "Paused") + # 4 should never happen, if it does it means the DAQ reports undocumented statusbits + field(FRVL, "4") + field(FRST, "INVALID") + # We start in idle + field(VAL, 0) +} + +################################################################################ +# Time Channel interface +################################################################################ + +record(ai,"$(INSTR)$(NAME):T") +{ + field(DESC, "DAQ Measured Time") + field(EGU, "sec") +} + +record(ai, "$(INSTR)$(NAME):T_PRESET") +{ + field(DESC, "Time Preset") + field(VAL, 0) +} + +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, "(0 < A && A < 4) || B") + field(FLNK, "$(INSTR)$(NAME):T_STS") +} + +# Current Status of elapsed time +record(bi, "$(INSTR)$(NAME):T_STS") +{ + field(DESC, "Channel Status") + field(INP, "$(INSTR)$(NAME):T_STS_RAW NPP MS") + field(ZNAM, "Idle") + field(ONAM, "Busy") +} + +record(bi, "$(INSTR)$(NAME):T_CLEARED") +{ + field(DESC, "is being cleared") + field(VAL, 0) + field(ZNAM, "Cleared") + field(ONAM, "Clearing") + field(FLNK, "$(INSTR)$(NAME):T_STS_RAW") +} + +# Emulate Reset elapsed time +# 0. set status to busy +# 1. set elapsed time to 0 +# 2. set status to OK +record(seq, "$(INSTR)$(NAME):T_CLEAR") +{ + field(SELM, "All") + field(LNK0, "$(INSTR)$(NAME):T_CLEARED PP") + field(DO0, 1) + field(LNK1, "$(INSTR)$(NAME):T PP") + field(DO1, 0) + field(LNK2, "$(INSTR)$(NAME):T_CLEARED PP") + field(DO2, 0) +} + +################################################################################ # Channel interface -####################### +################################################################################ + record(int64in, "$(INSTR)$(NAME):CH1") { field(DESC, "DAQ CH0, proton current") @@ -307,19 +342,19 @@ record(ai, "$(INSTR)$(NAME):CH1_RATE-PREV") { field(DESC, "Previous rate of DAQ CH0 proton current") } -# Emulate clearing channel -# 0. set status to busy -# 1. set elapsed time to 0 -# 2. set status to OK -record(seq, "$(INSTR)$(NAME):CH1_CLEAR") +record(int64in, "$(INSTR)$(NAME):CH1_PRESET") { - field(SELM, "All") - field(LNK0, "$(INSTR)$(NAME):CH1_STS PP") - field(DO0, 1) - field(LNK1, "$(INSTR)$(NAME):CH1 PP") - field(DO1, 0) - field(LNK2, "$(INSTR)$(NAME):CH1_STS PP") - field(DO2, 0) + field(DESC, "Monitor Count Preset") + field(VAL, 0) +} + +record(calc, "$(INSTR)$(NAME):CH1_STS_RAW") +{ + field(DESC, "Raw Channel Status") + field(INPA, "$(INSTR)$(NAME):STATUS NPP MS") + field(INPB, "$(INSTR)$(NAME):CH1_CLEARED NPP") + field(CALC, "(0 < A && A < 4) || B") + field(FLNK, "$(INSTR)$(NAME):CH1_STS") } # Current Status of Channel @@ -327,7 +362,31 @@ record(seq, "$(INSTR)$(NAME):CH1_CLEAR") record(bi, "$(INSTR)$(NAME):CH1_STS") { field(DESC, "Channel Status") + field(INP, "$(INSTR)$(NAME):CH1_STS_RAW NPP MS") + field(ZNAM, "Idle") + field(ONAM, "Busy") +} + +record(bi, "$(INSTR)$(NAME):CH1_CLEARED") +{ + field(DESC, "are hw counts being cleared") field(VAL, 0) - field(ZNAM, "OK") - field(ONAM, "CLEARING") + field(ZNAM, "Cleared") + field(ONAM, "Clearing") + field(FLNK, "$(INSTR)$(NAME):CH1_STS_RAW") +} + +# Emulate clearing channel +# 0. set status to busy +# 1. set elapsed time to 0 +# 2. set status to OK +record(seq, "$(INSTR)$(NAME):CH1_CLEAR") +{ + field(SELM, "All") + field(LNK0, "$(INSTR)$(NAME):CH1_CLEARED PP") + field(DO0, 1) + field(LNK1, "$(INSTR)$(NAME):CH1 PP") + field(DO1, 0) + field(LNK2, "$(INSTR)$(NAME):CH1_CLEARED PP") + field(DO2, 0) } diff --git a/db/time.db b/db/time.db index 1140620..2ee4a67 100644 --- a/db/time.db +++ b/db/time.db @@ -100,6 +100,7 @@ record(mbbi, "$(INSTR)$(NAME):T_STS") # Time Channel Preset # If set, stop count once preset reached +# TODO type record(int64in, "$(INSTR)$(NAME):T_PRESET") { field(DESC, "Time Preset") diff --git a/scripts/daq_soft_proton.cmd b/scripts/daq_soft_proton.cmd index 4fea727..526a63a 100644 --- a/scripts/daq_soft_proton.cmd +++ b/scripts/daq_soft_proton.cmd @@ -1,8 +1,6 @@ -#var softProtonDebug 1 +var softProtonDebug 1 $(SET_SIM_MODE=#)dbLoadRecords("$(sinqDAQ_DB)sim_proton_current.db", "INSTR=$(INSTR), NAME=$(NAME)") $(SET_SIM_MODE=#)epicsEnvSet("REMOTE_RATE_PV", "$(INSTR)$(NAME):SIM-PROTON-CURR") dbLoadRecords("$(sinqDAQ_DB)daq_soft_proton.db", "INSTR=$(INSTR), NAME=$(NAME), REMOTE_RATE_PV=$(REMOTE_RATE_PV=MHC6:IST:2), RATE_EGU=$(RATE_EGU=cts/sec), COUNTER_EGU=$(COUNTER_EGU=cts), SCALE_FACTOR=$(SCALE_FACTOR=100)") - -iocInit diff --git a/src/daq_soft_proton.c b/src/daq_soft_proton.c index 4cc5530..ed5c0e6 100644 --- a/src/daq_soft_proton.c +++ b/src/daq_soft_proton.c @@ -31,9 +31,9 @@ struct spc_internal { epicsFloat64 threshold; epicsFloat64 proton_rate; epicsFloat64 prev_proton_rate; - epicsUInt32 count_type; - epicsFloat64 preset_count; - epicsFloat64 preset_time; + //epicsUInt32 count_type; + epicsInt64 ch1_preset; + epicsFloat64 t_preset; epicsFloat64 average_rate; }; @@ -134,9 +134,9 @@ static long processEmulatedCounter(struct aSubRecord *psub) { spc->command_trig = *(epicsUInt32 *)psub->d; spc->threshold_ch = *(epicsInt32 *)psub->e; spc->threshold = *(epicsFloat64 *)psub->f; - spc->count_type = *(epicsUInt32 *)psub->g; - spc->preset_count = *(epicsFloat64 *)psub->h; - spc->preset_time = *(epicsFloat64 *)psub->i; + // spc->count_type = *(epicsUInt32 *)psub->g; + spc->ch1_preset = *(epicsInt64 *)psub->h; + spc->t_preset = *(epicsFloat64 *)psub->i; spc->prev_proton_rate = *(epicsFloat64 *)psub->j; spc->proton_rate = *(epicsFloat64 *)psub->l; @@ -218,13 +218,14 @@ static long processEmulatedCounter(struct aSubRecord *psub) { spc->command_trig == TIME_PRESET)) { /* Determine if we are idle but received a count command */ if (softProtonDebug) - printf("%s: Starting Count!\n", funcstr); + printf("%s: Starting Count! (time <= %f, count <= %d)\n", + funcstr, spc->t_preset, spc->ch1_preset); /* Sanity check that count type is properly stored */ - if (spc->command_trig != spc->count_type) { - if (softProtonDebug) - printf("%s: Count type not stored!\n", funcstr); - return -1; - } + // if (spc->command_trig != spc->count_type) { + // if (softProtonDebug) + // printf("%s: Count type not stored!\n", funcstr); + // return -1; + // } /* Starting a new count * Reset counter and time */ *monitor_count_out = 0; @@ -281,12 +282,14 @@ static long processEmulatedCounter(struct aSubRecord *psub) { /* Check if count is finished normally. * Higher priority than low rate */ - if (/* Time based count finished */ - (*elapsed_time_out >= spc->preset_time && - spc->count_type == TIME_PRESET) || - /* Monitor based count finished */ - (*monitor_count_out >= spc->preset_count && - spc->count_type == COUNT_PRESET)) { + if ( + (spc->t_preset > 0 && *elapsed_time_out >= spc->t_preset) || + (spc->ch1_preset > 0 && *monitor_count_out >= spc->ch1_preset) + ) { + if (softProtonDebug) + printf("%s: Case COUNT preset reached (time: %f >= %f, count: %lld >= %lld)\n", + funcstr, *elapsed_time_out, spc->t_preset, + *monitor_count_out, spc->ch1_preset); *status_out = IDLE; }