diff --git a/Makefile b/Makefile index 19c6236..56ca12a 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # This build the sinq extensions for the PSI EPICS setup include /ioc/tools/driver.makefile -MODULE=counterbox +MODULE=sinqDAQ BUILDCLASSES=Linux EPICS_VERSIONS=7.0.7 ARCH_FILTER=RHEL% @@ -13,23 +13,27 @@ REQUIRED+=stream # DB files to include in the release TEMPLATES += db/channels.db -TEMPLATES += db/counterbox_4ch.db -TEMPLATES += db/counterbox_8ch.db -TEMPLATES += db/counterbox_common.db -TEMPLATES += db/counterbox_v2.db -TEMPLATES += db/counterbox_v2_test.db -TEMPLATES += db/counterbox.proto +TEMPLATES += db/gating_channels.db +TEMPLATES += db/daq_4ch.db +TEMPLATES += db/daq_8ch.db +TEMPLATES += db/daq_common.db +TEMPLATES += db/daq_2nd_gen.db +TEMPLATES += db/daq_2nd_gen_test.db +TEMPLATES += db/daq.proto + +# Just for simulation +TEMPLATES += db/daq_simcontrol.db # DBD files to include in the release -DBDS += src/counterbox.dbd +DBDS += src/daq.dbd # Source files to build -SOURCES += src/counterbox.cpp +SOURCES += src/daq.cpp -SCRIPTS += scripts/counterbox_4ch.cmd -SCRIPTS += scripts/counterbox_8ch.cmd -SCRIPTS += scripts/counterbox_v2.cmd -SCRIPTS += sim/counterbox_sim.py +SCRIPTS += scripts/daq_4ch.cmd +SCRIPTS += scripts/daq_8ch.cmd +SCRIPTS += scripts/daq_2nd_gen.cmd +SCRIPTS += sim/daq_sim.py CXXFLAGS += -std=c++17 USR_CFLAGS += -Wall -Wextra #-Werror diff --git a/README.md b/README.md index 575c9b0..5a76d62 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ -Counterbox Epics Module +SINQDAQ Epics Module ----------------------- -A Stream and Asyn based driver for configuring the Counterboxes at SINQ. +A Stream and Asyn based driver for configuring the Data Acquisition Systems at +SINQ. This supports the older 4 and 8 channel EL737 models and the new 10CH 2nd generation systems. @@ -9,51 +10,53 @@ generation systems. ## How to Use Unless a custom database is needed, a device can be configure simply by setting -the required environment variables when calling the correct counterbox script. +the required environment variables when calling the correct DAQ interface +script. Required Variables | Environment Variable | Purpose | |----------------------|-----------------------------------------| -| PREFIX | Prefix of all device specific PVs | +| INSTR | Prefix of all device specific PVs | | NAME | First field in all PVs after Prefix | -| CNTBOX\_IP | Network IP of device | -| CNTBOX\_PORT | Network Port of device | +| DAQ\_IP | Network IP of device | +| DAQ\_PORT | Network Port of device | All PVs take the form ``` -$(PREFIX):$(NAME):* +$(INSTR)$(NAME):* ``` Available device startup scripts -* scripts/counterbox\_4ch.cmd -* scripts/counterbox\_8ch.cmd -* scripts/counterbox\_v2.cmd +* scripts/daq\_4ch.cmd +* scripts/daq\_8ch.cmd +* scripts/daq\_2nd\_gen.cmd A device can be configured using one of the startup scripts as follows ``` -epicsEnvSet("PREFIX", "SQ:INSTRUMENT") # can also be set in runScript call +epicsEnvSet("INSTR", "SQ:INSTRUMENT:") # can also be set in runScript call -runScript "$(counterbox_DIR)counterbox_v2.cmd" "NAME=COUNTERBOX, CNTBOX_IP=TestInst-DAQ1, CNTBOX_PORT=2000" +runScript "$(sinqDAQ_DIR)daq_2nd_gen.cmd" "NAME=DAQ, DAQ_IP=TestInst-DAQ1, DAQ_PORT=2000" ``` ## PVs of Interest -| PV | Description | -|---------------------------------------|----------------------------------------------------------------------| -| \$(PREFIX):\$(NAME):MsgTxt | Contains unexpected response to executed command | -| \$(PREFIX):\$(NAME):STATUS | 0: Idle, 1: Counting, 2: Low rate, 3: Paused, 4: Error | -| \$(PREFIX):\$(NAME):MONITOR-CHANNEL | Channel that PRESET-COUNT monitors (has RBV, only v2 can be changed) | -| \$(PREFIX):\$(NAME):PRESET-COUNT | Run count until specified pv value reached | -| \$(PREFIX):\$(NAME):PRESET-TIME | Run count until specified pv value in seconds reached | -| \$(PREFIX):\$(NAME):THRESHOLD | Minimum rate for counting to preceed. (has RBV) | -| \$(PREFIX):\$(NAME):THRESHOLD-MONITOR | Channel monitored for minimum rate (has RBV) | -| \$(PREFIX):\$(NAME):ELAPSED-TIME | Time Counterbox has been measuring for | -| \$(PREFIX):\$(NAME):M_ | Current count on channel. (1-10 depending on box) | -| \$(PREFIX):\$(NAME):CHANNELS | Number of available channels (4, 8 or 10) | +| PV | Description | +|-------------------------------------|----------------------------------------------------------------------| +| \$(INSTR)\$(NAME):MsgTxt | Contains unexpected response to executed command | +| \$(INSTR)\$(NAME):STATUS | 0: Idle, 1: Counting, 2: Low rate, 3: Paused, 4: Error | +| \$(INSTR)\$(NAME):MONITOR-CHANNEL | Channel that PRESET-COUNT monitors (has RBV, only v2 can be changed) | +| \$(INSTR)\$(NAME):PRESET-COUNT | Run count until specified pv value reached | +| \$(INSTR)\$(NAME):PRESET-TIME | Run count until specified pv value in seconds reached | +| \$(INSTR)\$(NAME):THRESHOLD | Minimum rate for counting to preceed. (has RBV) | +| \$(INSTR)\$(NAME):THRESHOLD-MONITOR | Channel monitored for minimum rate (has RBV) | +| \$(INSTR)\$(NAME):ELAPSED-TIME | Time DAQ has been measuring for | +| \$(INSTR)\$(NAME):M_ | Current count on channel. (1-10 depending on DAQ system) | +| \$(INSTR)\$(NAME):CHANNELS | Number of available channels (4, 8 or 10) | +| \$(INSTR)\$(NAME):GATE-_ | Configuration for Gating in newer hardware | ## Generating Test Signals @@ -64,34 +67,133 @@ runtime via the following ``` epicsEnvSet("LOAD_TEST_PVS","") -runScript "$(counterbox_DIR)counterbox_v2.cmd" "NAME=COUNTERBOX, CNTBOX_IP=TestInst-DAQ1, CNTBOX_PORT=2000" +runScript "$(sinqDAQ_DIR)daq_2nd_gen.cmd" "NAME=DAQ, DAQ_IP=TestInst-DAQ1, DAQ_PORT=2000" ``` -See the file [counterbox\_v2\_test.db](./db/counterbox_v2_test.db) +See the file [daq\_2nd\_gen\_test.db](./db/daq_2nd_gen_test.db) + +## Nicos Interface + +A set of Nicos devices have been developed which allow control of the Detector +Hardware via this Epics Driver. The corresponding code can be found in +[sinqdaq.py](https://gitea.psi.ch/lin-instrument-computers/Nicos/src/branch/release-3.12/nicos_sinq/devices/epics/sinqdaq.py). + +## Full Example + +Include the following snippet in your IOC + +``` +# st.cmd at SINQTEST + +epicsEnvSet("STREAM_PROTOCOL_PATH","./db") +epicsEnvSet("INSTR","SQ:SINQTEST:") + +require sinqDAQ +runScript "$(sinqDAQ_DIR)daq_2nd_gen.cmd" "NAME=DAQ, DAQ_IP=TestInst-DAQ1, DAQ_PORT=2000" +``` + +What follows is an example Nicos setup file. The "channels" are created in the loop +at the bottom. + +``` +# DAQDetector.py +description = 'Devices for the detectors' + +countprefix = 'SQ:SINQTEST:DAQ' + +devices = dict( + ElapsedTime = device( + 'nicos_sinq.devices.epics.sinqdaq.DAQTime', + daqpvprefix = countprefix, + ), + DAQPreset = device( + 'nicos_sinq.devices.epics.sinqdaq.DAQPreset', + description = '2nd Generation Data Acquisition', + daqpvprefix = countprefix, + channels = [], + time_channel = ['ElapsedTime'], + ), + DAQV2 = device( + 'nicos_sinq.devices.epics.sinqdaq.SinqDetector', + description = 'Detector Interface', + timers = ['ElapsedTime'], + counters = [], + monitors = ['DAQPreset'], + images = [], + others = [], + liveinterval = 2, + saveintervals = [2] + ), + ThresholdChannel = device( + 'nicos_sinq.devices.epics.sinqdaq.DAQMinThresholdChannel', + daqpvprefix = countprefix, + channels = [], + visibility = {'metadata', 'namespace'}, + ), + Threshold = device( + 'nicos_sinq.devices.epics.sinqdaq.DAQMinThreshold', + daqpvprefix = countprefix, + min_rate_channel = 'ThresholdChannel', + visibility = {'metadata', 'namespace'}, + ), + Gate1 = device( + 'nicos_sinq.devices.epics.sinqdaq.DAQGate', + daqpvprefix = countprefix, + channel = 1, + visibility = {'metadata', 'namespace'}, + ), + Gate2 = device( + 'nicos_sinq.devices.epics.sinqdaq.DAQGate', + daqpvprefix = countprefix, + channel = 2, + visibility = {'metadata', 'namespace'}, + ), + TestGen = device('nicos_sinq.devices.epics.sinqdaq.DAQTestGen', + daqpvprefix = countprefix, + visibility = {'metadata', 'namespace'}, + ), +) + +for i in range(10): + devices[f'monitor{i+1}'] = device( + 'nicos_sinq.devices.epics.sinqdaq.DAQChannel', + description = f'Monitor {i + 1}', + daqpvprefix = countprefix, + channel = i + 1, + type = 'monitor', + ) + devices['DAQPreset'][1]['channels'].append(f'monitor{i+1}') + devices['ThresholdChannel'][1]['channels'].append(f'monitor{i+1}') + devices['DAQV2'][1]['monitors'].append(f'monitor{i+1}') + +startupcode = ''' +SetDetectors(DAQV2) +''' +``` ## Simulation Simulation of the Hardware can be toggled on as follows: ``` -epicsEnvSet("SET_SIM_MODE","") # run counterbox simulation instead of connecting to actual box -runScript "$(counterbox_DIR)counterbox_v2.cmd" "NAME=CB_TEST, CNTBOX_IP=localhost, CNTBOX_PORT=2000" +epicsEnvSet("SET_SIM_MODE","") # run DAQ simulation instead of connecting to actual system +runScript "$(sinqDAQ_DIR)daq_2nd_gen.cmd" "NAME=CB_TEST, DAQ_IP=localhost, DAQ_PORT=2000" ``` -In such a case, the provided `CNTBOX_IP` is ignored, and a python program +In such a case, the provided `DAQ_IP` is ignored, and a python program simulating the hardware is started in the background, listening at the -specified `CNTBOX_PORT`. So, if you have multiple devices listening on the same +specified `DAQ_PORT`. So, if you have multiple devices listening on the same port, you might have to change this port value of one of the devices when simulating hardware. You can then interact with the PVs as with the normal hardware. Keep in mind, however, that not all functionality has been implemented. -See [sim/counterbox\_sim.py](sim/counterbox_sim.py). +See [sim/daq\_sim.py](sim/daq_sim.py). ## Testing -An IOC with the counterbox\_v2 started in simulation mode can be started via -the [test/ioc.sh](test/ioc.sh) script. +An IOC with the 2nd generation DAQ started in simulation mode can be started +via the [test/ioc.sh](test/ioc.sh) script. There is also a simple automated test that can be run for a simple check of functionality and that the PVs load [test/test.py](test/test.py). diff --git a/db/channels.db b/db/channels.db index e12ceaa..48dae2a 100644 --- a/db/channels.db +++ b/db/channels.db @@ -1,20 +1,77 @@ -# EL737 EPICS Database for streamdevice support +# EPICS Database for streamdevice specific to measurement channels +# # Macros -# P - Prefix -# NAME - just a name, e.g. EL737 +# INSTR - Prefix +# NAME - the device name, e.g. EL737 # PROTO - Stream device protocol file -# ASYN_PORT - Low level Asyn IP Port to EL737 +# ASYN_PORT - Low level Asyn IP Port to DAQ +# CHANNEL - the number associated with the measurment channel ################################################################################ # Status Variables +# Trigger a change in status as clearing +record(bo, "$(INSTR)$(NAME):T$(CHANNEL)") +{ + field(DESC, "Trigger Clearing Status") + field(VAL, 1) + field(OUT, "$(INSTR)$(NAME):S$(CHANNEL) PP") +} + +# Trigger a change in status as value returned to 0 +record(seq, "$(INSTR)$(NAME):O$(CHANNEL)") +{ + 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") +} + +# Current Status of Channel, i.e. is it ready to count? +record(bi, "$(INSTR)$(NAME):S$(CHANNEL)") +{ + field(DESC, "Channel Status") + field(VAL, 0) + field(ZNAM, "OK") + field(ONAM, "CLEARING") +} + ################################################################################ # Count Commands +record(longout, "$(INSTR)$(NAME):C$(CHANNEL)") +{ + field(DESC, "Clear the current channel count") + field(DTYP, "stream") + field(OUT, "@$(PROTO) clearChannel($(INSTR)$(NAME):, $(CHANNEL)) $(ASYN_PORT)") + field(FLNK, "$(INSTR)$(NAME):T$(CHANNEL)") +} + +record(ao,"$(INSTR)$(NAME):THRESH$(CHANNEL)") +{ + field(DESC, "Sets minimum 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(longin, "$(P):$(NAME):M$(CHANNEL)") +record(longin, "$(INSTR)$(NAME):M$(CHANNEL)") { - field(DESC, "Counterbox CH$(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/counterbox.proto b/db/counterbox.proto deleted file mode 100644 index b933334..0000000 --- a/db/counterbox.proto +++ /dev/null @@ -1,134 +0,0 @@ -# -# Counterbox Protocol File -# -OutTerminator = CR; -InTerminator = CR; -ReadTimeout = 100; -WriteTimeout = 100; -ReplyTimeout = 200; -LockTimeout = 450; - -initialise { - out "RMT 1"; # Turn on Remote Control - in; - out "ECHO 2"; # Ask for reponses - in "%(\$1MsgTxt)s"; # Clear MsgTxt on Init - @mismatch{ - exec 'echo "Failed to configure counterbox" && exit(1)'; - } -} - -fullReset { - out "\%"; - wait 5000; -} - -################################################################################ -# Status Variables - -readStatus { - out "RS"; - in "%d"; - @mismatch{in "%(\$1MsgTxt)s";} -} - -readPresetMonitor { - out "PC"; - in "%d"; - @mismatch{in "%(\$1MsgTxt)s";} -} - -writePresetMonitor { - out "PC %d"; - @mismatch{in "%(\$1MsgTxt)s";} -} - -################################################################################ -# Count Commands - -startWithCountPreset { - out "MP %d"; - in; - @mismatch{in "%(\$1MsgTxt)s";} -} - -startWithTimePreset { - out "TP %#.2f"; - in; - @mismatch{in "%(\$1MsgTxt)s";} -} - -pauseCount { - out "PS"; - in; - @mismatch{in "%(\$1MsgTxt)s";} -} - -continueCount { - out "CO"; - in; - @mismatch{in "%(\$1MsgTxt)s";} -} - -stopCount { - out "S"; - in; - @mismatch{in "%(\$1MsgTxt)s";} -} - -setMinRate{ - out "DL %(\$1THRESHOLD-MONITOR)d %(\$1THRESHOLD)d"; - in; - out "DR %(\$1THRESHOLD-MONITOR)d"; - in; - @mismatch{in "%(\$1MsgTxt)s";} -} - -readMinRate{ - out "DR"; - in "%(\$1THRESHOLD-MONITOR_RBV)d"; - out "DL %(\$1THRESHOLD-MONITOR_RBV)d"; - in "%(\$1THRESHOLD_RBV)d"; - @mismatch{in "%(\$1MsgTxt)s";} -} - -################################################################################ -# Read Values From Monitors - -readAll4 { - out "RA"; - in "%(\$1ELAPSED-TIME)f %(\$1M1)d %(\$1M2)d %(\$1M3)d %(\$1M4)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"; - @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 %(\$1M9)d %(\$1M10)d"; - @mismatch{in "%(\$1MsgTxt)s";} -} - -readRate { - out "RR \$2"; - in "%(\$1R\$2)f"; - @mismatch{in "%(\$1MsgTxt)s";} -} - -################################################################################ -# Testing Commands - -switchTestgenOnOff { - out "TG %{off|on}"; - @mismatch{in "%(\$1MsgTxt)s";} -} - -# Only suppporting test channel 1 at the moment. (The first argument to TG) -setTestSignal { - out "TG 1 %(\$1TESTGEN-HIGHRATE)d %(\$1TESTGEN-LOWRATE)d"; - @mismatch{in "%(\$1MsgTxt)s";} -} diff --git a/db/counterbox_4ch.db b/db/counterbox_4ch.db deleted file mode 100644 index e5703d1..0000000 --- a/db/counterbox_4ch.db +++ /dev/null @@ -1,29 +0,0 @@ -# Counterbox EPICS Database -# Macros -# P - Prefix -# NAME - just a name, e.g. EL737 -# PROTO - Stream device protocol file -# ASYN_PORT - Low level Asyn IP Port to EL737 - -################################################################################ -# Status Variables - -record(longin, "$(P):$(NAME):MONITOR-CHANNEL") -{ - field(DESC, "PRESET-COUNT Monitors this channel") - field(VAL, 1) - field(DISP, 1) -} - -record(longin, "$(P):$(NAME):MONITOR-CHANNEL_RBV") -{ - field(DESC, "PRESET-COUNT Monitors this channel") - field(VAL, 1) - field(DISP, 1) -} - -################################################################################ -# Count Commands - -################################################################################ -# Read all monitors values diff --git a/db/counterbox_8ch.db b/db/counterbox_8ch.db deleted file mode 100644 index 8f0dfc0..0000000 --- a/db/counterbox_8ch.db +++ /dev/null @@ -1,29 +0,0 @@ -# EL737 EPICS Database for streamdevice support -# Macros -# P - Prefix -# NAME - just a name, e.g. EL737 -# PROTO - Stream device protocol file -# ASYN_PORT - Low level Asyn IP Port to EL737 - -################################################################################ -# Status Variables - -record(longin, "$(P):$(NAME):MONITOR-CHANNEL") -{ - field(DESC, "PRESET-COUNT Monitors this channel") - field(VAL, 1) - field(DISP, 1) -} - -record(longin, "$(P):$(NAME):MONITOR-CHANNEL_RBV") -{ - field(DESC, "PRESET-COUNT Monitors this channel") - field(VAL, 1) - field(DISP, 1) -} - -################################################################################ -# Count Commands - -################################################################################ -# Read all monitors values diff --git a/db/counterbox_common.db b/db/counterbox_common.db deleted file mode 100644 index 09aaf5d..0000000 --- a/db/counterbox_common.db +++ /dev/null @@ -1,215 +0,0 @@ -# EL737 EPICS Database for streamdevice support -# Macros -# P - Prefix -# NAME - just a name, e.g. EL737 -# PROTO - Stream device protocol file -# ASYN_PORT - Low level Asyn IP Port to EL737 - -# Send initial initialisation commands -record(bo, "$(P):$(NAME):INIT-CONF") -{ - field(DESC, "Initialises the Counterbox") - field(OUT, "@$(PROTO) initialise($(P):$(NAME):) $(ASYN_PORT)") - field(PINI, "YES") # Run at init - field(DTYP, "stream") - field(FLNK, "$(P):$(NAME):INIT-BOX") -} - -# As we aren't certain of the order that PINI exectutes PVs, we only set it to -# true on INIT-CONF to make sure the box is ready to receive commands, and then -# let INIT-CONF trigger the initialisation of other necessary records -record(fanout, "$(P):$(NAME):INIT-BOX") -{ - field(DESC, "Rewrite PVs to Box") - field(SELM, "All") - field(LNK0, "$(P):$(NAME):MONITOR-CHANNEL_RBV PP") - field(LNK1, "$(P):$(NAME):RAW-STATUS PP") - field(LNK2, "$(P):$(NAME):THRESHOLD_RBV PP") -} - -record(longout, "$(P):$(NAME):FULL-RESET") -{ - field(DESC, "Reset the Counterbox") - field(OUT, "@$(PROTO) fullReset($(P):$(NAME):) $(ASYN_PORT)") - field(DTYP, "stream") -} - -################################################################################ -# Status Variables - -record(stringin, "$(P):$(NAME):MsgTxt") -{ - field(DESC, "Unexpected received response") - field(DTYP, "devCounterBoxStringError") - field(FLNK, "$(P):$(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 box off and -# on again or running a full reset -record(scalcout, "$(P):$(NAME):INVALID-CONFIG") -{ - field(DESC, "Has the counterbox been configured?") - field(CALC, "AA[0,2] == '?OF'") - field(INAA, "$(P):$(NAME):MsgTxt") - field(FLNK, "$(P):$(NAME):REINIT-CONF") -} - -record(seq, "$(P):$(NAME):REINIT-CONF") -{ - field(LNK1, "$(P):$(NAME):INIT-CONF PP") - field(DO1, 1) - field(SELM, "Specified") - field(SELL, "$(P):$(NAME):INVALID-CONFIG.VAL") -} - -# Important! The "$(P):$(NAME):READALL" isn't configure with a SCAN. Instead, -# it must always be triggered after the value of $(P):$(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. -record(longin, "$(P):$(NAME):RAW-STATUS") -{ - field(DESC, "Raw returned status value") - field(DTYP, "stream") - field(SCAN, ".1 second") - field(INP, "@$(PROTO) readStatus($(P):$(NAME):) $(ASYN_PORT)") - field(FLNK, "$(P):$(NAME):READALL") -} - -record(calc, "$(P):$(NAME):MAP-STATUS") -{ - field(DESC, "Maps Raw Status to State") - field(INPA, "$(P):$(NAME):RAW-STATUS NPP") - field(INPB, "$(P):$(NAME):INVALID-CONFIG NPP") - field(INPC, "$(P):$(NAME):RAW-STATUS.UDF NPP") # should also be invalid if can't read the status - field(CALC, "(B=1||C==1)?4:A=0?0:(A=1||A=2)?1:(A=5||A=6)?2:(A=9||A=13||A=10||A=14)?3:4") - field(FLNK, "$(P):$(NAME):STATUS") -} - -record(mbbi, "$(P):$(NAME):STATUS") -{ - field(DESC, "Counterbox Status") - field(INP, "$(P):$(NAME):MAP-STATUS NPP") - 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 counter box reports undocumented statusbits - field(FRVL, "4") - field(FRST, "INVALID") -} - -record(longin, "$(P):$(NAME):CHANNELS") -{ - field(DESC, "Total Supported Channels") - field(VAL, $(CHANNELS)) - field(DISP, 1) -} - - -################################################################################ -# Count Commands - -record(ao,"$(P):$(NAME):PRESET-COUNT") -{ - field(DESC, "Count until preset reached") - field(DTYP, "stream") - field(OUT, "@$(PROTO) startWithCountPreset($(P):$(NAME):) $(ASYN_PORT)") - field(VAL, 0) - field(PREC, 2) -} - -record(ao,"$(P):$(NAME):PRESET-TIME") -{ - field(DESC, "Count for specified time") - field(DTYP, "stream") - field(OUT, "@$(PROTO) startWithTimePreset($(P):$(NAME):) $(ASYN_PORT)") - field(VAL, 0) - field(PREC, 2) - field(EGU, "seconds") -} - -record(bo,"$(P):$(NAME):PAUSE") -{ - field(DESC, "Pause the current count") - field(DTYP, "stream") - field(OUT, "@$(PROTO) pauseCount($(P):$(NAME):) $(ASYN_PORT)") - field(VAL, "0") -} - -record(bo,"$(P):$(NAME):CONTINUE") -{ - field(DESC, "Continue with a count that was paused") - field(DTYP, "stream") - field(OUT, "@$(PROTO) continueCount($(P):$(NAME):) $(ASYN_PORT)") - field(VAL, "0") -} - -record(bo, "$(P):$(NAME):STOP") -{ - field(DESC, "Stop the current counting operation") - field(DTYP, "stream") - field(OUT, "@$(PROTO) stopCount($(P):$(NAME):) $(ASYN_PORT)") -} - -# TODO should changing the monitor also set things? -# or only when actually setting a threshold? -record(longout,"$(P):$(NAME):THRESHOLD") -{ - field(DESC, "Minimum rate for counting to proceed") - field(VAL, "0") # Rate - field(DRVL, "0") # Minimum Rate - field(DTYP, "stream") - field(OUT, "@$(PROTO) setMinRate($(P):$(NAME):) $(ASYN_PORT)") -} - -record(longin,"$(P):$(NAME):THRESHOLD_RBV") -{ - field(DESC, "Minimum rate for counting to proceed") - field(DTYP, "stream") - field(INP, "@$(PROTO) readMinRate($(P):$(NAME):) $(ASYN_PORT)") - field(SCAN, "2 second") -} - -record(longout,"$(P):$(NAME):THRESHOLD-MONITOR") -{ - field(DESC, "Channel monitored for minimum rate") - field(VAL, "1") # Monitor - field(DRVL, "1") # Smallest Threshold Channel - field(DRVL, "$(CHANNELS)") # Largest Threshold Channel -} - -record(longin,"$(P):$(NAME):THRESHOLD-MONITOR_RBV") -{ - field(DESC, "Channel monitored for minimum rate") -} - -################################################################################ -# Read all monitors values - -record(ai, "$(P):$(NAME):READALL") -{ - field(DESC, "Reads monitors and elapsed time") - field(INP, "@$(PROTO) readAll$(CHANNELS)($(P):$(NAME):) $(ASYN_PORT)") - field(DTYP, "stream") - field(FLNK, "$(P):$(NAME):MAP-STATUS") -} - -record(ai,"$(P):$(NAME):ELAPSED-TIME") -{ - field(DESC, "Counterbox Measured Time") - field(EGU, "seconds") -} - -# Not yet sure whether we want to support this -# record(longin, "$(P):$(NAME):R1") -# { -# field(DESC, "Counterbox Rate CH1") -# field(INP, "@$(PROTO) readRate($(P):$(NAME):, 1) $(ASYN_PORT)") -# field(SCAN, ".2 second") -# field(DTYP, "stream") -# } diff --git a/db/counterbox_v2.db b/db/counterbox_v2.db deleted file mode 100644 index 5be40f0..0000000 --- a/db/counterbox_v2.db +++ /dev/null @@ -1,31 +0,0 @@ -# EL737 EPICS Database for streamdevice support -# Macros -# P - Prefix -# NAME - just a name, e.g. DAQV2 -# PROTO - Stream device protocol file -# ASYN_PORT - Low level Asyn IP Port to Counterbox - -################################################################################ -# Status Variables - -record(longout, "$(P):$(NAME):MONITOR-CHANNEL") -{ - field(DESC, "PRESET-COUNT Monitors this channel") - field(DTYP, "stream") - field(OUT, "@$(PROTO) writePresetMonitor($(P):$(NAME):) $(ASYN_PORT)") - field(FLNK, "$(P):$(NAME):MONITOR-CHANNEL_RBV") -} - -record(longin, "$(P):$(NAME):MONITOR-CHANNEL_RBV") -{ - field(DESC, "PRESET-COUNT Monitors this channel") - field(DTYP, "stream") - field(INP, "@$(PROTO) readPresetMonitor($(P):$(NAME):) $(ASYN_PORT)") - field(SCAN, "5 second") -} - -################################################################################ -# Count Commands - -################################################################################ -# Read all monitors values diff --git a/db/counterbox_v2_test.db b/db/counterbox_v2_test.db deleted file mode 100644 index 07b0f65..0000000 --- a/db/counterbox_v2_test.db +++ /dev/null @@ -1,31 +0,0 @@ -################################################################################ -# Testing Commands - -# These won't match the values on the machine after a full restart But I chose -# not to force their intialisation as they are only important for testing - -record(bo, "$(P):$(NAME):TESTGEN") -{ - field(DESC, "Turn on/off Testgen Signal") - field(DTYP, "stream") - field(OUT, "@$(PROTO) switchTestgenOnOff($(P):$(NAME):) $(ASYN_PORT)") - field(VAL, 0) - field(ZNAM, "OFF") - field(ONAM, "ON") -} - -record(longout, "$(P):$(NAME):TESTGEN-LOWRATE") -{ - field(DESC, "Set Minimum Testgen Rate") - field(DTYP, "stream") - field(OUT, "@$(PROTO) setTestSignal($(P):$(NAME):) $(ASYN_PORT)") - field(VAL, 1000) -} - -record(longout, "$(P):$(NAME):TESTGEN-HIGHRATE") -{ - field(DESC, "Set Maximum Testgen Rate") - field(DTYP, "stream") - field(OUT, "@$(PROTO) setTestSignal($(P):$(NAME):) $(ASYN_PORT)") - field(VAL, 1000) -} diff --git a/db/daq.proto b/db/daq.proto new file mode 100644 index 0000000..6d5fbec --- /dev/null +++ b/db/daq.proto @@ -0,0 +1,268 @@ +# +# SinqDAQ Protocol File +# +OutTerminator = CR; +InTerminator = CR; +ReadTimeout = 100; +WriteTimeout = 100; +ReplyTimeout = 200; +LockTimeout = 450; + +initialise { + out "RMT 1"; # Turn on Remote Control + in; + out "ECHO 2"; # Ask for reponses + in "%(\$1MsgTxt)s"; # Clear MsgTxt on Init + @mismatch{ + exec 'echo "Failed to configure DAQ" && exit(1)'; + } +} + +fullReset { + out "\%"; + wait 5000; +} + +################################################################################ +# Status Variables + +readStatus { + out "RS"; + in "%d"; + @mismatch{in "%(\$1MsgTxt)s";} +} + +readPresetMonitor { + out "PC"; + in "%d"; + @mismatch{in "%(\$1MsgTxt)s";} +} + +writePresetMonitor { + out "PC %d"; + @mismatch{in "%(\$1MsgTxt)s";} +} + +################################################################################ +# Count Commands + +pauseCount { + out "PS"; + in; + @mismatch{in "%(\$1MsgTxt)s";} +} + +continueCount { + out "CO"; + in; + @mismatch{in "%(\$1MsgTxt)s";} +} + +stopCount { + out "S"; + in; + @mismatch{in "%(\$1MsgTxt)s";} +} + +clearTimer{ + # We first stop the count, as otherwise the 2nd Gen Data Acquisition starts + # counting again if a time preset was set. Not a problem with the older boxes + stopCount; + out "CT"; + in; + @mismatch{in "%(\$1MsgTxt)s";} +} + +clearChannel{ + out "CC \$2"; + in; + @mismatch{in "%(\$1MsgTxt)s";} +} + +clearCounter4 { + out "CC 1"; + in; + out "CC 2"; + in; + out "CC 3"; + in; + out "CC 4"; + in; + @mismatch{in "%(\$1MsgTxt)s";} +} + +clearCounter8 { + out "CC 5"; + in; + out "CC 6"; + in; + out "CC 7"; + in; + out "CC 8"; + in; + @mismatch{in "%(\$1MsgTxt)s";} +} + +clearCounter10 { + out "CC 9"; + in; + out "CC 10"; + in; + @mismatch{in "%(\$1MsgTxt)s";} +} + +startWithCountPreset { + out "MP %d"; + in; + @mismatch{in "%(\$1MsgTxt)s";} +} + +startWithTimePreset { + out "TP %#.2f"; + in; + @mismatch{in "%(\$1MsgTxt)s";} +} + +setMinRate{ + out "DL \$2 %.3f"; + in; + @mismatch{in "%(\$1MsgTxt)s";} +} + +readMinRate{ + out "DL %(\$1THRESHOLD-MONITOR_RBV)d"; + in "%f"; + @mismatch{in "%(\$1MsgTxt)s";} +} + +setRateMonitor{ + out "DR %d"; + in; + @mismatch{in "%(\$1MsgTxt)s";} +} + +readRateMonitor{ + out "DR"; + in "%d"; + @mismatch{in "%(\$1MsgTxt)s";} +} + +################################################################################ +# Read Values From Monitors + +readAll4 { + out "RA"; + in "%(\$1ELAPSED-TIME)f %(\$1M1)d %(\$1M2)d %(\$1M3)d %(\$1M4)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"; + @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"; + # At least on the sinqtest variant this is broken + # requiring channels 9 and 10 to be manually queried + out "RC 9"; + in "%(\$1M9)d"; + out "RC 10"; + in "%(\$1M10)d"; + @mismatch{in "%(\$1MsgTxt)s";} +} + +readRate { + out "RR \$2"; + in "%f"; + @mismatch{in "%(\$1MsgTxt)s";} +} + +################################################################################ +# Testing Commands + +switchTestgenOnOff { + out "TG %{off|on}"; + @mismatch{in "%(\$1MsgTxt)s";} +} + +# Only suppporting test channel 1 at the moment. (The first argument to TG) +setTestSignal { + out "TG 1 %(\$1TESTGEN-HIGHRATE)d %(\$1TESTGEN-LOWRATE)d"; + @mismatch{in "%(\$1MsgTxt)s";} +} + +################################################################################ +# Gating Settings + +getGateStatus { + out "GT \$2"; + in "%d %(\$1GATE-\$2-TRIG_RBV)d"; + @mismatch{in "%(\$1MsgTxt)s";} +} + +setGateStatus { + extrainput = ignore; + out "GT \$2 %(\$1GATE-\$2-ENABLE)d %(\$1GATE-\$2-TRIG)d"; + in "Gate \$2"; + @mismatch{in "%(\$1MsgTxt)s";} +} + +setGate { + out "GATE \$2 %d"; + in ""; + @mismatch{in "%(\$1MsgTxt)s";} +} + +################################################################################ +# TODO To clean + +startWithCountPreset4 { + clearTimer; + clearCounter4; + readAll4; + startWithCountPreset; +} + +startWithCountPreset8 { + clearTimer; + clearCounter4; + clearCounter8; + readAll8; + startWithCountPreset; +} + +startWithCountPreset10 { + clearTimer; + clearCounter4; + clearCounter8; + clearCounter10; + readAll10; + startWithCountPreset; +} + +startWithTimePreset4 { + clearTimer; + clearCounter4; + readAll4; + startWithTimePreset; +} + +startWithTimePreset8 { + clearTimer; + clearCounter4; + clearCounter8; + readAll8; + startWithTimePreset; +} + +startWithTimePreset10 { + clearTimer; + clearCounter4; + clearCounter8; + clearCounter10; + readAll10; + startWithTimePreset; +} diff --git a/db/daq_2nd_gen.db b/db/daq_2nd_gen.db new file mode 100644 index 0000000..f5f2af9 --- /dev/null +++ b/db/daq_2nd_gen.db @@ -0,0 +1,78 @@ +# EPICS Database for streamdevice support for functionality specific to the 2nd +# Generation Systems +# +# Macros +# INSTR - Prefix +# NAME - the device name, e.g. DAQV2 +# PROTO - Stream device protocol file +# ASYN_PORT - Low level Asyn IP Port to DAQ + +################################################################################ +# Status Variables + +record(longout, "$(INSTR)$(NAME):MONITOR-CHANNEL") +{ + field(DESC, "PRESET-COUNT Monitors this channel") + field(DRVL, "1") # Smallest Monitor Channel + field(DRVH, "$(CHANNELS)") # Largest Monitor Channel + field(DTYP, "stream") + field(OUT, "@$(PROTO) writePresetMonitor($(INSTR)$(NAME):) $(ASYN_PORT)") + field(FLNK, "$(INSTR)$(NAME):MONITOR-CHANNEL_RBV") +} + +record(longin, "$(INSTR)$(NAME):MONITOR-CHANNEL_RBV") +{ + field(DESC, "PRESET-COUNT Monitors this channel") + field(DTYP, "stream") + field(INP, "@$(PROTO) readPresetMonitor($(INSTR)$(NAME):) $(ASYN_PORT)") + field(SCAN, "1 second") +} + +# Force back to 1 if it is 0, as 0 has no meaning... +record(seq, "$(INSTR)$(NAME):CORRECT-MONITOR-CHANNEL") +{ + field(SELM, "Specified") + field(SELL, "$(INSTR)$(NAME):MONITOR-CHANNEL_RBV.VAL NPP") + field(DO0, 1) + field(LNK0, "$(INSTR)$(NAME):MONITOR-CHANNEL PP") + field(SCAN, ".5 second") +} + +################################################################################ +# 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") +{ + field(OMSL, "supervisory") + field(SELM, "All") + field(OUTA, "$(INSTR)$(NAME):THRESHOLD-F1 PP") + field(OUTB, "$(INSTR)$(NAME):THRESHOLD-F2 PP") +} + +record(dfanout,"$(INSTR)$(NAME):THRESHOLD-F1") +{ + 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") +} + +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_2nd_gen_test.db b/db/daq_2nd_gen_test.db new file mode 100644 index 0000000..68d3a7c --- /dev/null +++ b/db/daq_2nd_gen_test.db @@ -0,0 +1,40 @@ +# EPICS Database for streamdevice support for testing functionality specific to +# the 2nd Generation Systems +# +# Macros +# INSTR - Prefix +# NAME - the device name, e.g. DAQV2 +# PROTO - Stream device protocol file +# ASYN_PORT - Low level Asyn IP Port to DAQ + +################################################################################ +# Testing Commands + +# These won't match the values on the machine after a full restart But I chose +# not to force their intialisation as they are only important for testing + +record(bo, "$(INSTR)$(NAME):TESTGEN") +{ + field(DESC, "Turn on/off Testgen Signal") + field(DTYP, "stream") + field(OUT, "@$(PROTO) switchTestgenOnOff($(INSTR)$(NAME):) $(ASYN_PORT)") + field(VAL, 0) + field(ZNAM, "OFF") + field(ONAM, "ON") +} + +record(longout, "$(INSTR)$(NAME):TESTGEN-LOWRATE") +{ + field(DESC, "Set Minimum Testgen Rate") + field(DTYP, "stream") + field(OUT, "@$(PROTO) setTestSignal($(INSTR)$(NAME):) $(ASYN_PORT)") + field(VAL, 1000) +} + +record(longout, "$(INSTR)$(NAME):TESTGEN-HIGHRATE") +{ + field(DESC, "Set Maximum Testgen Rate") + field(DTYP, "stream") + field(OUT, "@$(PROTO) setTestSignal($(INSTR)$(NAME):) $(ASYN_PORT)") + field(VAL, 1000) +} diff --git a/db/daq_4ch.db b/db/daq_4ch.db new file mode 100644 index 0000000..193a01a --- /dev/null +++ b/db/daq_4ch.db @@ -0,0 +1,45 @@ +# EPICS Database for streamdevice support 1st gen systems with 4 channels +# +# Macros +# INSTR - Prefix +# NAME - the device name, e.g. EL737 +# PROTO - Stream device protocol file +# ASYN_PORT - Low level Asyn IP Port to DAQ + +################################################################################ +# Status Variables + +record(longout, "$(INSTR)$(NAME):MONITOR-CHANNEL") +{ + field(DESC, "PRESET-COUNT Monitors this channel") + field(VAL, 1) + field(DRVL, "1") # Smallest Monitor Channel + field(DRVH, "1") # Largest Monitor Channel + field(DISP, 1) +} + +record(longin, "$(INSTR)$(NAME):MONITOR-CHANNEL_RBV") +{ + 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") +{ + 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") +} + +################################################################################ +# Read all monitors values diff --git a/db/daq_8ch.db b/db/daq_8ch.db new file mode 100644 index 0000000..c770a7d --- /dev/null +++ b/db/daq_8ch.db @@ -0,0 +1,49 @@ +# EPICS Database for streamdevice support 1st gen systems with 8 channels +# +# Macros +# INSTR - Prefix +# NAME - the device name, e.g. EL737 +# PROTO - Stream device protocol file +# ASYN_PORT - Low level Asyn IP Port to DAQ + +################################################################################ +# Status Variables + +record(longout, "$(INSTR)$(NAME):MONITOR-CHANNEL") +{ + field(DESC, "PRESET-COUNT Monitors this channel") + field(VAL, 1) + field(DRVL, "1") # Smallest Monitor Channel + field(DRVH, "1") # Largest Monitor Channel + field(DISP, 1) +} + +record(longin, "$(INSTR)$(NAME):MONITOR-CHANNEL_RBV") +{ + 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") +{ + 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") +} + +################################################################################ +# Read all monitors values diff --git a/db/daq_common.db b/db/daq_common.db new file mode 100644 index 0000000..fa86c65 --- /dev/null +++ b/db/daq_common.db @@ -0,0 +1,243 @@ +# 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. +record(longin, "$(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(calc, "$(INSTR)$(NAME):MAP-STATUS") +{ + field(DESC, "Maps Raw Status to State") + field(INPA, "$(INSTR)$(NAME):RAW-STATUS NPP") + field(INPB, "$(INSTR)$(NAME):INVALID-CONFIG NPP") + field(INPC, "$(INSTR)$(NAME):RAW-STATUS.UDF NPP") # should also be invalid if can't read the status + field(CALC, "(B=1||C==1)?4:A=0?0:(A=1||A=2)?1:(A=5||A=6)?2:(A=9||A=13||A=10||A=14)?3:4") + field(FLNK, "$(INSTR)$(NAME):STATUS") +} + +record(mbbi, "$(INSTR)$(NAME):STATUS") +{ + field(DESC, "DAQ Status") + field(INP, "$(INSTR)$(NAME):MAP-STATUS NPP") + 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") +} + +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 + +record(ao,"$(INSTR)$(NAME):PRESET-COUNT") +{ + 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") +} + +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(DTYP, "stream") + field(SCAN, "1 second") + 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") +} + +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") +} diff --git a/db/daq_simcontrol.db b/db/daq_simcontrol.db new file mode 100644 index 0000000..53e5ca0 --- /dev/null +++ b/db/daq_simcontrol.db @@ -0,0 +1,27 @@ +# Sinq DAQ EPICS Database for StreamDevice Communication with Simulation +# Macros +# +# INSTR - Prefix +# NAME - just a name, e.g. EL737 +# PROTO - Stream device protocol file +# ASYN_PORT - Low level Asyn IP Port to EL737 + +################################################################################ + +record(bo, "$(INSTR)$(NAME):G1") +{ + field(DESC, "Set Gate 1 Low/High") + field(ZNAM, "Low") + field(ONAM, "High") + field(DTYP, "stream") + field(OUT, "@$(PROTO) setGate($(INSTR)$(NAME):, 1) $(ASYN_PORT)") +} + +record(bo, "$(INSTR)$(NAME):G2") +{ + field(DESC, "Set Gate 2 Low/High") + field(ZNAM, "Low") + field(ONAM, "High") + field(DTYP, "stream") + field(OUT, "@$(PROTO) setGate($(INSTR)$(NAME):, 2) $(ASYN_PORT)") +} diff --git a/db/gating_channels.db b/db/gating_channels.db new file mode 100644 index 0000000..248e609 --- /dev/null +++ b/db/gating_channels.db @@ -0,0 +1,102 @@ +# EPICS Database for streamdevice specific to gating channels +# +# Macros +# INSTR - Prefix +# NAME - the device name, e.g. EL737 +# PROTO - Stream device protocol file +# ASYN_PORT - Low level Asyn IP Port to DAQ +# CHANNEL - the number associated with the measurment channel + +################################################################################ + +# Records for configuring gating settings +record(mbbo, "$(INSTR)$(NAME):GATE-$(CHANNEL)") +{ + field(DESC, "Sets the current gate state") + field(DTYP, "Soft Channel") + field(OUT, "$(INSTR)$(NAME):GATE-$(CHANNEL)-SET PP") + field(ZRST, "Disabled") + field(ONST, "Trigger Low") + field(TWST, "Trigger High") +} + +record(dfanout, "$(INSTR)$(NAME):GATE-$(CHANNEL)-SET") +{ + field(OUTA, "$(INSTR)$(NAME):GATE-$(CHANNEL)-SEL.SELN PP") + field(OUTB, "$(INSTR)$(NAME):GATE-$(CHANNEL)-SEL2.SELN PP") +} + +record(seq, "$(INSTR)$(NAME):GATE-$(CHANNEL)-SEL") +{ + field(SELM, "Specified") + field(DO0, 0) + field(LNK0, "$(INSTR)$(NAME):GATE-$(CHANNEL)-ENABLE PP") + field(DO1, 1) + field(LNK1, "$(INSTR)$(NAME):GATE-$(CHANNEL)-ENABLE PP") + field(DO2, 1) + field(LNK2, "$(INSTR)$(NAME):GATE-$(CHANNEL)-ENABLE PP") +} + +record(bo, "$(INSTR)$(NAME):GATE-$(CHANNEL)-ENABLE") +{ + field(DESC, "Enable Gating Channel") + field(ZNAM, "Disabled") + field(ONAM, "Enabled") + field(DTYP, "stream") + field(OUT, "@$(PROTO) setGateStatus($(INSTR)$(NAME):, $(CHANNEL)) $(ASYN_PORT)") +} + +record(seq, "$(INSTR)$(NAME):GATE-$(CHANNEL)-SEL2") +{ + field(SELM, "Specified") + field(DO1, 0) + field(LNK1, "$(INSTR)$(NAME):GATE-$(CHANNEL)-TRIG PP") + field(DO2, 1) + field(LNK2, "$(INSTR)$(NAME):GATE-$(CHANNEL)-TRIG PP") +} + +record(bo, "$(INSTR)$(NAME):GATE-$(CHANNEL)-TRIG") +{ + field(DESC, "Set Count when first Gate high/low") + field(ZNAM, "Low") + field(ONAM, "High") + field(DTYP, "stream") + field(OUT, "@$(PROTO) setGateStatus($(INSTR)$(NAME):, $(CHANNEL)) $(ASYN_PORT)") +} + +# Records for reading configured gating settings +record(mbbi, "$(INSTR)$(NAME):GATE-$(CHANNEL)_RBV") +{ + field(DESC, "The current gate state") + field(ZRST, "Disabled") + field(ONST, "Trigger Low") + field(TWST, "Trigger High") +} + +record(calcout, "$(INSTR)$(NAME):GATE-$(CHANNEL)-SEL_RBV") +{ + field(INPA, "$(INSTR)$(NAME):GATE-$(CHANNEL)-ENABLE_RBV NPP") + field(INPB, "$(INSTR)$(NAME):GATE-$(CHANNEL)-TRIG_RBV NPP") + field(CALC, "A=0?0:B=0?1:2") + field(OOPT, "On Change") + field(OUT, "$(INSTR)$(NAME):GATE-$(CHANNEL)_RBV PP") + field(FLNK, "$(INSTR)$(NAME):GATE-$(CHANNEL)_RBV") +} + +record(bi, "$(INSTR)$(NAME):GATE-$(CHANNEL)-ENABLE_RBV") +{ + field(DESC, "Is Gating Channel Enabled") + field(ZNAM, "Disabled") + field(ONAM, "Enabled") + field(DTYP, "stream") + field(INP, "@$(PROTO) getGateStatus($(INSTR)$(NAME):, $(CHANNEL)) $(ASYN_PORT)") + field(SCAN, "2 second") + field(FLNK, "$(INSTR)$(NAME):GATE-$(CHANNEL)-SEL_RBV") +} + +record(bi, "$(INSTR)$(NAME):GATE-$(CHANNEL)-TRIG_RBV") +{ + field(DESC, "Count when first Gate high/low") + field(ZNAM, "Low") + field(ONAM, "High") +} diff --git a/scripts/counterbox_4ch.cmd b/scripts/counterbox_4ch.cmd deleted file mode 100644 index e04fb80..0000000 --- a/scripts/counterbox_4ch.cmd +++ /dev/null @@ -1,22 +0,0 @@ -require asyn -require stream - -epicsEnvSet("$(NAME)_CNTBOX_HOST", "$(CNTBOX_IP):$(CNTBOX_PORT)") - -$(SET_SIM_MODE=#) $(SET_SIM_MODE) require misc -$(SET_SIM_MODE=#) $(SET_SIM_MODE) epicsEnvSet("$(NAME)_CNTBOX_HOST", "127.0.0.1:$(CNTBOX_PORT)") -$(SET_SIM_MODE=#) $(SET_SIM_MODE) system "$(counterbox_DIR)counterbox_sim.py $(CNTBOX_PORT) 4 &" -# starting the python socket seems to take a while -# and need misc to use built in sleep command -$(SET_SIM_MODE=#) $(SET_SIM_MODE) sleep 3 - -epicsEnvSet("PROTO", "$(counterbox_DB)counterbox.proto") -drvAsynIPPortConfigure("ASYN_$(NAME)", "$($(NAME)_CNTBOX_HOST)", 0, 0, 0) -dbLoadRecords("$(counterbox_DB)counterbox_common.db", "P=$(PREFIX), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNELS=4") -dbLoadRecords("$(counterbox_DB)counterbox_4ch.db", "P=$(PREFIX), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME)") - -# Could also use substitions instead. -dbLoadRecords("$(counterbox_DB)channels.db", "P=$(PREFIX), NAME=$(NAME), CHANNEL=1") -dbLoadRecords("$(counterbox_DB)channels.db", "P=$(PREFIX), NAME=$(NAME), CHANNEL=2") -dbLoadRecords("$(counterbox_DB)channels.db", "P=$(PREFIX), NAME=$(NAME), CHANNEL=3") -dbLoadRecords("$(counterbox_DB)channels.db", "P=$(PREFIX), NAME=$(NAME), CHANNEL=4") diff --git a/scripts/counterbox_8ch.cmd b/scripts/counterbox_8ch.cmd deleted file mode 100644 index 7dfbff2..0000000 --- a/scripts/counterbox_8ch.cmd +++ /dev/null @@ -1,26 +0,0 @@ -require asyn -require stream - -epicsEnvSet("$(NAME)_CNTBOX_HOST", "$(CNTBOX_IP):$(CNTBOX_PORT)") - -$(SET_SIM_MODE=#) $(SET_SIM_MODE) require misc -$(SET_SIM_MODE=#) $(SET_SIM_MODE) epicsEnvSet("$(NAME)_CNTBOX_HOST", "127.0.0.1:$(CNTBOX_PORT)") -$(SET_SIM_MODE=#) $(SET_SIM_MODE) system "$(counterbox_DIR)counterbox_sim.py $(CNTBOX_PORT) 10 &" -# starting the python socket seems to take a while -# and need misc to use built in sleep command -$(SET_SIM_MODE=#) $(SET_SIM_MODE) sleep 3 - -epicsEnvSet("PROTO", "$(counterbox_DB)counterbox.proto") -drvAsynIPPortConfigure("ASYN_$(NAME)", "$($(NAME)_CNTBOX_HOST)", 0, 0, 0) -dbLoadRecords("$(counterbox_DB)counterbox_common.db", "P=$(PREFIX), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNELS=8") -dbLoadRecords("$(counterbox_DB)counterbox_8ch.db", "P=$(PREFIX), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME)") - -# Could also use substitions instead. -dbLoadRecords("$(counterbox_DB)channels.db", "P=$(PREFIX), NAME=$(NAME), CHANNEL=1") -dbLoadRecords("$(counterbox_DB)channels.db", "P=$(PREFIX), NAME=$(NAME), CHANNEL=2") -dbLoadRecords("$(counterbox_DB)channels.db", "P=$(PREFIX), NAME=$(NAME), CHANNEL=3") -dbLoadRecords("$(counterbox_DB)channels.db", "P=$(PREFIX), NAME=$(NAME), CHANNEL=4") -dbLoadRecords("$(counterbox_DB)channels.db", "P=$(PREFIX), NAME=$(NAME), CHANNEL=5") -dbLoadRecords("$(counterbox_DB)channels.db", "P=$(PREFIX), NAME=$(NAME), CHANNEL=6") -dbLoadRecords("$(counterbox_DB)channels.db", "P=$(PREFIX), NAME=$(NAME), CHANNEL=7") -dbLoadRecords("$(counterbox_DB)channels.db", "P=$(PREFIX), NAME=$(NAME), CHANNEL=8") diff --git a/scripts/counterbox_v2.cmd b/scripts/counterbox_v2.cmd deleted file mode 100644 index da4ea6d..0000000 --- a/scripts/counterbox_v2.cmd +++ /dev/null @@ -1,30 +0,0 @@ -require asyn -require stream - -epicsEnvSet("$(NAME)_CNTBOX_HOST", "$(CNTBOX_IP):$(CNTBOX_PORT=2000)") - -$(SET_SIM_MODE=#) $(SET_SIM_MODE) require misc -$(SET_SIM_MODE=#) $(SET_SIM_MODE) epicsEnvSet("$(NAME)_CNTBOX_HOST", "127.0.0.1:$(CNTBOX_PORT=2000)") -$(SET_SIM_MODE=#) $(SET_SIM_MODE) system "$(counterbox_DIR)counterbox_sim.py $(CNTBOX_PORT=2000) 10 &" -# starting the python socket seems to take a while -# and need misc to use built in sleep command -$(SET_SIM_MODE=#) $(SET_SIM_MODE) sleep 3 - -epicsEnvSet("PROTO", "$(counterbox_DB)counterbox.proto") -drvAsynIPPortConfigure("ASYN_$(NAME)", "$($(NAME)_CNTBOX_HOST)", 0, 0, 0) -dbLoadRecords("$(counterbox_DB)counterbox_common.db", "P=$(PREFIX), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNELS=10") -dbLoadRecords("$(counterbox_DB)counterbox_v2.db", "P=$(PREFIX), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME)") - -# Could also use substitions instead. -dbLoadRecords("$(counterbox_DB)channels.db", "P=$(PREFIX), NAME=$(NAME), CHANNEL=1") -dbLoadRecords("$(counterbox_DB)channels.db", "P=$(PREFIX), NAME=$(NAME), CHANNEL=2") -dbLoadRecords("$(counterbox_DB)channels.db", "P=$(PREFIX), NAME=$(NAME), CHANNEL=3") -dbLoadRecords("$(counterbox_DB)channels.db", "P=$(PREFIX), NAME=$(NAME), CHANNEL=4") -dbLoadRecords("$(counterbox_DB)channels.db", "P=$(PREFIX), NAME=$(NAME), CHANNEL=5") -dbLoadRecords("$(counterbox_DB)channels.db", "P=$(PREFIX), NAME=$(NAME), CHANNEL=6") -dbLoadRecords("$(counterbox_DB)channels.db", "P=$(PREFIX), NAME=$(NAME), CHANNEL=7") -dbLoadRecords("$(counterbox_DB)channels.db", "P=$(PREFIX), NAME=$(NAME), CHANNEL=8") -dbLoadRecords("$(counterbox_DB)channels.db", "P=$(PREFIX), NAME=$(NAME), CHANNEL=9") -dbLoadRecords("$(counterbox_DB)channels.db", "P=$(PREFIX), NAME=$(NAME), CHANNEL=10") - -$(LOAD_TEST_PVS=#) $(LOAD_TEST_PVS) dbLoadRecords("$(counterbox_DB)counterbox_v2_test.db", "P=$(PREFIX), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME)") diff --git a/scripts/daq_2nd_gen.cmd b/scripts/daq_2nd_gen.cmd new file mode 100644 index 0000000..25f576b --- /dev/null +++ b/scripts/daq_2nd_gen.cmd @@ -0,0 +1,35 @@ +require asyn +require stream + +epicsEnvSet("$(NAME)_DAQ_HOST", "$(DAQ_IP):$(DAQ_PORT=2000)") + +$(SET_SIM_MODE=#) $(SET_SIM_MODE) require misc +$(SET_SIM_MODE=#) $(SET_SIM_MODE) epicsEnvSet("$(NAME)_DAQ_HOST", "127.0.0.1:$(DAQ_PORT=2000)") +$(SET_SIM_MODE=#) $(SET_SIM_MODE) system "$(sinqDAQ_DIR)daq_sim.py $(DAQ_PORT=2000) 10 &" +# starting the python socket seems to take a while +# and need misc to use built in sleep command +$(SET_SIM_MODE=#) $(SET_SIM_MODE) sleep 3 + +epicsEnvSet("PROTO", "$(sinqDAQ_DB)daq.proto") +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") +dbLoadRecords("$(sinqDAQ_DB)daq_2nd_gen.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNELS=10") + +# 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") +dbLoadRecords("$(sinqDAQ_DB)channels.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNEL=3") +dbLoadRecords("$(sinqDAQ_DB)channels.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNEL=4") +dbLoadRecords("$(sinqDAQ_DB)channels.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNEL=5") +dbLoadRecords("$(sinqDAQ_DB)channels.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNEL=6") +dbLoadRecords("$(sinqDAQ_DB)channels.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNEL=7") +dbLoadRecords("$(sinqDAQ_DB)channels.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNEL=8") +dbLoadRecords("$(sinqDAQ_DB)channels.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNEL=9") +dbLoadRecords("$(sinqDAQ_DB)channels.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNEL=10") + +dbLoadRecords("$(sinqDAQ_DB)gating_channels.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNEL=1") +dbLoadRecords("$(sinqDAQ_DB)gating_channels.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNEL=2") + +$(LOAD_TEST_PVS=#) $(LOAD_TEST_PVS) dbLoadRecords("$(sinqDAQ_DB)daq_2nd_gen_test.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME)") + +$(SET_SIM_MODE=#) $(SET_SIM_MODE) dbLoadRecords("$(sinqDAQ_DB)daq_simcontrol.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME)") diff --git a/scripts/daq_4ch.cmd b/scripts/daq_4ch.cmd new file mode 100644 index 0000000..6c43c94 --- /dev/null +++ b/scripts/daq_4ch.cmd @@ -0,0 +1,22 @@ +require asyn +require stream + +epicsEnvSet("$(NAME)_DAQ_HOST", "$(DAQ_IP):$(DAQ_PORT)") + +$(SET_SIM_MODE=#) $(SET_SIM_MODE) require misc +$(SET_SIM_MODE=#) $(SET_SIM_MODE) epicsEnvSet("$(NAME)_DAQ_HOST", "127.0.0.1:$(DAQ_PORT)") +$(SET_SIM_MODE=#) $(SET_SIM_MODE) system "$(sinqDAQ_DIR)daq_sim.py $(DAQ_PORT) 4 &" +# starting the python socket seems to take a while +# and need misc to use built in sleep command +$(SET_SIM_MODE=#) $(SET_SIM_MODE) sleep 3 + +epicsEnvSet("PROTO", "$(sinqDAQ_DB)daq.proto") +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") +dbLoadRecords("$(sinqDAQ_DB)daq_4ch.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") +dbLoadRecords("$(sinqDAQ_DB)channels.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNEL=3") +dbLoadRecords("$(sinqDAQ_DB)channels.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNEL=4") diff --git a/scripts/daq_8ch.cmd b/scripts/daq_8ch.cmd new file mode 100644 index 0000000..1ac5187 --- /dev/null +++ b/scripts/daq_8ch.cmd @@ -0,0 +1,26 @@ +require asyn +require stream + +epicsEnvSet("$(NAME)_DAQ_HOST", "$(DAQ_IP):$(DAQ_PORT)") + +$(SET_SIM_MODE=#) $(SET_SIM_MODE) require misc +$(SET_SIM_MODE=#) $(SET_SIM_MODE) epicsEnvSet("$(NAME)_DAQ_HOST", "127.0.0.1:$(DAQ_PORT)") +$(SET_SIM_MODE=#) $(SET_SIM_MODE) system "$(sinqDAQ_DIR)daq_sim.py $(DAQ_PORT) 8 &" +# starting the python socket seems to take a while +# and need misc to use built in sleep command +$(SET_SIM_MODE=#) $(SET_SIM_MODE) sleep 3 + +epicsEnvSet("PROTO", "$(sinqDAQ_DB)daq.proto") +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") +dbLoadRecords("$(sinqDAQ_DB)daq_8ch.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") +dbLoadRecords("$(sinqDAQ_DB)channels.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNEL=3") +dbLoadRecords("$(sinqDAQ_DB)channels.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNEL=4") +dbLoadRecords("$(sinqDAQ_DB)channels.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNEL=5") +dbLoadRecords("$(sinqDAQ_DB)channels.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNEL=6") +dbLoadRecords("$(sinqDAQ_DB)channels.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNEL=7") +dbLoadRecords("$(sinqDAQ_DB)channels.db", "INSTR=$(INSTR), NAME=$(NAME), PROTO=$(PROTO), ASYN_PORT=ASYN_$(NAME), CHANNEL=8") diff --git a/sim/counterbox_sim.py b/sim/counterbox_sim.py deleted file mode 100644 index 6f6755a..0000000 --- a/sim/counterbox_sim.py +++ /dev/null @@ -1,146 +0,0 @@ -#!/usr/bin/env python3 - -import re -import socket -import sys -import time - -from random import randrange - -HOST = "127.0.0.1" # Localhost -PORT = int(sys.argv[1]) # Port to listen on -TOTAL_CH = int(sys.argv[2]) # Number of Channels - - -class CounterBox: - def __init__(self, total_channels): - self.total_channels = total_channels - self.counts = [0] * self.total_channels - - self.status = 0 - self.countmode = 'time' - self.presettime = 0 - self.presetcount = 0 - self.starttime = 0 - self.elapsed = 0 - self.monitor = 0 - - def resetCounts(self): - self.counts = [0] * self.total_channels - self.starttime = time.time() - self.elapsed = 0 - - def getStatus(self): - return self.status - - def getCounts(self): - return self.counts - - def getMonitorCount(self): - return self.counts[self.monitor] - - def updateCounts(self): - for i in range(self.total_channels): - self.counts[i] += randrange(5) - - def getRunTime(self): - elapsed = round(time.time() - self.starttime, 3) - - if self.countmode == 'time': - if elapsed < self.presettime: - self.updateCounts() - self.elapsed = elapsed - else: - self.elapsed = self.presettime - self.status = 0 - - elif self.countmode == 'count': - if self.getMonitorCount() < self.presetcount: - self.updateCounts() - self.elapsed = elapsed - - if self.getMonitorCount() >= self.presetcount: - self.counts[self.monitor] = self.presetcount - self.status = 0 - - else: - raise Exception("Invalid State") - - return self.elapsed - - def startTimePreset(self, presettime): - self.countmode = 'time' - self.status = 1 - self.presettime = round(presettime, 3) - self.resetCounts() - - def startCountPreset(self, presetcount): - self.countmode = 'count' - self.status = 1 - self.presetcount = presetcount - self.resetCounts() - -with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: - - s.bind((HOST, PORT)) - s.listen() - conn, addr = s.accept() - with conn: - - def send(data: str): - if data: - return conn.sendall(f'{data}\r'.encode()) - else: - return conn.sendall(b'\r') - - def receive(): - data = conn.recv(1024) - if data: - # also removes terminator - return data.decode('ascii').rstrip() - else: - return '' - - counterbox = CounterBox(TOTAL_CH) - - while True: - - data = receive() - - if not data: # Empty implies client disconnected - break # Close Server - - try: - - if data == 'RMT 1': - send('') - - elif data == 'ECHO 2': - send('Counterbox') # Sends some sort of info command - - elif data == 'RA': - send( - ' '.join(map(str, - [counterbox.getRunTime()] + \ - counterbox.getCounts() - )) - ) - - elif data == 'RS': - send(str(counterbox.getStatus())) - - elif re.fullmatch(r'TP (\d+(\.\d+)?)', data): - presettime = float(re.fullmatch(r'TP (\d+(\.\d+)?)', data).group(1)) - counterbox.startTimePreset(presettime) - send('') - - elif re.fullmatch(r'MP (\d+)', data): - counts = int(re.fullmatch(r'MP (\d+)', data).group(1)) - counterbox.startCountPreset(counts) - send('') - - else: - send('?2') # Bad command - - except: - send('?OV') diff --git a/sim/daq_sim.py b/sim/daq_sim.py new file mode 100644 index 0000000..627a1c6 --- /dev/null +++ b/sim/daq_sim.py @@ -0,0 +1,331 @@ +#!/usr/bin/env python3 + +import os +import re +import socket +import sys +import time + +from random import randrange + +HOST = "127.0.0.1" # Localhost +PORT = int(sys.argv[1]) # Port to listen on +TOTAL_CH = int(sys.argv[2]) # Number of Channels +LOG2FILE = False if len(sys.argv) < 4 else bool(int(sys.argv[3])) + +import logging +logger = logging.getLogger('daq') + +if LOG2FILE: + logging.basicConfig(filename=os.path.join(os.getcwd(), 'daq_sim.log'), level=logging.INFO) + + +class DAQ: + def __init__(self, total_channels): + self.total_channels = total_channels + self.counts = [0] * self.total_channels + self.rates = [randrange(5) for i in range(self.total_channels)] + + self.status = 0 + self.countmode = 'time' + self.presettime = 0 + self.presetcount = 0 + self.starttime = 0 + self.elapsed = 0 + self.monitor = 0 + + self.minratechannel = 0 + self.minrates = [2] * self.total_channels + + self.gate_config = [ + #(enabled, count high/low), + ( False, True), + ( False, True), + ] + + self.gate = [ + # high/low + False, + False, + ] + + def clearCount(self, counter): + self.counts[counter-1] = 0 + + def clearCounts(self): + self.counts = [0] * self.total_channels + + def clearTime(self): + self.elapsed = 0 + self.starttime = time.time() + + def getStatus(self): + return self.status + + def getCount(self, channel): + return self.counts[channel - 1] + + def getCounts(self): + # The sinqtest daq returns a maximum of 8 + return self.counts[0:min(len(self.counts), 8)] + + def getMonitorCount(self): + return self.counts[self.monitor] + + def updateRates(self): + for i in range(self.total_channels): + self.rates[i] = randrange(5) + + def updateCounts(self): + for i in range(self.total_channels): + self.counts[i] += self.rates[i] + + def getRunTime(self): + elapsed = round(time.time() - self.starttime, 3) + self.updateRates() + + # If gating and a low rate threshold are enabled, then the threshold + # seems to have precedence and sets the status to 5. + # If we are waiting on the gate, then the status is just 1 as normal + # after having started a count. + + if self.countmode == 'time': + if elapsed < self.presettime: + + if self.minratechannel >= 0 and self.rates[self.minratechannel] < self.minrates[self.minratechannel]: + # adjust the starttime, so that it is as if this polling period didn't happen + self.starttime += elapsed - self.elapsed + self.status = 5 + return self.elapsed + + self.status = 1 + + for i in range(len(self.gate)): + # If the gating is enabled and the signal is in the active position + if self.gate_config[i][0] and self.gate_config[i][1] != self.gate[i]: + self.starttime += elapsed - self.elapsed + return self.elapsed + + self.updateCounts() + self.elapsed = elapsed + else: + self.elapsed = self.presettime if self.presettime > 0 else self.elapsed + self.status = 0 + + elif self.countmode == 'count': + if self.getMonitorCount() < self.presetcount: + + if self.minratechannel >= 0 and self.rates[self.minratechannel] < self.minrates[self.minratechannel]: + # adjust the starttime, so that it is as if this polling period didn't happen + self.starttime += elapsed - self.elapsed + self.status = 5 + return self.elapsed + + self.status = 1 + + for i in range(len(self.gate)): + # If the gating is enabled and the signal is in the active position + if self.gate_config[i][0] and self.gate_config[i][1] != self.gate[i]: + self.starttime += elapsed - self.elapsed + return self.elapsed + + self.updateCounts() + self.elapsed = elapsed + + if self.getMonitorCount() >= self.presetcount: + self.counts[self.monitor] = self.presetcount if self.presetcount > 0 else self.counts[self.monitor] + self.status = 0 + + else: + raise Exception("Invalid State") + + return self.elapsed + + def stop(self): + self.getRunTime() + self.status = 0 + self.presettime = 0 + self.presetcount = 0 + + def startTimePreset(self, presettime): + self.countmode = 'time' + self.status = 1 + self.presettime = round(presettime, 3) + self.clearTime() + self.clearCounts() + + def startCountPreset(self, presetcount): + self.countmode = 'count' + self.status = 1 + self.presetcount = presetcount + self.clearTime() + self.clearCounts() + + def setMonitorChannel(self, channel): + self.monitor = channel - 1 + + def getMonitorChannel(self): + return self.monitor + 1 + + def getRate(self, channel): + return float(self.rates[channel - 1]) + + def getMinRateChannel(self): + return self.minratechannel + 1 + + def setMinRateChannel(self, channel): + self.minratechannel = channel - 1 + + def getMinRate(self, channel): + return self.minrates[channel - 1] + + def setMinRate(self, channel, rate): + self.minrates[channel - 1] = rate + + def getGateStatus(self, channel): + return self.gate_config[channel - 1] + + def setGateStatus(self, channel, enable, highlow): + self.gate_config[channel - 1] = (enable, highlow) + + 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)) + s.listen() + conn, addr = s.accept() + with conn: + + def send(data: str): + if data: + logger.info(f'SENDING: "{data}"') + return conn.sendall(f'{data}\r'.encode()) + else: + logger.info(f'SENDING: ""') + return conn.sendall(b'\r') + + def receive(): + data = conn.recv(1024) + if data: + # also removes terminator + received = data.decode('ascii').rstrip() + else: + received = '' + logger.info(f'RECEIVED: "{received}"') + return received + + daq = DAQ(TOTAL_CH) + + while True: + + data = receive() + + if not data: # Empty implies client disconnected + break # Close Server + + try: + + if data == 'RMT 1': + send('') + + elif data == 'ECHO 2': + send('DAQ System Version Simulation') # Sends some sort of info command + + elif data == 'RA': + send( + ' '.join(map(str, + [daq.getRunTime()] + \ + daq.getCounts() + )) + ) + + elif re.fullmatch(r'RC (\d+)', data): + channel = int(re.fullmatch(r'RC (\d+)', data).group(1)) + count = daq.getCount(channel) + send(f'{count}') + + elif data == 'RS': + send(str(daq.getStatus())) + + elif data == 'S': + daq.stop() + send('') + + elif data == 'CT': + daq.clearTime() + send('') + + elif re.fullmatch(r'CC (\d+)', data): + counter = int(re.fullmatch(r'CC (\d+)', data).group(1)) + daq.clearCount(counter) + send('') + + elif re.fullmatch(r'TP (\d+(\.\d+)?)', data): + presettime = float(re.fullmatch(r'TP (\d+(\.\d+)?)', data).group(1)) + daq.startTimePreset(presettime) + send('') + + elif re.fullmatch(r'MP (\d+)', data): + counts = int(re.fullmatch(r'MP (\d+)', data).group(1)) + daq.startCountPreset(counts) + send('') + + elif data == 'PC': + send(str(daq.getMonitorChannel())) + + elif re.fullmatch(r'PC (\d+)', data): + channel = int(re.fullmatch(r'PC (\d+)', data).group(1)) + daq.setMonitorChannel(channel) + send('') + + elif data == 'DR': + send(str(daq.getMinRateChannel())) + + elif re.fullmatch(r'DR (\d+)', data): + channel = int(re.fullmatch(r'DR (\d+)', data).group(1)) + daq.setMinRateChannel(channel) + send('') + + elif re.fullmatch(r'DL (\d+)', data): + channel = int(re.fullmatch(r'DL (\d+)', data).group(1)) + send('{:.3f}'.format(daq.getMinRate(channel))) + + elif re.fullmatch(r'DL (\d+) (\d+(?:.\d+)?)', data): + channel, rate = re.fullmatch(r'DL (\d+) (\d+(?:.\d+)?)', data).groups() + daq.setMinRate(int(channel), float(rate)) + send('') + + elif re.fullmatch(r'RR (\d+)', data): + channel = int(re.fullmatch(r'RR (\d+)', data).group(1)) + send(daq.getRate(channel)) + + elif re.fullmatch(r'GT (\d+)', data): + channel = int(re.fullmatch(r'GT (\d+)', data).group(1)) + enabled, highlow = daq.getGateStatus(channel) + send(f'{int(enabled)} {int(highlow)}') + + elif re.fullmatch(r'GT (\d+) (\d+) (\d+)', data): + channel, enable, highlow = re.fullmatch(r'GT (\d+) (\d+) (\d+)', data).groups() + channel, enable, highlow = int(channel), bool(int(enable)), bool(int(highlow)) + daq.setGateStatus(channel, enable, highlow) + if enable: + send(f'Gate {channel} enabled, counting when input = {"high" if highlow else "low"}') + else: + send(f'Gate {channel} disabled') + + # Only for the simulation + elif re.fullmatch(r'GATE (\d+) (\d+)', data): + channel, highlow = re.fullmatch(r'GATE (\d+) (\d+)', data).groups() + channel, highlow = int(channel), bool(int(highlow)) + daq.setGate(channel, highlow) + send('') + + else: + send('?2') # Bad command + + except Exception as e: + logger.exception('Simulation Broke') + send('?OV') diff --git a/src/counterbox.dbd b/src/counterbox.dbd deleted file mode 100644 index 4ef690d..0000000 --- a/src/counterbox.dbd +++ /dev/null @@ -1,5 +0,0 @@ -#--------------------------------------------- -# Counterbox specific DB definitions -#--------------------------------------------- - -device(stringin,INST_IO,devCounterBoxStringError,"devCounterBoxStringError") diff --git a/src/counterbox.cpp b/src/daq.cpp similarity index 96% rename from src/counterbox.cpp rename to src/daq.cpp index 591fea3..02d2bf0 100644 --- a/src/counterbox.cpp +++ b/src/daq.cpp @@ -54,7 +54,7 @@ struct { DEVSUPFUN get_ioint_info; DEVSUPFUN read_ai; DEVSUPFUN special_linconv; -} devCounterBoxStringError = { +} devDAQStringError = { 6, NULL, NULL, NULL, NULL, (DEVSUPFUN)map_raw_failure_message, NULL}; -epicsExportAddress(dset, devCounterBoxStringError); +epicsExportAddress(dset, devDAQStringError); diff --git a/src/daq.dbd b/src/daq.dbd new file mode 100644 index 0000000..3bfdf32 --- /dev/null +++ b/src/daq.dbd @@ -0,0 +1,5 @@ +#--------------------------------------------- +# DAQ specific DB definitions +#--------------------------------------------- + +device(stringin, INST_IO, devDAQStringError, "devDAQStringError") diff --git a/test/st.cmd b/test/st.cmd index afb4067..7f55320 100755 --- a/test/st.cmd +++ b/test/st.cmd @@ -2,13 +2,13 @@ on error break -require counterbox +require sinqDAQ epicsEnvSet("STREAM_PROTOCOL_PATH","./db") -epicsEnvSet("PREFIX","SQ:TEST") +epicsEnvSet("INSTR","SQ:TEST:") epicsEnvSet("NAME","CB_TEST") -epicsEnvSet("SET_SIM_MODE","") # Run Counterbox Simulation Instead of Actual Box -runScript "$(counterbox_DIR)counterbox_v2.cmd" "CNTBOX_IP=127.0.0.1, CNTBOX_PORT=2000" +epicsEnvSet("SET_SIM_MODE","") # Run Simulation Instead of Actual Interface +runScript "$(sinqDAQ_DIR)daq_2nd_gen.cmd" "DAQ_IP=127.0.0.1, DAQ_PORT=2000" iocInit() diff --git a/test/test.py b/test/test.py index 36626cc..c7d45ff 100755 --- a/test/test.py +++ b/test/test.py @@ -40,53 +40,53 @@ def get_piped_output(proc): return stdqueue, errqueue -def getState(prefix, name): - result = run(['caget', f'{prefix}:{name}:STATUS'], stdout=PIPE) +def getState(instr, name): + result = run(['caget', f'{instr}{name}:STATUS'], stdout=PIPE) state = result.stdout.decode('ascii').rstrip().split()[1] print(f'Currently in state {state}') return state -def getCount(prefix, name, ch): - result = run(['caget', f'{prefix}:{name}:M{ch}'], stdout=PIPE) +def getCount(instr, name, ch): + result = run(['caget', f'{instr}{name}:M{ch}'], stdout=PIPE) count = int(result.stdout.decode('ascii').rstrip().split()[1]) print(f'M{ch} == {count}') return count -def presetTime(prefix, name, time): +def presetTime(instr, name, time): print(f'Starting count for {time} seconds') - run(['caput', f'{prefix}:{name}:PRESET-TIME', f'{time}']) + run(['caput', f'{instr}{name}:PRESET-TIME', f'{time}']) -def presetCount(prefix, name, count): +def presetCount(instr, name, count): print(f'Starting count until channel 1 reaches {count}') - run(['caput', f'{prefix}:{name}:PRESET-COUNT', f'{count}']) + run(['caput', f'{instr}{name}:PRESET-COUNT', f'{count}']) -def testCanCount(prefix, name): +def testCanCount(instr, name): # Check in Idle State - assert getState(prefix, name) == 'Idle', 'Not in valid state' + assert getState(instr, name) == 'Idle', 'Not in valid state' # Start Time Based Count and Check that Status Changes - assert getCount(prefix, name, 1) == 0, "Erroneous nonzero starting count value" - presetTime(prefix, name, 5) + assert getCount(instr, name, 1) == 0, "Erroneous nonzero starting count value" + presetTime(instr, name, 5) time.sleep(1) - assert getState(prefix, name) == 'Counting', 'Didn\'t start counting' + assert getState(instr, name) == 'Counting', 'Didn\'t start counting' time.sleep(5) - assert getState(prefix, name) == 'Idle', 'Didn\'t finish counting' - assert getCount(prefix, name, 1) > 0, 'No events were counted' + assert getState(instr, name) == 'Idle', 'Didn\'t finish counting' + assert getCount(instr, name, 1) > 0, 'No events were counted' # Start Monitor Based Count and Check that Status Changes presetAmount = 100 - presetCount(prefix, name, presetAmount) + presetCount(instr, name, presetAmount) time.sleep(1) - assert getState(prefix, name) == 'Counting', 'Didn\'t start counting' - assert getCount(prefix, name, 1) < presetAmount - while getState(prefix, name) != 'Idle': + assert getState(instr, name) == 'Counting', 'Didn\'t start counting' + assert getCount(instr, name, 1) < presetAmount + while getState(instr, name) != 'Idle': time.sleep(1) - assert getCount(prefix, name, 1) == presetAmount, 'Counted events not equal to preset' - assert getCount(prefix, name, 2) > 0 + assert getCount(instr, name, 1) == presetAmount, 'Counted events not equal to preset' + assert getCount(instr, name, 2) > 0 -def test(prefix, name): +def test(instr, name): - # TODO pass prefix and name to script + # TODO pass instr and name to script proc = Popen([f'{os.environ["PARENT_PATH"]}/ioc.sh'], stdout=PIPE, stderr=PIPE, shell=False) try: @@ -104,7 +104,7 @@ def test(prefix, name): print("IOC Initialisation Complete") print("Starting Tests") - testCanCount(prefix, name) + testCanCount(instr, name) print("Success") proc.kill() @@ -123,7 +123,7 @@ if __name__ == '__main__': print("Starting Test") # Test V2 - if test('SQ:TEST', 'CB_TEST'): + if test('SQ:TEST:', 'CB_TEST'): exit(0) else: exit(1)