From 2e70b64426963efa931f9c484d58c25cfd6d858b Mon Sep 17 00:00:00 2001
From: Juliano Murari <juliano.murari@ess.eu>
Date: Wed, 14 Sep 2022 13:15:17 +0200
Subject: [PATCH] PBIBCM-223 Add Beam Absence Signals

---
 sis8300bcmApp/Db/sis8300bcm.template | 52 ++++++++++++++++++++++++++++
 sis8300bcmApp/src/sis8300bcm.cpp     | 39 +++++++++++++++++++++
 sis8300bcmApp/src/sis8300bcm.h       |  6 ++++
 vendor/ess/lib/sis8300bcm_reg.h      |  1 +
 vendor/ess/lib/sis8300drvbcm.c       | 34 ++++++++++++++++++
 vendor/ess/lib/sis8300drvbcm.h       |  2 ++
 6 files changed, 134 insertions(+)

diff --git a/sis8300bcmApp/Db/sis8300bcm.template b/sis8300bcmApp/Db/sis8300bcm.template
index db1894f..6eb3871 100644
--- a/sis8300bcmApp/Db/sis8300bcm.template
+++ b/sis8300bcmApp/Db/sis8300bcm.template
@@ -685,3 +685,55 @@ record(ao, "$(P)$(R)CalibrationActualCurrent")
     field(ASG,  "critical")
     info(autosaveFields, "VAL")
 }
+
+record(bo, "$(P)$(R)BeamAbsenceMask-Ch0")
+{
+    field(DTYP, "asynInt32")
+    field(OUT,  "@asyn($(PORT),$(ADDR=0),$(TIMEOUT=1))BCM.BEAM_ABSENCE_CHANNEL_0")
+    field(ZNAM, "Disable")
+    field(ONAM, "Enable")
+    field(ASG,  "critical")
+    info(autosaveFields, "VAL")
+}
+record(bi, "$(P)$(R)BeamAbsenceMask-Ch0R")
+{
+    field(DTYP, "asynInt32")
+    field(INP,  "@asyn($(PORT),$(ADDR=0),$(TIMEOUT=1))BCM.BEAM_ABSENCE_CHANNEL_0")
+    field(SCAN, "I/O Intr")
+    field(ZNAM, "Disabled")
+    field(ONAM, "Enabled")
+}
+record(bo, "$(P)$(R)BeamAbsenceMask-Ch1")
+{
+    field(DTYP, "asynInt32")
+    field(OUT,  "@asyn($(PORT),$(ADDR=0),$(TIMEOUT=1))BCM.BEAM_ABSENCE_CHANNEL_1")
+    field(ZNAM, "Disable")
+    field(ONAM, "Enable")
+    field(ASG,  "critical")
+    info(autosaveFields, "VAL")
+}
+record(bi, "$(P)$(R)BeamAbsenceMask-Ch1R")
+{
+    field(DTYP, "asynInt32")
+    field(INP,  "@asyn($(PORT),$(ADDR=0),$(TIMEOUT=1))BCM.BEAM_ABSENCE_CHANNEL_1")
+    field(SCAN, "I/O Intr")
+    field(ZNAM, "Disabled")
+    field(ONAM, "Enabled")
+}
+record(bo, "$(P)$(R)BeamAbsenceMask-Ch2")
+{
+    field(DTYP, "asynInt32")
+    field(OUT,  "@asyn($(PORT),$(ADDR=0),$(TIMEOUT=1))BCM.BEAM_ABSENCE_CHANNEL_2")
+    field(ZNAM, "Disable")
+    field(ONAM, "Enable")
+    field(ASG,  "critical")
+    info(autosaveFields, "VAL")
+}
+record(bi, "$(P)$(R)BeamAbsenceMask-Ch2R")
+{
+    field(DTYP, "asynInt32")
+    field(INP,  "@asyn($(PORT),$(ADDR=0),$(TIMEOUT=1))BCM.BEAM_ABSENCE_CHANNEL_2")
+    field(SCAN, "I/O Intr")
+    field(ZNAM, "Disabled")
+    field(ONAM, "Enabled")
+}
diff --git a/sis8300bcmApp/src/sis8300bcm.cpp b/sis8300bcmApp/src/sis8300bcm.cpp
index fce8414..b496e11 100644
--- a/sis8300bcmApp/src/sis8300bcm.cpp
+++ b/sis8300bcmApp/src/sis8300bcm.cpp
@@ -185,6 +185,9 @@ sis8300bcm::sis8300bcm(const char *portName, const char *devicePath,
     createParam(BCMHighVoltagePresenceString,               asynParamInt32,     &BCMHighVoltagePresence);
     createParam(BCMHighVoltageOKString,                     asynParamInt32,     &BCMHighVoltageOK);
     createParam(BCMEnableCalibrationPulseString,            asynParamInt32,     &BCMEnableCalibrationPulse);
+    createParam(BCMBeamAbsenceChannel0String,               asynParamInt32,     &BCMBeamAbsenceChannel0);
+    createParam(BCMBeamAbsenceChannel1String,               asynParamInt32,     &BCMBeamAbsenceChannel1);
+    createParam(BCMBeamAbsenceChannel2String,               asynParamInt32,     &BCMBeamAbsenceChannel2);
     // ACCT block, channel specific
     createParam(BCMAcctTriggerSourceString,                 asynParamInt32,     &BCMAcctTriggerSource);
     createParam(BCMAcctPulseChargeString,                   asynParamFloat64,   &BCMAcctPulseCharge);
@@ -680,6 +683,27 @@ int sis8300bcm::readbackParameters()
     }
     setIntegerParam(BCMBeamTriggerSource, uintValue);
 
