# EPICS Database for streamdevice support with SinqDAQ Systems # # Macros # INSTR - Prefix # NAME - the device name, e.g. EL737 # PROTO - Stream device protocol file # ASYN_PORT - Low level Asyn IP Port to EL737 # Send initial initialisation commands record(bo, "$(INSTR)$(NAME):INIT-CONF") { field(DESC, "Initialises the DAQ") field(OUT, "@$(PROTO) initialise($(INSTR)$(NAME):) $(ASYN_PORT)") field(PINI, "YES") # Run at init field(DTYP, "stream") } record(longout, "$(INSTR)$(NAME):FULL-RESET") { field(DESC, "Reset the DAQ") field(OUT, "@$(PROTO) fullReset($(INSTR)$(NAME):) $(ASYN_PORT)") field(DTYP, "stream") } ################################################################################ # Status Variables record(stringin, "$(INSTR)$(NAME):MsgTxt") { field(DESC, "Unexpected received response") field(DTYP, "devDAQStringError") field(FLNK, "$(INSTR)$(NAME):INVALID-CONFIG") } # We want to recognise the invalid config error message, so that we can rerun # the init if it occurs. This should only happen after turning the DAQ off and # on again or running a full reset record(scalcout, "$(INSTR)$(NAME):INVALID-CONFIG") { field(DESC, "Has the DAQ been configured?") field(CALC, "AA[0,2] == '?OF'") field(INAA, "$(INSTR)$(NAME):MsgTxt") field(FLNK, "$(INSTR)$(NAME):REINIT-CONF") } record(seq, "$(INSTR)$(NAME):REINIT-CONF") { field(LNK1, "$(INSTR)$(NAME):INIT-CONF PP") field(DO1, 1) field(SELM, "Specified") 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") { 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") } record(bi, "$(INSTR)$(NAME):COUNTING_TIME") { 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(ZNAM, "DISABLED") field(ONAM, "COUNTING") } 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(CALC, "(A=$(RATE_OKAY_BIT))?0:1") } record(bi, "$(INSTR)$(NAME):IS_LOWRATE") { field(INP, "$(INSTR)$(NAME):RATE_MAP PP MS") field(ONAM, "LOW RATE") field(ZNAM, "GOOD RATE") } record(bi, "$(INSTR)$(NAME):IS_PAUSED") { field(INP, "$(INSTR)$(NAME):RAW-STATUS.B3 NPP MS") field(ZNAM, "RUNNING") field(ONAM, "PAUSED") } record(longin, "$(INSTR)$(NAME):COUNT_STARTED") { field(DESC, "Internal Sent Start Count") field(VAL, 0) field(PINI, "YES") } 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):COUNT_STARTED NPP MS") field(CALC, "(A=1||B=1)?4:(F=1)?3:(C=0&&D=0&&G<=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(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") field(FLNK, "$(INSTR)$(NAME):RESET-P-PRESET") } record(calcout, "$(INSTR)$(NAME):RESET-P-PRESET") { 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") field(FLNK, "$(INSTR)$(NAME):RESET-HW_ETT") } record(calcout, "$(INSTR)$(NAME):RESET-HW_ETT") { 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):HW_ETT PP") field(FLNK, "$(INSTR)$(NAME):RESET-HW-PRESET") } record(calcout, "$(INSTR)$(NAME):RESET-HW-PRESET") { 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):RESET_HW_MT PP") field(FLNK, "$(INSTR)$(NAME):Z_COUNT_STARTED") } record(calcout, "$(INSTR)$(NAME):Z_COUNT_STARTED") { field(INPA, "$(INSTR)$(NAME):COUNT_STARTED 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):COUNT_STARTED PP") } 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):ET_CLEARED 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):ET_CLEARED PP") field(DO0, 0) field(SELM, "Specified") field(SELL, "$(INSTR)$(NAME):ELAPSED-TIME.VAL") field(FLNK, "$(INSTR)$(NAME):ETS") } # Current Status of Channel, i.e. is it ready to count? record(bi, "$(INSTR)$(NAME):ET_CLEARED") { field(DESC, "Channel Status") field(VAL, 0) field(ZNAM, "CLEARED") field(ONAM, "CLEARING") } record(calc, "$(INSTR)$(NAME):ETS") { field(DESC, "Stupid Nicos Stuff") field(INPA, "$(INSTR)$(NAME):STATUS NPP") field(INPB, "$(INSTR)$(NAME):ET_CLEARED NPP") field(CALC, "A == 1 || B") } # Time Threshold record(int64in, "$(INSTR)$(NAME):HW_ETT") { field(DESC, "Time Threshold") field(VAL, 0) field(FLNK, "$(INSTR)$(NAME):SET-TYPE-TIME") } record(calcout, "$(INSTR)$(NAME):SET-TYPE-TIME") { field(INPA, "$(INSTR)$(NAME):PRESET-TYPE NPP") field(INPB, "$(INSTR)$(NAME):HW_ETT 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") } ################################################################################ # Count Commands 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") field(VAL, 0) field(PINI, "YES") } record(bo,"$(INSTR)$(NAME):START") { field(DESC, "Zero, then trigger") field(FLNK, "$(INSTR)$(NAME):PREPARE") } record(dfanout,"$(INSTR)$(NAME):PREPARE") { field(DESC, "Zero channels") field(SELM, "All") field(OMSL, "supervisory") # Elapsed Time field(OUTA, "$(INSTR)$(NAME):CT PP") field(OUTB, "$(INSTR)$(NAME):CMONITORS PP") field(FLNK, "$(INSTR)$(NAME):TRIGGER") } record(seq,"$(INSTR)$(NAME):TRIGGER") { field(DESC, "Actually triggers sending start") field(DO1, 1) field(LNK1, "$(INSTR)$(NAME):PRESET-TIME.PROC") field(DO2, 1) field(LNK2, "$(INSTR)$(NAME):PRESET-COUNT.PROC") field(SELM, "Specified") field(SELL, "$(INSTR)$(NAME):PRESET-TYPE NPP") field(FLNK, "$(INSTR)$(NAME):O_COUNT_STARTED") } record(longout, "$(INSTR)$(NAME):O_COUNT_STARTED") { field(OMSL, "closed_loop") field(DOL, 5) field(OUT, "$(INSTR)$(NAME):COUNT_STARTED PP") } record(ao,"$(INSTR)$(NAME):PRESET-TIME") { field(DESC, "Count for specified time") field(DTYP, "stream") field(OMSL, "closed_loop") field(DOL, "$(INSTR)$(NAME):HW_ETT NPP") field(OUT, "@$(PROTO) startWithTimePreset$(CHANNELS)($(INSTR)$(NAME):) $(ASYN_PORT)") field(PREC, 2) field(EGU, "seconds") field(FLNK, "$(INSTR)$(NAME):RAW-STATUS") } record(ao,"$(INSTR)$(NAME):PRESET-COUNT") { field(DESC, "Count until preset reached") field(DTYP, "stream") field(OMSL, "closed_loop") field(DOL, "$(INSTR)$(NAME):HW_MT PP") field(OUT, "@$(PROTO) startWithCountPreset$(CHANNELS)($(INSTR)$(NAME):) $(ASYN_PORT)") field(PREC, 0) field(FLNK, "$(INSTR)$(NAME):RAW-STATUS") } record(bo,"$(INSTR)$(NAME):PAUSE") { field(DESC, "Pause the current count") field(DTYP, "stream") field(OUT, "@$(PROTO) pauseCount($(INSTR)$(NAME):) $(ASYN_PORT)") field(VAL, "0") field(FLNK, "$(INSTR)$(NAME):RAW-STATUS") } record(bo,"$(INSTR)$(NAME):CONTINUE") { field(DESC, "Continue with a count that was paused") field(DTYP, "stream") field(OUT, "@$(PROTO) continueCount($(INSTR)$(NAME):) $(ASYN_PORT)") field(VAL, "0") field(FLNK, "$(INSTR)$(NAME):RAW-STATUS") } 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") } record(ao,"$(INSTR)$(NAME):THRESHOLD") { field(DESC, "Minimum rate for counting to proceed") field(VAL, "1") # Default Rate # Could perhaps still be improved. # It seems to only accept whole counts? field(DRVL, "1") # Minimum Rate field(DRVH, "100000") # Maximum Rate field(OMSL, "supervisory") field(OROC, "0") field(OUT, "$(INSTR)$(NAME):THRESHOLD-F PP") } record(ai,"$(INSTR)$(NAME):THRESHOLD_RBV") { field(DESC, "Minimum rate for counting to proceed") field(INP, "@$(PROTO) readMinRate($(INSTR)$(NAME):) $(ASYN_PORT)") field(VAL, 0) field(DTYP, "stream") field(EGU, "cts/sec") } record(longout,"$(INSTR)$(NAME):THRESHOLD-MONITOR") { field(DESC, "Channel monitored for minimum rate") field(VAL, "1") # Monitor field(DRVL, "0") # Smallest Threshold Channel (0 is off) field(DRVH, "$(CHANNELS)") # Largest Threshold Channel field(OUT, "@$(PROTO) setRateMonitor($(INSTR)$(NAME):) $(ASYN_PORT)") field(DTYP, "stream") } record(longin,"$(INSTR)$(NAME):THRESHOLD-MONITOR_RBV") { field(DESC, "Channel monitored for minimum rate") field(INP, "@$(PROTO) readRateMonitor($(INSTR)$(NAME):) $(ASYN_PORT)") field(DTYP, "stream") field(SCAN, "1 second") field(EGU, "CH") field(FLNK, "$(INSTR)$(NAME):THRESHOLD-MONITOR-FLNK") } record(calcout, "$(INSTR)$(NAME):THRESHOLD-MONITOR-FLNK") { field(DESC, "Only process Threshold when Non-Zero") field(CALC, "A") field(INPA, "$(INSTR)$(NAME):THRESHOLD-MONITOR_RBV") 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 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") }