# 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 # 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") { 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") } record(dfanout, "$(INSTR)$(NAME):RESET") { 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 # 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") } ################################################################################ # Hardware Box Specific record(longin, "$(INSTR)$(NAME):CHANNELS") { 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(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(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") } ################################################################################ # HW Commands record(dfanout,"$(INSTR)$(NAME):START") { 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") { field(DESC, "Pause the current count") field(DTYP, "stream") field(OUT, "@$(PROTO) pauseCount($(INSTR)$(NAME):) $(ASYN_PORT)") field(VAL, "0") field(FLNK, "$(INSTR)$(NAME):HW_POLL_SEQ") } 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):HW_POLL_SEQ") } 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):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") 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):CH_THRESHOLD 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):THR_MONITOR_PROCESS") } record(calcout, "$(INSTR)$(NAME):THR_MONITOR_PROCESS") { field(DESC, "Only process Threshold when Non-Zero") field(INPA, "$(INSTR)$(NAME):THRESHOLD-MONITOR_RBV") field(CALC, "A") field(OOPT, "When Non-zero") field(OUT, "$(INSTR)$(NAME):THRESHOLD_RBV.PROC PP") } ################################################################################ # 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") }