+    ret = sis8300drvbcm_get_beam_absence_signals(mDeviceHandle, 0, &uintValue);
+    if (ret) {
+        asynPrintError(pasynUserSelf, "sis8300drvbcm_get_beam_absence_signals bit 0 returned %d", ret);
+        return ret;
+    }
+    setIntegerParam(BCMBeamAbsenceChannel0, uintValue);
+
+    ret = sis8300drvbcm_get_beam_absence_signals(mDeviceHandle, 1, &uintValue);
+    if (ret) {
+        asynPrintError(pasynUserSelf, "sis8300drvbcm_get_beam_absence_signals bit 1 returned %d", ret);
+        return ret;
+    }
+    setIntegerParam(BCMBeamAbsenceChannel1, uintValue);
+
+    ret = sis8300drvbcm_get_beam_absence_signals(mDeviceHandle, 2, &uintValue);
+    if (ret) {
+        asynPrintError(pasynUserSelf, "sis8300drvbcm_get_beam_absence_signals bit 2 returned %d", ret);
+        return ret;
+    }
+    setIntegerParam(BCMBeamAbsenceChannel2, uintValue);
+
     // readback channel configuration parameters
     for (int addr = 0; addr < SIS8300BCM_NUM_CHANNELS; addr++) {
         asynPrintDeviceInfo(pasynUserSelf, "readback acq %d parameters", addr);
@@ -1756,6 +1780,21 @@ asynStatus sis8300bcm::writeInt32(asynUser *pasynUser, epicsInt32 value)
         if (ret) {
             asynPrintError(pasynUser, "sis8300drvbcm_set_enable_calibration_pulse returned %d", ret);
         }
+    } else if (function == BCMBeamAbsenceChannel0) {
+        ret = sis8300drvbcm_set_beam_absence_signals(mDeviceHandle, 0, value);
+        if (ret) {
+            asynPrintError(pasynUser, "sis8300drvbcm_set_beam_absence_signals bit 0 returned %d", ret);
+        }
+    } else if (function == BCMBeamAbsenceChannel1) {
+        ret = sis8300drvbcm_set_beam_absence_signals(mDeviceHandle, 1, value);
+        if (ret) {
+            asynPrintError(pasynUser, "sis8300drvbcm_set_beam_absence_signals bit 1 returned %d", ret);
+        }
+    } else if (function == BCMBeamAbsenceChannel2) {
+        ret = sis8300drvbcm_set_beam_absence_signals(mDeviceHandle, 2, value);
+        if (ret) {
+            asynPrintError(pasynUser, "sis8300drvbcm_set_beam_absence_signals bit 2 returned %d", ret);
+        }
     } else if (function == SIS8300TriggerSource || function == SIS8300TriggerExternalLine) {
         // override generic trigger source/line handling from sis8300
     } else if (function == BCMAcctDroopCompensating) {
diff --git a/sis8300bcmApp/src/sis8300bcm.h b/sis8300bcmApp/src/sis8300bcm.h
index a4e9df6..a1a8940 100644
--- a/sis8300bcmApp/src/sis8300bcm.h
+++ b/sis8300bcmApp/src/sis8300bcm.h
@@ -81,6 +81,9 @@
 #define BCMHighVoltagePresenceString                 "BCM.HIGH_VOLTAGE_PRESENCE"
 #define BCMHighVoltageOKString                       "BCM.HIGH_VOLTAGE_OK"
 #define BCMEnableCalibrationPulseString              "BCM.ENABLE_CALIBRATION_PULSE"
+#define BCMBeamAbsenceChannel0String                 "BCM.BEAM_ABSENCE_CHANNEL_0"
+#define BCMBeamAbsenceChannel1String                 "BCM.BEAM_ABSENCE_CHANNEL_1"
+#define BCMBeamAbsenceChannel2String                 "BCM.BEAM_ABSENCE_CHANNEL_2"
 // ACCT block, channel specific
 #define BCMAcctTriggerSourceString                   "BCM.ACCT.TRIGGER_SOURCE"
 #define BCMAcctPulseChargeString                     "BCM.ACCT.PULSE_CHARGE"
@@ -308,6 +311,9 @@ protected:
     int BCMHighVoltagePresence;
     int BCMHighVoltageOK;
     int BCMEnableCalibrationPulse;
+    int BCMBeamAbsenceChannel0;
+    int BCMBeamAbsenceChannel1;
+    int BCMBeamAbsenceChannel2;
     // ACCT block, channel specific
     int BCMAcctTriggerSource;
     int BCMAcctPulseCharge;
diff --git a/vendor/ess/lib/sis8300bcm_reg.h b/vendor/ess/lib/sis8300bcm_reg.h
index b307372..26827bd 100644
--- a/vendor/ess/lib/sis8300bcm_reg.h
+++ b/vendor/ess/lib/sis8300bcm_reg.h
@@ -70,6 +70,7 @@ extern "C" {
 #define SIS8300BCM_ACQUITISION_TRIGGER_SOURCE_REG       0x436
 #define SIS8300BCM_CRATE_ID_REG                         0x437
 #define SIS8300BCM_PULSE_WIDTH_FILTER_REG               0x43E
+#define SIS8300BCM_BEAM_ABSENCE_SIGNALS_REG             0x43F
 
 /* channel specific registers start at 0x500 */
 #define SIS8300BCM_CHANNEL_BLOCK_BASE                   0x500
diff --git a/vendor/ess/lib/sis8300drvbcm.c b/vendor/ess/lib/sis8300drvbcm.c
index 7e51093..908ee3e 100644
--- a/vendor/ess/lib/sis8300drvbcm.c
+++ b/vendor/ess/lib/sis8300drvbcm.c
@@ -145,6 +145,40 @@ int sis8300drvbcm_get_pulse_width_filter(sis8300drv_usr *sisuser, double *width)
     return ret;
 }
 
+// used to control beam absence signals
+int sis8300drvbcm_set_beam_absence_signals(sis8300drv_usr *sisuser, unsigned int bit, unsigned int mask)
+{
+    unsigned int value;
+    // register has lowest 3 bits defined
+    int ret = sis8300drv_reg_read(sisuser, SIS8300BCM_BEAM_ABSENCE_SIGNALS_REG, &value);
+    if (ret) {
+        return ret;
+    }
+    value &= 0x7;
+    // set / clear the desired bit
+    if (mask) {
+        value |= (1 << bit);
+    } else {
+        value &= ~(1 << bit);
+    }
+    ret = sis8300drv_reg_write(sisuser, SIS8300BCM_BEAM_ABSENCE_SIGNALS_REG, value);
+    printf("%s: beam absence register is 0x%x, bit %d: %d\n", __func__, value, bit, mask);
+    return ret;
+}
+
+int sis8300drvbcm_get_beam_absence_signals(sis8300drv_usr *sisuser, unsigned int bit, unsigned int *mask)
+{
+    unsigned int value;
+    // register has lowest 3 bits defined
+    int ret = sis8300drv_reg_read(sisuser, SIS8300BCM_BEAM_ABSENCE_SIGNALS_REG, &value);
+    if (ret) {
+        return ret;
+    }
+    // check the desired bit
+    *mask = (value & (1 << bit)) ? 1 : 0;
+    return ret;
+}
+
 // used to control trigger selection for beam start for individual ACCTs
 int sis8300drvbcm_set_channel_trigger_source(sis8300drv_usr *sisuser, unsigned int channel, unsigned int source)
 {
diff --git a/vendor/ess/lib/sis8300drvbcm.h b/vendor/ess/lib/sis8300drvbcm.h
index 93b3c59..ad67f43 100644
--- a/vendor/ess/lib/sis8300drvbcm.h
+++ b/vendor/ess/lib/sis8300drvbcm.h
@@ -95,6 +95,8 @@ int sis8300drvbcm_set_crate_id(sis8300drv_usr *sisuser, unsigned int crate_id);
 int sis8300drvbcm_get_crate_id(sis8300drv_usr *sisuser, unsigned int *crate_id);
 int sis8300drvbcm_set_pulse_width_filter(sis8300drv_usr *sisuser, double width);
 int sis8300drvbcm_get_pulse_width_filter(sis8300drv_usr *sisuser, double *width);
+int sis8300drvbcm_set_beam_absence_signals(sis8300drv_usr *sisuser, unsigned int bit, unsigned int mask);
+int sis8300drvbcm_get_beam_absence_signals(sis8300drv_usr *sisuser, unsigned int bit, unsigned int *mask);
 int sis8300drvbcm_set_channel_trigger_source(sis8300drv_usr *sisuser, unsigned int channel, unsigned int source);
 int sis8300drvbcm_get_channel_trigger_source(sis8300drv_usr *sisuser, unsigned int channel, unsigned int *source);
 int sis8300drvbcm_set_channel_number_of_samples(sis8300drv_usr *sisuser, unsigned int channel, unsigned int count);
-- 
GitLab