# EPICS database for counterbox-like interface using proton current, # as retrieved via network from HIPA. # # This is created to be able reuse the SinqDAQ interface # in Nicos, to avoid having more code to maintain there. # # This requires following macros to specified: # INSTR: Instrument prefix, e.g. "SQAMOR:" # NAME: Name of the DAQ, e.g. "PROTONDAQ" # SHUTTER1_PV: PV of a shutter state will be taken as a gate signal for the protoon current # SHUTTER1_CLOSED_VAL: Value of the shutter PV when the shutter is closed # 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) } record(longin, "$(INSTR)$(NAME):CHANNELS") { field(DESC, "Total Supported Channels") field(VAL, 1) field(DISP, 1) } record(stringin, "$(INSTR)$(NAME):MsgTxt") { field(DESC, "Miscellanous messages") } record(bi, "$(INSTR)$(NAME):IS_LOWRATE") { field(ZNAM, "LOW RATE") field(ONAM, "GOOD RATE") } ################################################################################ # Commands ################################################################################ record(int64in, "$(INSTR)$(NAME):PRESET-COUNT") { field(DESC, "Count until preset reached") field(VAL, 0) 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(calcout, "$(INSTR)$(NAME):PRESET-TIME") { field(DESC, "Count for specified time") field(VAL, 0) field(PREC, 2) field(EGU, "seconds") # Signal count preset as command field(OCAL, 2) field(OOPT, "Every Time") field(DOPT, "Use OCAL") field(OUT, "$(INSTR)$(NAME):COMMAND-TRIG PP") field(FLNK, "$(INSTR)$(NAME):COUNT-TYPE") } record(calcout, "$(INSTR)$(NAME):PAUSE") { field(DESC, "Pause the current count") field(VAL, 0) field(OCAL, 3) field(OOPT, "Every Time") field(DOPT, "Use OCAL") field(OUT, "$(INSTR)$(NAME):COMMAND-TRIG PP") } record(calcout, "$(INSTR)$(NAME):CONTINUE") { field(DESC, "Continue with a count that was paused") field(VAL, "0") field(OCAL, 4) field(OOPT, "Every Time") field(DOPT, "Use OCAL") field(OUT, "$(INSTR)$(NAME):COMMAND-TRIG PP") } record(calcout, "$(INSTR)$(NAME):STOP") { field(DESC, "Stop the current counting operation") field(OCAL, 5) field(OOPT, "Every Time") field(DOPT, "Use OCAL") field(OUT, "$(INSTR)$(NAME):COMMAND-TRIG PP") } record(calcout, "$(INSTR)$(NAME):FULL-RESET") { field(DESC, "Reset the DAQ") field(OCAL, 6) field(OOPT, "Every Time") field(DOPT, "Use OCAL") field(OUT, "$(INSTR)$(NAME):COMMAND-TRIG PP") } # Record is to signal command given by the client to the emulated counter. # It's set back to no command from the emulated counter subroutine record record(mbbi, "$(INSTR)$(NAME):COMMAND-TRIG") { field(DESC, "Command type") field(VAL, 0) field(ZRST, "No command") field(ZRVL, 0) field(ONST, "Count preset command") field(ONVL, 1) field(TWST, "Time preset command") field(TWVL, 2) field(THST, "Pause command") field(THVL, 3) field(FRST, "Continue command") field(FRVL, 4) field(FVST, "Stop command") field(FVVL, 5) field(FVST, "Full reset command") field(FVVL, 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) } 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(ai,"$(INSTR)$(NAME):ELAPSED-TIME") { field(DESC, "DAQ Measured Time") field(EGU, "sec") } # Array Subroutine record which emulates the counterbox functionality # Use an aSub because it allows specifying the type. record(aSub, "$(INSTR)$(NAME):EMULATION") { # Scan rate determines how often we sample the rate # and how often the counter value updates. field(SCAN, ".1 second") field(SNAM, "processEmulatedCounter") # The first 4 inputs are also mapped as the first 4 outputs field(INPA, "$(INSTR)$(NAME):STATUS") field(FTA, "ULONG") field(INPB, "$(INSTR)$(NAME):M0") field(FTB, "INT64") field(INPC, "$(INSTR)$(NAME):ELAPSED-TIME") field(FTC, "DOUBLE") field(OUTD, "$(INSTR)$(NAME):COMMAND-TRIG") field(FTD, "ULONG") field(OUTE, "$(INSTR)$(NAME):THRESHOLD") field(FTE, "DOUBLE") # Address the PV which are mapped as input backwards field(INPF, "$(INSTR)$(NAME):COUNT-TYPE") field(FTF, "ULONG") field(INPG, "$(INSTR)$(NAME):PRESET-COUNT") field(FTG, "INT64") field(INPH, "$(INSTR)$(NAME):PRESET-TIME") field(FTH, "DOUBLE") # L is last input before EPICS 7.0.10 field(INPJ, "$(INSTR)$(NAME):R0-PREV") field(FTJ, "DOUBLE") field(INPL, "$(INSTR)$(NAME):R0 PP") field(FTL, "DOUBLE") # The first 4 outputs are also mapped as the first 4 inputs field(OUTA, "$(INSTR)$(NAME):STATUS PP") field(FTVA, "ULONG") field(OUTB, "$(INSTR)$(NAME):M0 PP") field(FTVB, "INT64") field(OUTC, "$(INSTR)$(NAME):ELAPSED-TIME PP") field(FTVC, "DOUBLE") field(OUTD, "$(INSTR)$(NAME):COMMAND-TRIG PP") field(FTVD, "ULONG") field(OUTE, "$(INSTR)$(NAME):R0-PREV PP") field(FTVE, "DOUBLE") field(OUTF, "$(INSTR)$(NAME):IS_LOWRATE PP") field(FTVF, "ULONG") field(OUTF, "$(INSTR)$(NAME):MSG_TXT PP") field(FTVF, "CHAR") } ####################### # Channel interface ####################### record(int64in, "$(INSTR)$(NAME):M0") { field(DESC, "DAQ CH0, proton current") field(EGU, "cts") } # The proton rate take by a PV over the network, PV named indicated by $(REMOTE_RATE_PV) macro # It emulates Zero rate if either shutter is closed. record(calc, "$(INSTR)$(NAME):R0") { field(DESC, "Rate of DAQ CH0 proton current") #field(INPA, "$(REMOTE_RATE_PV) CA") field(INPA, "$(INSTR)$(NAME):PROTON_CURR") field(INPB, "$(SHUTTER1_PV=0)") field(INPC, "$(SHUTTER1_CLOSED_VAL=1)") field(INPD, "$(SHUTTER2_PV=0)") field(INPE, "$(SHUTTER2_CLOSED_VAL=1)") # If either shutter is closed we have no rate field(CALC, "B != C && D != E ? A : 0") field(EGU, "cts/sec") } # Store previous rate value, so we can average over the period record(ai, "$(INSTR)$(NAME):R0-PREV") { field(DESC, "Previous rate of DAQ CH0 proton current") } # Clear channel, has to be calcout due to client # writing 1 to it. record(calcout, "$(INSTR)$(NAME):C0") { field(DESC, "Clear the current channel count") field(OOPT, "Every Time") field(DOPT, "Use OCAL") field(OCAL, "0") field(OUT, "$(INSTR)$(NAME):M0 PP") } # Current Status of Channel, i.e. is it ready to count? # This is probbably only need to satify the interface. record(bi, "$(INSTR)$(NAME):S0") { field(DESC, "Channel Status") field(VAL, 0) field(ZNAM, "OK") field(ONAM, "CLEARING") } record(calc, "$(INSTR)$(NAME):PROTON_CURR") { field(SCAN, ".1 second") field(CALC, "1500 * 101 * SIN(A)") field(INPA, "$(INSTR)$(NAME):PROTON_CURR_VAR PP") } record(calc, "$(INSTR)$(NAME):PROTON_CURR_VAR") { field(CALC, "VAL + 0.001") }