From a336ca74c98ef76e07dca26be695d61e53a83852 Mon Sep 17 00:00:00 2001 From: Edward Wall Date: Mon, 3 Nov 2025 09:26:50 +0100 Subject: [PATCH] adds remaining missing PVs --- db/channels.db | 109 ++++++------------- db/daq_common.db | 168 ++++++++++++++---------------- src/asynStreamGeneratorDriver.cpp | 32 +++++- src/asynStreamGeneratorDriver.h | 10 ++ 4 files changed, 152 insertions(+), 167 deletions(-) diff --git a/db/channels.db b/db/channels.db index c2cde1f..bb7a3fe 100644 --- a/db/channels.db +++ b/db/channels.db @@ -9,86 +9,43 @@ ################################################################################ # 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") -# } +# 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 -# # Unfortunately, clearing the channels is somewhat complicated as a result of -# # the addition of more channels over time and minimal changes to the underlying interface -# # -# # Urs Greuter provided the following explanation: -# # -# # bei den Befehlen CC r und HC r ist der Parameter r als bit-Maske zu verstehen: -# # -# # Bit0: Zähler Channel 1 -# # Bit2: Zähler Channel 2 -# # Bit3: Zähler Channel 3 -# # Bit4: Zähler Channel 4 -# # Bit5: Zähler Channel Timer -# # Bit6: Zähler Channel 5 -# # Bit7: Zähler Channel 6 -# # Bit8: Zähler Channel 7 -# # Bit9: Zähler Channel 8 -# # -# # Beispiele: -# # CC 1 setzt den Zähler des Channels 1 zurück -# # CC 4 setzt den Zähler des Channels 3 zurück -# # CC 5 setzt gleichzeitig die Zähler der Channels 1 und 3 zurück -# # CC 16 ist gleichbedeutend wie CT (Timer zurücksetzen) -# # CC 511 setzt gleichzeitig die Zähler aller Kanäle (auch des Timers) zurück. -# -# record(calc, "$(INSTR)$(NAME):BM$(CHANNEL)") -# { -# field(DESC, "Bit Mask for Channel") -# field(INPA, $(CHANNEL)) -# field(CALC, "A > 4 ? 2 ^ A : 2 ^ (A-1)") -# field(PINI, "YES") -# } -# -# record(longout, "$(INSTR)$(NAME):C$(CHANNEL)") -# { -# field(DESC, "Clear the current channel count") -# field(DTYP, "stream") -# field(OMSL, "closed_loop") -# field(DOL, "$(INSTR)$(NAME):BM$(CHANNEL) NPP") -# field(OUT, "@... clearChannel($(INSTR)$(NAME):) $(PORT)") -# field(FLNK, "$(INSTR)$(NAME):T$(CHANNEL)") -# } -# -# record(ao,"$(INSTR)$(NAME):THRESH$(CHANNEL)") -# { -# field(DESC, "Sets min rate for counting to proceed") -# field(OMSL, "supervisory") -# field(OROC, "0") -# field(OUT, "@... setMinRate($(INSTR)$(NAME):, $(CHANNEL)) $(PORT)") -# field(DTYP, "stream") -# } +record(longout, "$(INSTR)$(NAME):C$(CHANNEL)") +{ + field(DESC, "Clear the current channel count") + field(DTYP, "asynInt32") + field(OUT, "@asyn($(PORT),0,$(TIMEOUT=1)) C_$(CHANNEL)") + field(FLNK, "$(INSTR)$(NAME):T$(CHANNEL)") +} ################################################################################ # Read all monitors values diff --git a/db/daq_common.db b/db/daq_common.db index 7c91111..96a1cd3 100644 --- a/db/daq_common.db +++ b/db/daq_common.db @@ -50,32 +50,32 @@ record(longin, "$(INSTR)$(NAME):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") -# } +# 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 @@ -116,14 +116,13 @@ record(ao,"$(INSTR)$(NAME):PRESET-TIME") # 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, "@... stopCount($(INSTR)$(NAME):) $(PORT)") -# field(FLNK, "$(INSTR)$(NAME):RAW-STATUS") -# } + +record(longout, "$(INSTR)$(NAME):STOP") +{ + field(DESC, "Stop the current counting operation") + field(DTYP, "asynInt32") + field(OUT, "@asyn($(PORT),0,$(TIMEOUT=1)) STOP") +} record(longout, "$(INSTR)$(NAME):MONITOR-CHANNEL") { @@ -143,62 +142,53 @@ record(longin, "$(INSTR)$(NAME):MONITOR-CHANNEL_RBV") field(PINI, "YES") } -# record(calc, "$(INSTR)$(NAME):RATE_MAP") -# { -# field(DESC, "Want a consistent lowrate pv") -# field(INPA, "$(INSTR)$(NAME):RAW-STATUS.B2 NPP") -# field(CALC, "(A=1)?1:0") -# } +record(ao,"$(INSTR)$(NAME):THRESHOLD") +{ + field(DESC, "Minimum rate for counting to proceed") + field(DTYP, "asynInt32") + field(OUT, "@asyn($(PORT),0,$(TIMEOUT=1)) THRESH") + field(VAL, "1") # Default Rate + field(DRVL, "1") # Minimum Rate + field(DRVH, "100000") # Maximum Rate +} -# -# 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(EGU, "cts/sec") -# field(INP, "@... readMinRate($(INSTR)$(NAME):) $(PORT)") -# field(DTYP, "stream") -# field(SCAN, "1 second") -# } -# -# 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, "@... setRateMonitor($(INSTR)$(NAME):) $(PORT)") -# field(DTYP, "stream") -# } -# -# record(longin,"$(INSTR)$(NAME):THRESHOLD-MONITOR_RBV") -# { -# field(DESC, "Channel monitored for minimum rate") -# field(EGU, "CH") -# field(INP, "@... readRateMonitor($(INSTR)$(NAME):) $(PORT)") -# field(DTYP, "stream") -# field(SCAN, "1 second") -# } -# -# record(longout, "$(INSTR)$(NAME):CT") -# { -# field(DESC, "Clear the timer") -# field(DTYP, "stream") -# field(OUT, "@... clearTimer($(INSTR)$(NAME):) $(PORT)") -# field(FLNK, "$(INSTR)$(NAME):ETT") -# } +record(ai,"$(INSTR)$(NAME):THRESHOLD_RBV") +{ + field(DESC, "Minimum rate for counting to proceed") + field(EGU, "cts/sec") + field(DTYP, "asynInt32") + field(INP, "@asyn($(PORT),0,$(TIMEOUT=1)) THRESH") + field(SCAN, "I/O Intr") + field(PINI, "YES") +} + +record(longout,"$(INSTR)$(NAME):THRESHOLD-MONITOR") +{ + field(DESC, "Channel monitored for minimum rate") + field(DTYP, "asynInt32") + field(OUT, "@asyn($(PORT),0,$(TIMEOUT=1)) THRESH_CH") + field(VAL, "1") # Monitor + field(DRVL, "0") # Smallest Threshold Channel (0 is off) + field(DRVH, "$(CHANNELS)") # Largest Threshold Channel +} + +record(longin,"$(INSTR)$(NAME):THRESHOLD-MONITOR_RBV") +{ + field(DESC, "Channel monitored for minimum rate") + field(EGU, "CH") + field(DTYP, "asynInt32") + field(INP, "@asyn($(PORT),0,$(TIMEOUT=1)) THRESH_CH") + field(SCAN, "I/O Intr") + field(PINI, "YES") +} + +record(longout, "$(INSTR)$(NAME):CT") +{ + field(DESC, "Clear the timer") + field(DTYP, "asynInt32") + field(OUT, "@asyn($(PORT),0,$(TIMEOUT=1)) C_TIME") + field(FLNK, "$(INSTR)$(NAME):ETT") +} ################################################################################ # Read all monitors values diff --git a/src/asynStreamGeneratorDriver.cpp b/src/asynStreamGeneratorDriver.cpp index 0414a0e..b9f28a2 100644 --- a/src/asynStreamGeneratorDriver.cpp +++ b/src/asynStreamGeneratorDriver.cpp @@ -99,6 +99,10 @@ asynStreamGeneratorDriver::asynStreamGeneratorDriver(const char *portName, createParam(P_ResetString, asynParamInt32, &P_Reset)); status = (asynStatus)(status | setIntegerParam(P_Reset, 0)); + status = (asynStatus)(status | + createParam(P_StopString, asynParamInt32, &P_Stop)); + status = (asynStatus)(status | setIntegerParam(P_Stop, 0)); + status = (asynStatus)(status | createParam(P_CountPresetString, asynParamInt32, &P_CountPreset)); status = (asynStatus)(status | setIntegerParam(P_CountPreset, 0)); @@ -111,15 +115,32 @@ asynStreamGeneratorDriver::asynStreamGeneratorDriver(const char *portName, asynParamInt32, &P_ElapsedTime)); status = (asynStatus)(status | setIntegerParam(P_ElapsedTime, 0)); + status = (asynStatus)(status | createParam(P_ClearElapsedTimeString, + asynParamInt32, &P_ClearElapsedTime)); + status = (asynStatus)(status | setIntegerParam(P_ClearElapsedTime, 0)); + status = (asynStatus)(status | createParam(P_MonitorChannelString, asynParamInt32, &P_MonitorChannel)); status = (asynStatus)(status | setIntegerParam(P_MonitorChannel, 0)); + status = + (asynStatus)(status | createParam(P_ThresholdString, + asynParamInt32, &P_Threshold)); + status = (asynStatus)(status | setIntegerParam(P_Threshold, 1)); + + status = + (asynStatus)(status | createParam(P_ThresholdChannelString, + asynParamInt32, &P_ThresholdChannel)); + status = (asynStatus)(status | setIntegerParam(P_ThresholdChannel, 1)); + + + // Create Parameters templated on Channel Number char pv_name_buffer[100]; P_Counts = new int[this->num_channels]; P_Rates = new int[this->num_channels]; + P_ClearCounts = new int[this->num_channels]; for (size_t i = 0; i < this->num_channels; ++i) { memset(pv_name_buffer, 0, 100); epicsSnprintf(pv_name_buffer, 100, P_CountsString, i); @@ -134,6 +155,13 @@ asynStreamGeneratorDriver::asynStreamGeneratorDriver(const char *portName, (asynStatus)(status | createParam(pv_name_buffer, asynParamInt32, P_Rates + i)); status = (asynStatus)(status | setIntegerParam(P_Rates[i], 0)); + + memset(pv_name_buffer, 0, 100); + epicsSnprintf(pv_name_buffer, 100, P_ClearCountsString, i); + status = + (asynStatus)(status | createParam(pv_name_buffer, asynParamInt32, + P_ClearCounts + i)); + status = (asynStatus)(status | setIntegerParam(P_ClearCounts[i], 0)); } if (status) { @@ -145,8 +173,8 @@ asynStreamGeneratorDriver::asynStreamGeneratorDriver(const char *portName, // Create Events this->pausedEventId = epicsEventCreate(epicsEventEmpty); - // this->monitorProducer = create_kafka_producer(); - // this->detectorProducer = create_kafka_producer(); + this->monitorProducer = create_kafka_producer(); + this->detectorProducer = create_kafka_producer(); // Setup for Thread Producing Monitor Kafka Events status = diff --git a/src/asynStreamGeneratorDriver.h b/src/asynStreamGeneratorDriver.h index f770cf1..7904a24 100644 --- a/src/asynStreamGeneratorDriver.h +++ b/src/asynStreamGeneratorDriver.h @@ -82,13 +82,18 @@ struct __attribute__((__packed__)) NormalisedDetectorEvent { #define P_StatusString "STATUS" #define P_ResetString "RESET" +#define P_StopString "STOP" #define P_CountPresetString "P_CNT" #define P_TimePresetString "P_TIME" #define P_ElapsedTimeString "TIME" +#define P_ClearElapsedTimeString "C_TIME" #define P_MonitorChannelString "MONITOR" +#define P_ThresholdString "THRESH" +#define P_ThresholdChannelString "THRESH_CH" #define P_CountsString "COUNTS%d" #define P_RateString "RATE%d" +#define P_ClearCountsString "C_%d" /******************************************************************************* * Stream Generator Coordinating Class @@ -109,12 +114,17 @@ class asynStreamGeneratorDriver : public asynPortDriver { // Parameter Identifying IDs int P_Status; int P_Reset; + int P_Stop; int P_CountPreset; int P_TimePreset; int P_ElapsedTime; + int P_ClearElapsedTime; int P_MonitorChannel; + int P_Threshold; + int P_ThresholdChannel; int *P_Counts; int *P_Rates; + int *P_ClearCounts; private: asynUser *pasynUDPUser;