From 1a6173c91157c47bb6d7cd7de7ae07c28754b8a0 Mon Sep 17 00:00:00 2001 From: Pedro Nariyoshi Date: Wed, 18 Jun 2025 14:04:04 -0400 Subject: [PATCH 1/2] Implement drvCaen for CAEN devices using DPP-PHA firmware --- iocBoot/iocCaen/Makefile | 6 + iocBoot/iocCaen/st.cmd | 33 + mcaApp/CaenSrc/DigitizerFunctions.cpp | 90 ++ mcaApp/CaenSrc/DigitizerFunctions.h | 11 + mcaApp/CaenSrc/Makefile | 67 ++ mcaApp/CaenSrc/ParamStruct.h | 24 + mcaApp/CaenSrc/TODO | 8 + mcaApp/CaenSrc/drvCaen.cpp | 1156 +++++++++++++++++++++++++ mcaApp/CaenSrc/drvCaen.h | 240 +++++ mcaApp/CaenSrc/mcaCaenAppMain.cpp | 23 + mcaApp/CaenSrc/mcaCaenSupport.dbd | 4 + mcaApp/Db/Caen.db | 144 +++ mcaApp/Db/CaenBoard.db | 143 +++ mcaApp/Db/CaenChannel.db | 509 +++++++++++ mcaApp/Makefile | 4 + 15 files changed, 2462 insertions(+) create mode 100644 iocBoot/iocCaen/Makefile create mode 100755 iocBoot/iocCaen/st.cmd create mode 100644 mcaApp/CaenSrc/DigitizerFunctions.cpp create mode 100644 mcaApp/CaenSrc/DigitizerFunctions.h create mode 100644 mcaApp/CaenSrc/Makefile create mode 100644 mcaApp/CaenSrc/ParamStruct.h create mode 100644 mcaApp/CaenSrc/TODO create mode 100644 mcaApp/CaenSrc/drvCaen.cpp create mode 100644 mcaApp/CaenSrc/drvCaen.h create mode 100644 mcaApp/CaenSrc/mcaCaenAppMain.cpp create mode 100644 mcaApp/CaenSrc/mcaCaenSupport.dbd create mode 100644 mcaApp/Db/Caen.db create mode 100755 mcaApp/Db/CaenBoard.db create mode 100644 mcaApp/Db/CaenChannel.db diff --git a/iocBoot/iocCaen/Makefile b/iocBoot/iocCaen/Makefile new file mode 100644 index 00000000..daa50601 --- /dev/null +++ b/iocBoot/iocCaen/Makefile @@ -0,0 +1,6 @@ +TOP = ../.. +include $(TOP)/configure/CONFIG +ARCH = linux-x86_64 +#ARCH = windows-x64-static +TARGETS = envPaths +include $(TOP)/configure/RULES.ioc diff --git a/iocBoot/iocCaen/st.cmd b/iocBoot/iocCaen/st.cmd new file mode 100755 index 00000000..524a7308 --- /dev/null +++ b/iocBoot/iocCaen/st.cmd @@ -0,0 +1,33 @@ +#!../../bin/linux-x86_64/mcaCaenApp + +< envPaths + +epicsEnvSet(STARTUP,$(TOP)/iocBoot/$(IOC)) + +dbLoadDatabase("$(MCA)/dbd/mcaCaenApp.dbd",0,0) +mcaCaenApp_registerRecordDeviceDriver(pdbbase) + +# See CAENDigitizer documentation on OpenDigitizer for more info on this function +# drvCaenConfigure(Portname, LinkType, LinkNum, ConetNode, VMEBaseAddress) +drvCaenConfigure(Caen1, 5, 12345, 0, 0) + +#asynSetTraceMask(Caen1, 7, 15) +#asynSetTraceIOMask(Caen1, 7, 15) +epicsEnvSet("P", "CAEN_MCA:") +epicsEnvSet("PORT", "Caen1") + +# Board wide parameters +dbLoadRecords("$(MCA)/db/Caen.db","P=$(P),R=MCA01:,PORT=$(PORT)") +# Multi-ADC auxilary PVs +dbLoadRecords("$(MCA)/db/CaenBoard.db","P=$(P),M=MCA01:,PORT=$(PORT),M1=MCA01_CH01,M2=MCA01_CH02,M3=MCA01_CH03,M4=MCA01_CH04,M5=MCA01_CH05,M6=MCA01_CH06,M7=MCA01_CH07,M8=MCA01_CH08") +dbLoadRecords("$(MCA)/db/CaenChannel.db","P=$(P),R=MCA01_CH01,PORT=$(PORT),CHAN=0,NCHAN=16384,DTYP=asynMCA") +# MCA records and per-ADC parameters +dbLoadRecords("$(MCA)/db/CaenChannel.db","P=$(P),R=MCA01_CH02,PORT=$(PORT),CHAN=1,NCHAN=16384,DTYP=asynMCA") +dbLoadRecords("$(MCA)/db/CaenChannel.db","P=$(P),R=MCA01_CH03,PORT=$(PORT),CHAN=2,NCHAN=16384,DTYP=asynMCA") +dbLoadRecords("$(MCA)/db/CaenChannel.db","P=$(P),R=MCA01_CH04,PORT=$(PORT),CHAN=3,NCHAN=16384,DTYP=asynMCA") +dbLoadRecords("$(MCA)/db/CaenChannel.db","P=$(P),R=MCA01_CH05,PORT=$(PORT),CHAN=4,NCHAN=16384,DTYP=asynMCA") +dbLoadRecords("$(MCA)/db/CaenChannel.db","P=$(P),R=MCA01_CH06,PORT=$(PORT),CHAN=5,NCHAN=16384,DTYP=asynMCA") +dbLoadRecords("$(MCA)/db/CaenChannel.db","P=$(P),R=MCA01_CH07,PORT=$(PORT),CHAN=6,NCHAN=16384,DTYP=asynMCA") +dbLoadRecords("$(MCA)/db/CaenChannel.db","P=$(P),R=MCA01_CH08,PORT=$(PORT),CHAN=7,NCHAN=16384,DTYP=asynMCA") + +iocInit() diff --git a/mcaApp/CaenSrc/DigitizerFunctions.cpp b/mcaApp/CaenSrc/DigitizerFunctions.cpp new file mode 100644 index 00000000..33474d7d --- /dev/null +++ b/mcaApp/CaenSrc/DigitizerFunctions.cpp @@ -0,0 +1,90 @@ +#include "DigitizerFunctions.h" + +int ProgramDigitizer(int handle, DigitizerParams_t Params, CAEN_DGTZ_DPP_PHA_Params_t DPPParams){ + /* This function uses the CAENDigitizer API functions to perform the digitizer's initial configuration */ + //CAEN_DGTZ_ErrorCode ret = CAEN_DGTZ_Success; + int ret = 0; + + /* Reset the digitizer */ + ret |= CAEN_DGTZ_Reset(handle); + + if (ret) { + printf("ERROR: can't reset the digitizer.\n"); + return -1; + } + // I do not know what this does, but CAEN's example uses it + // TODO: remove this eventually? + ret |= CAEN_DGTZ_WriteRegister(handle, 0x8000, 0x01000114); // Channel Control Reg (indiv trg, seq readout) ?? + + ret |= CAEN_DGTZ_SetDPPAcquisitionMode(handle, Params.DPPAcqMode, Params.DPPSaveParam); + ret |= CAEN_DGTZ_SetAcquisitionMode(handle, Params.AcqMode); + ret |= CAEN_DGTZ_SetRecordLength(handle, Params.RecordLength); + ret |= CAEN_DGTZ_SetIOLevel(handle, Params.IOlev); + ret |= CAEN_DGTZ_SetExtTriggerInputMode(handle, Params.TrigMode); + ret |= CAEN_DGTZ_SetChannelEnableMask(handle, Params.ChannelMask); + ret |= CAEN_DGTZ_SetDPPEventAggregation(handle, Params.EventAggr, 0); + // TODO: create parameter for this + ret |= CAEN_DGTZ_SetRunSynchronizationMode(handle, CAEN_DGTZ_RUN_SYNC_Disabled); + ret |= CAEN_DGTZ_SetDPPParameters(handle, Params.ChannelMask, &DPPParams); + + for(unsigned int i=0; iIOlev = CAEN_DGTZ_IOLevel_NIM; + Params->DPPAcqMode = CAEN_DGTZ_DPP_ACQ_MODE_List; // TODO: Maybe consider CAEN_DGTZ_DPP_ACQ_MODE_Mixed + Params->DPPSaveParam = CAEN_DGTZ_DPP_SAVE_PARAM_EnergyAndTime; + Params->AcqMode = CAEN_DGTZ_SW_CONTROLLED; + Params->RecordLength = 50000; // Only needed for Mixed/Scope mode + Params->ChannelMask = (1<<8) - 1; // Enable 8 channels +// Params->ChannelMask = (1<EventAggr = 0; // 0 = Auto + Params->TrigMode = CAEN_DGTZ_TRGMODE_ACQ_ONLY; + + for(unsigned int ch = 0; ch < MAX_DPP_PHA_CHANNEL_SIZE; ch++) { + Params->PulsePolarity[ch] = CAEN_DGTZ_PulsePolarityPositive; + Params->PreTriggerSize[ch] = 1000; + Params->DCOffset[ch] = 0x8000; + DPPParams->thr[ch] = 100; // Trigger Threshold (in LSB) + DPPParams->k[ch] = 3000; // Trapezoid Rise Time (ns) + DPPParams->m[ch] = 900; // Trapezoid Flat Top (ns) + DPPParams->M[ch] = 25000; // Decay Time Constant (ns) + DPPParams->ftd[ch] = 500; // Flat top delay (peaking time) (ns) + DPPParams->a[ch] = 4; // Trigger Filter smoothing factor (number of samples to average for RC-CR2 filter) Options: 1; 2; 4; 8; 16; 32 + DPPParams->b[ch] = 200; // Input Signal Rise time (ns) + DPPParams->trgho[ch] = 1200; // Trigger Hold Off + DPPParams->nsbl[ch] = 4; //number of samples for baseline average calculation. Options: 1->16 samples; 2->64 samples; 3->256 samples; 4->1024 samples; 5->4096 samples; 6->16384 samples + DPPParams->nspk[ch] = 0; //Peak mean (number of samples to average for trapezoid height calculation). Options: 0-> 1 sample; 1->4 samples; 2->16 samples; 3->64 samples + DPPParams->pkho[ch] = 2000; //peak holdoff (ns) + DPPParams->blho[ch] = 500; //Baseline holdoff (ns) + DPPParams->enf[ch] = 1.0; // Energy Normalization Factor + DPPParams->decimation[ch] = 0; //decimation (the input signal samples are averaged within this number of samples): 0 ->disabled; 1->2 samples; 2->4 samples; 3->8 samples + DPPParams->dgain[ch] = 0; //decimation gain. Options: 0->DigitalGain=1; 1->DigitalGain=2 (only with decimation >= 2samples); 2->DigitalGain=4 (only with decimation >= 4samples); 3->DigitalGain=8( only with decimation = 8samples). + DPPParams->otrej[ch] = 0; // Deprecated + DPPParams->trgwin[ch] = 0; //Enable Rise time Discrimination. Options: 0->disabled; 1->enabled + DPPParams->twwdt[ch] = 100; //Rise Time Validation Window (ns) + //DPPParams.tsampl[ch] = 10; + //DPPParams.dgain[ch] = 1; + } +} + +unsigned long long int get_time_ns(){ + return std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()).count(); +} diff --git a/mcaApp/CaenSrc/DigitizerFunctions.h b/mcaApp/CaenSrc/DigitizerFunctions.h new file mode 100644 index 00000000..cf6952c6 --- /dev/null +++ b/mcaApp/CaenSrc/DigitizerFunctions.h @@ -0,0 +1,11 @@ +#include "ParamStruct.h" +#include +#include +#include +#include // Needed for get_time_ms (requires C++11) + +int ProgramDigitizer(int handle, DigitizerParams_t Params, CAEN_DGTZ_DPP_PHA_Params_t DPPParams); + +void SetDefaultParams(DigitizerParams_t * Params, CAEN_DGTZ_DPP_PHA_Params_t * DPPParams); + +unsigned long long int get_time_ns(); diff --git a/mcaApp/CaenSrc/Makefile b/mcaApp/CaenSrc/Makefile new file mode 100644 index 00000000..a6c10d1d --- /dev/null +++ b/mcaApp/CaenSrc/Makefile @@ -0,0 +1,67 @@ +TOP=../.. +include $(TOP)/configure/CONFIG +#---------------------------------------- +# ADD MACRO DEFINITIONS AFTER THIS LINE +#============================= +PYDEVSUP ?= /etc/epics +PYTHON ?= python3 +include $(PYDEVSUP)/configure/CONFIG_PY + +#============================= + +# .dbd will be created from Include.dbd +DBD += mcaCaenApp.dbd +mcaCaenApp_DBD += +DBD += mcaCaenSupport.dbd + +# I only have a Linux environment to test +LIBRARY_IOC += mcaCaen +PROD_IOC += mcaCaenApp + +# Include where CAENDigitizer.h is +USR_INCLUDES += -I/usr/include/ + +## _registerRecordDeviceDriver.cpp will be created from .dbd +#mcaCaen_SRCS += NetFinder.cpp + +mcaCaen_SRCS += drvCaen.cpp + +mcaCaen_LIBS += asyn +mcaCaen_LIBS += $(EPICS_BASE_IOC_LIBS) +#mcaCaen_SYS_LIBS += usb-1.0 +#mcaCaen_LIBS_WIN32 += libusb-1.0 + +## _registerRecordDeviceDriver.cpp will be created from .dbd +mcaCaenApp_SRCS += mcaCaenApp_registerRecordDeviceDriver.cpp +mcaCaenApp_SRCS += DigitizerFunctions.cpp +mcaCaenApp_SRCS_DEFAULT += mcaCaenAppMain.cpp +mcaCaenApp_SRCS_vxWorks += -nil- +mcaCaenApp_LIBS += mcaCaen +mcaCaenApp_LIBS += mca +mcaCaenApp_LIBS += calc autosave +mcaCaenApp_LIBS += sscan busy +mcaCaenApp_LIBS += asyn +mcaCaenApp_LIBS += seq pv +mcaCaenApp_LIBS += pyDevSup$(PY_LD_VER) +mcaCaenApp_LIBS += $(EPICS_BASE_IOC_LIBS) +mcaCaenApp_SYS_LIBS += CAENDigitizer +#mcaCaenApp_SYS_LIBS += usb-1.0 +#mcaCaenApp_LIBS_WIN32 += libusb-1.0 + +mcaCaenApp_DBD += base.dbd +mcaCaenApp_DBD += mcaCaenSupport.dbd +mcaCaenApp_DBD += mcaSupport.dbd +mcaCaenApp_DBD += asyn.dbd +mcaCaenApp_DBD += drvAsynIPPort.dbd +mcaCaenApp_DBD += calcSupport.dbd +mcaCaenApp_DBD += asSupport.dbd +mcaCaenApp_DBD += busySupport.dbd +mcaCaenApp_DBD += sscanSupport.dbd +mcaCaenApp_DBD += pyDevSup.dbd +mcaCaenApp_DBD += system.dbd + +DIAGSTD ?= $(EPICS_BASE) +include $(DIAGSTD)/configure/fribdiagstdMakefile +include $(TOP)/configure/RULES +#---------------------------------------- +# ADD RULES AFTER THIS LINE diff --git a/mcaApp/CaenSrc/ParamStruct.h b/mcaApp/CaenSrc/ParamStruct.h new file mode 100644 index 00000000..fa0bc59a --- /dev/null +++ b/mcaApp/CaenSrc/ParamStruct.h @@ -0,0 +1,24 @@ +#include "CAENDigitizerType.h" + +#ifndef PARAM_STRUCTS +#define PARAM_STRUCTS +typedef struct +{ + CAEN_DGTZ_ConnectionType LinkType; + uint32_t VMEBaseAddress; + uint32_t LinkNum; + uint32_t ConetNode; + uint32_t RecordLength; + uint32_t ChannelMask; + int EventAggr; + CAEN_DGTZ_PulsePolarity_t PulsePolarity[MAX_DPP_PHA_CHANNEL_SIZE]; + uint32_t DCOffset[MAX_DPP_PHA_CHANNEL_SIZE]; + uint32_t PreTriggerSize[MAX_DPP_PHA_CHANNEL_SIZE]; + CAEN_DGTZ_AcqMode_t AcqMode; + CAEN_DGTZ_DPP_SaveParam_t DPPSaveParam; + CAEN_DGTZ_DPP_AcqMode_t DPPAcqMode; + CAEN_DGTZ_TriggerMode_t TrigMode; + CAEN_DGTZ_IOLevel_t IOlev; +} DigitizerParams_t; + +#endif diff --git a/mcaApp/CaenSrc/TODO b/mcaApp/CaenSrc/TODO new file mode 100644 index 00000000..c6e0aebe --- /dev/null +++ b/mcaApp/CaenSrc/TODO @@ -0,0 +1,8 @@ +- Add way to resize buffers? +- Some parameters are still hard-coded +- Make poll period account for thread run time +- Initialize parameters in constructor or connectDevice +- Investigate how to measure live-time (perhaps discard one event and use the difference between the first and last event as elapsed time?) +- Implement PCTL and PCTH for PresetCounts +- Lean out read thread removing time tag processing +- Implement reading of pile-up events diff --git a/mcaApp/CaenSrc/drvCaen.cpp b/mcaApp/CaenSrc/drvCaen.cpp new file mode 100644 index 00000000..9210786a --- /dev/null +++ b/mcaApp/CaenSrc/drvCaen.cpp @@ -0,0 +1,1156 @@ +// File: drvCaen.cpp +// Author: Pedro Nariyoshi, Facility for Rare Isotope Beams +// Date: 18-January-2024 +// +// Purpose: +// This module provides the driver support for the MCA asyn device support layer +// for C.A.E.N. MCAs that support the CAENDigitizer library. +// +// + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +static const char *driverName = "drvCaen"; +void readThread(void *drvPvt); + +extern "C" { + static void exitHandlerC(void *arg) + { + drvCaen *p = (drvCaen *)arg; + p->exitHandler(); + } +} + +drvCaen::drvCaen(const char *portName, CAEN_DGTZ_ConnectionType LinkType, int LinkNum,int ConetNode, unsigned int VMEBaseAddress) + : asynPortDriver(portName, + MAX_ADCS, /* Maximum address */ + asynInt32Mask | asynInt32ArrayMask | asynFloat64Mask | asynOctetMask | asynDrvUserMask | asynOptionMask, /* Interface mask */ + asynInt32Mask | asynInt32ArrayMask | asynFloat64Mask | asynOctetMask, /* Interrupt mask */ + ASYN_CANBLOCK, /* asynFlags. This driver can block and is not multi-device */ + 1, /* Autoconnect */ + 0, /* Default priority */ + 0) /* Default stack size*/ +{ + const char *functionName = "drvCaen"; + + // Initialize parameters + LastReadTime_ = 0; + for(unsigned int chan = 0; chan < MAX_ADCS; chan++){ + StartTime_[chan] = LastReadTime_; + NumEvents_[chan] = 0; + Events_[chan] = NULL; + EHisto[chan] = NULL; + THisto[chan] = NULL; + TrgCnt[chan] = 0; + ECnt[chan] = 0; + PrevTime[chan] = 0; + ExtendedTT[chan] = 0; + PurCnt[chan] = 0; + } + memset(&Params_, 0, sizeof(DigitizerParams_t)); + memset(&DPPParams_, 0, sizeof(CAEN_DGTZ_DPP_PHA_Params_t)); + + // Initialize board parameters + Params_.LinkType = LinkType; + Params_.LinkNum = LinkNum; + Params_.ConetNode = ConetNode; + Params_.VMEBaseAddress = VMEBaseAddress; + + if(Params_.LinkType == CAEN_DGTZ_USB && Params_.ConetNode!=0){ + asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, + "%s::%s For USB, ConetMode must be equal to 0\n", + driverName, functionName); + return; + } + + // Initialize internal variables + acquiring_ = false; + isConnected_ = false; + exiting_ = false; + // Uncomment this line to enable asynTraceFlow during the constructor + //pasynTrace->setTraceMask(pasynUserSelf, 0x11); + + createParam(mcaStartAcquireString, asynParamInt32, &mcaStartAcquire_); + createParam(mcaStopAcquireString, asynParamInt32, &mcaStopAcquire_); /* int32, write */ + createParam(mcaEraseString, asynParamInt32, &mcaErase_); /* int32, write */ + createParam(mcaDataString, asynParamInt32Array, &mcaData_); /* int64Array, read/write */ + createParam(mcaReadStatusString, asynParamInt32, &mcaReadStatus_); /* int32, write */ + createParam(mcaChannelAdvanceSourceString, asynParamInt32, &mcaChannelAdvanceSource_); /* int32, write */ + createParam(mcaNumChannelsString, asynParamInt32, &mcaNumChannels_); /* int32, write */ + createParam(mcaDwellTimeString, asynParamFloat64, &mcaDwellTime_); /* float64, write */ + createParam(mcaPresetLiveTimeString, asynParamFloat64, &mcaPresetLiveTime_); /* float64, write */ + createParam(mcaPresetRealTimeString, asynParamFloat64, &mcaPresetRealTime_); /* float64, write */ + createParam(mcaPresetCountsString, asynParamFloat64, &mcaPresetCounts_); /* float64, write */ + createParam(mcaPresetLowChannelString, asynParamInt32, &mcaPresetLowChannel_); /* int32, write */ + createParam(mcaPresetHighChannelString, asynParamInt32, &mcaPresetHighChannel_); /* int32, write */ + createParam(mcaPresetSweepsString, asynParamInt32, &mcaPresetSweeps_); /* int32, write */ + createParam(mcaAcquireModeString, asynParamInt32, &mcaAcquireMode_); /* int32, write */ + createParam(mcaSequenceString, asynParamInt32, &mcaSequence_); /* int32, write */ + createParam(mcaPrescaleString, asynParamInt32, &mcaPrescale_); /* int32, write */ + createParam(mcaAcquiringString, asynParamInt32, &mcaAcquiring_); /* int32, read */ + createParam(mcaElapsedLiveTimeString, asynParamFloat64, &mcaElapsedLiveTime_); /* float64, read */ + createParam(mcaElapsedRealTimeString, asynParamFloat64, &mcaElapsedRealTime_); /* float64, read */ + createParam(mcaElapsedCountsString, asynParamFloat64, &mcaElapsedCounts_); /* float64, read */ + + // CAEN-specific board parameters + createParam(caenModelNameString, asynParamOctet, &caenModelName_); + createParam(caenModelString, asynParamInt32, &caenModel_); + createParam(caenNADCsString, asynParamInt32, &caenNADCs_); + createParam(caenFormFactorString, asynParamInt32, &caenFormFactor_); + createParam(caenFamilyCodeString, asynParamInt32, &caenFamilyCode_); + createParam(caenROCFirmwareString, asynParamOctet, &caenROC_FirmwareRel_); + createParam(caenAMCFirmwareString, asynParamOctet, &caenAMC_FirmwareRel_); + createParam(caenSerialNumberString, asynParamInt32, &caenSerialNumber_); + createParam(caenMezzanineSerNumString, asynParamOctet, &caenMezzSerNum_); + createParam(caenPCBRevisionString, asynParamInt32, &caenPCB_Revision_); + createParam(caenADCNBITSString, asynParamInt32, &caenADC_NBits_); + createParam(caenSAMCorrectionString, asynParamInt32, &caenSAMCorrectionDataLoaded_); + createParam(caenCommHandleString, asynParamInt32, &caenCommHandle_); + createParam(caenVMEHandleString, asynParamInt32, &caenVMEHandle_); + createParam(caenLicenseString, asynParamOctet, &caenLicense_); + createParam(caenDCOffsetString, asynParamInt32, &caenDCOffset_); + createParam(caenPreTriggerSizeString, asynParamInt32, &caenPreTriggerSize_); + createParam(caenPulsePolarityString, asynParamInt32, &caenPulsePolarity_); + createParam(caenBoardTempString, asynParamInt32, &caenBoardTemp_); + + // CAEN-specific channel parameters + createParam(caenTrigThreshString, asynParamInt32, &caenTrigThresh_); + createParam(caenTrapRiseString, asynParamInt32, &caenTrapRise_); + createParam(caenTrapFlatTopString, asynParamInt32, &caenTrapFlatTop_); + createParam(caenDecayTimeString, asynParamInt32, &caenDecayTime_); + createParam(caenFlatTopDelayString, asynParamInt32, &caenFlatTopDelay_); + createParam(caenTrigFiltSmooString, asynParamInt32, &caenTrigFiltSmoo_); + createParam(caenInputRiseTimeString, asynParamInt32, &caenInputRiseTime_); + createParam(caenTrigHoldOffString, asynParamInt32, &caenTrigHoldOff_); + createParam(caenNBaselineString, asynParamInt32, &caenNBaseline_); + createParam(caenNSPeakString, asynParamInt32, &caenNSPeak_); + createParam(caenPeakHoldOffString, asynParamInt32, &caenPeakHoldOff_); + createParam(caenBLHoldOffString, asynParamInt32, &caenBLHoldOff_); + createParam(caenEnergyNFString, asynParamFloat64, &caenEnergyNF_); + createParam(caenDecimationString, asynParamInt32, &caenDecimation_); + createParam(caenDecGainString, asynParamInt32, &caenDecGain_); + createParam(caenTrigWinString, asynParamInt32, &caenTrigWin_); + createParam(caenTWWDTString, asynParamInt32, &caenTWWDT_); + + // CAEN-specific miscelaneous parameters + createParam(caenRegAddrString, asynParamInt32, &caenRegAddr_); + createParam(caenRegisterString, asynParamInt32, &caenRegister_); + createParam(caenPollPeriodString, asynParamFloat64, &caenPollPeriod_); + + failedSends_ = 0; + + eventId_ = epicsEventCreate(epicsEventEmpty); + setDoubleParam(caenPollPeriod_, 0.005); // Default poll every 5ms + /* Create the thread that reads from the board in the background */ +#ifdef EPICS_THREAD_CAN_JOIN // Sadly, not all OS and EPICS versions can do things properly + epicsThreadOpts opts = EPICS_THREAD_OPTS_INIT; + opts.joinable = true; // We need to be able to stop the thread + opts.priority = epicsThreadPriorityHigh; // + threadId_ = epicsThreadCreateOpt("drvCaenReadBoardTask", + (EPICSTHREADFUNC)::readThread, + this, + &opts); +#else + threadId_ = epicsThreadCreate("drvCaenReadBoardTask", + epicsThreadPriorityHigh, + epicsThreadGetStackSize(epicsThreadStackMedium), + (EPICSTHREADFUNC)::readThread, + this); +#endif + if (threadId_ == NULL) { + epicsSnprintf(pasynUserSelf->errorMessage, pasynUserSelf->errorMessageSize, + "%s:%s: epicsThreadCreate failure\n", driverName, functionName); + return; + } + epicsAtExit(exitHandlerC, this); +} + +drvCaen::~drvCaen() +{ + exitHandler(); +} + +void drvCaen::exitHandler() +{ + int ret; + const char *functionName = "exitHandler"; + lock(); + ret = CAEN_DGTZ_SWStopAcquisition(handle_); + isConnected_ = false; + exiting_ = true; + acquiring_ = false; + unlock(); + +#ifdef EPICS_THREAD_CAN_JOIN // Sadly, not all OS and EPICS versions can do things properly + epicsEventSignal(eventId_); + epicsThreadMustJoin(threadId_); +#endif + + ret |= CAEN_DGTZ_CloseDigitizer(handle_); + CAEN_DGTZ_FreeReadoutBuffer(&buffer_); + CAEN_DGTZ_FreeDPPEvents(handle_, (void**) Events_); + CAEN_DGTZ_FreeDPPWaveforms(handle_, Waveform_); + + if (ret != CAEN_DGTZ_Success){ + epicsSnprintf(pasynUserSelf->errorMessage, pasynUserSelf->errorMessageSize, + "%s:%s: Error closing digitizer\n", driverName, functionName); + } +} + + +asynStatus drvCaen::connect(asynUser *pasynUser) +{ + static const char *functionName = "connect"; + int addr; + getAddress(pasynUser, &addr); + + // if (addr > 0) + // return (handle_ != 0) ? asynSuccess : asynError; + + if (isConnected_ == false) { + asynStatus status = connectDevice(pasynUser); + if (status != asynSuccess) { + /* the connection itself might be successful but the subsequent initialization might have failed */ + return status; + } + + isConnected_ = true; + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "%s::%s Digitizer (%s) handle is %d\n", + driverName, functionName, portName, handle_); + failedSends_ = 0; + pasynManager->exceptionConnect(pasynUser); + } + + // Check if ADC number could exist + // TODO: Maybe use specific number of channels for this board + if (addr >= 0 && addr < MAX_ADCS){ + return asynSuccess; + } + else{ + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "%s::%s Digitizer (%s) ADC Index %d does not exist\n", + driverName, functionName, portName, addr); + return asynError; + } + // Catchall at the end + return asynSuccess; +} + +//asynStatus drvCaen::disconnect(asynUser *pasynUser) +//{ +// static const char *functionName = "disconnectDevice"; +// asynStatus ret; +// +// // Disconnect from the digitizer +// if(isConnected_ == true){ +// ret = disconnectDevice(); +// +// int addr; +// getAddress(pasynUser, &addr); +// +// if (ret == asynSuccess){ +// isConnected_ = false; +// asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, +// "%s::%s Digitizer (%s) disconnected\n", +// driverName, functionName, portName); +// } +// else{ +// epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, +// "%s::%s Digitizer (%s) not disconnected\nError code = %d\n", +// driverName, functionName, portName, ret); +// return asynError; +// } +// } +// +// pasynManager->exceptionDisconnect(pasynUser); +// setParamsAlarm(COMM_ALARM, INVALID_ALARM); +// +// return asynSuccess; +//} + +void drvCaen::setParamsAlarm(int alarmStatus, int alarmSeverity) +{ + for (int addr = 0; addr < MAX_ADCS; ++addr) { + int numParams = 0; + getNumParams(addr, &numParams); + for (int i = 0; i < numParams; ++i) { + setParamAlarmStatus(addr, i, alarmStatus); + setParamAlarmSeverity(addr, i, alarmSeverity); + } + callParamCallbacks(addr); + } +} + +void drvCaen::checkFailedComm(const char *functionName) +{ + if (++failedSends_ > MAX_FAILED_SENDS) { + asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, + "%s::%s too many failed status queries, disconnecting\n", + driverName, functionName); + disconnect(pasynUserSelf); + } +} + +asynStatus drvCaen::connectDevice(asynUser *pasynUser) +{ + static const char *functionName = "connectDevice"; + CAEN_DGTZ_ErrorCode ret; + CAEN_DGTZ_BoardInfo_t BoardInfo; + + if (isConnected_ == true){ + return asynSuccess; + } + + /// Connect to digitizer + ret = CAEN_DGTZ_OpenDigitizer(Params_.LinkType, Params_.LinkNum, Params_.ConetNode, + Params_.VMEBaseAddress, &handle_); + if (ret == CAEN_DGTZ_Success){ + asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, + "%s::%s Digitizer (%d, %d, %d, %d) connected\n", + driverName, functionName, Params_.LinkType, Params_.LinkNum, Params_.ConetNode, Params_.VMEBaseAddress); + } + else{ + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "%s::%s Digitizer (%d, %d, %d, %d) not connected\nError code = %d\n", + driverName, functionName, Params_.LinkType, Params_.LinkNum, Params_.ConetNode, Params_.VMEBaseAddress,ret); + disconnect(pasynUser); + return asynError; + } + + // Get board info + ret = CAEN_DGTZ_GetInfo(handle_, &BoardInfo); + if (ret != CAEN_DGTZ_Success){ + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "%s::%s Failed to get BoardInfo for %s (error = %d)\n", + driverName, functionName, portName, ret); + disconnect(pasynUser); + return asynError; + } + + setStringParam(caenModelName_,BoardInfo.ModelName); + setIntegerParam(caenModel_,BoardInfo.Model); + setIntegerParam(caenNADCs_,BoardInfo.Channels); + setIntegerParam(caenFormFactor_,BoardInfo.FormFactor); + setIntegerParam(caenFamilyCode_,BoardInfo.FamilyCode); + setStringParam(caenROC_FirmwareRel_,BoardInfo.ROC_FirmwareRel); + setStringParam(caenAMC_FirmwareRel_,BoardInfo.AMC_FirmwareRel); + setIntegerParam(caenSerialNumber_,BoardInfo.SerialNumber); + setIntegerParam(caenPCB_Revision_,BoardInfo.PCB_Revision); + setIntegerParam(caenADC_NBits_,BoardInfo.ADC_NBits); + setIntegerParam(caenSAMCorrectionDataLoaded_,BoardInfo.SAMCorrectionDataLoaded); + setIntegerParam(caenCommHandle_,BoardInfo.CommHandle); + setIntegerParam(caenVMEHandle_,BoardInfo.VMEHandle); + setStringParam(caenLicense_,BoardInfo.License); + + BitMask_ = (1<errorMessage, pasynUser->errorMessageSize, + "%s::%s Could not allocate memory for energy histogram\n", + driverName, functionName); + disconnect(pasynUser); + return asynError; + } + if(THisto[chan] != NULL){ + free(THisto[chan]); + } + THisto[chan] = (uint32_t *)calloc((1 << BoardInfo.ADC_NBits),sizeof(uint32_t)); + if(THisto[chan] == NULL){ + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "%s::%s Could not allocate memory for timing histogram\n", + driverName, functionName); + disconnect(pasynUser); + return asynError; + } + } + + SetDefaultParams(&Params_, &DPPParams_); + ProgramDigitizer(handle_, Params_, DPPParams_); + allocateBuffers(); + + return asynSuccess; +} + +asynStatus drvCaen::allocateBuffers(){ + // This function allocates buffers that the CAEN driver uses + // It must be called after programming the digitizer + int ret = 0; + static const char *functionName = "allocateBuffers"; + /* Allocate readout buffer */ + if (buffer_ != NULL){ + CAEN_DGTZ_FreeReadoutBuffer(&buffer_); + } + ret = CAEN_DGTZ_MallocReadoutBuffer(handle_, &buffer_, &AllocatedSize_); + /* Allocate event buffer */ + if (Events_[0] != NULL){ + CAEN_DGTZ_FreeDPPEvents(handle_, (void **)Events_); + } + ret |= CAEN_DGTZ_MallocDPPEvents(handle_,(void **)Events_, &AllocatedSize_); + /* Allocate waveform buffer */ + if (Waveform_ != NULL){ + ret |= CAEN_DGTZ_FreeDPPWaveforms(handle_,(void **)&Waveform_); + } + ret |= CAEN_DGTZ_MallocDPPWaveforms(handle_,(void **)&Waveform_, &AllocatedSize_); + + if (ret != 0){ + asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, + "%s::%s Could not allocate memory. Error %d\n", + driverName, functionName, ret); + return asynError; + } + + return asynSuccess; +} + +asynStatus drvCaen::writeInt32(asynUser *pasynUser, epicsInt32 value) +{ + int ret = 0; + int command = pasynUser->reason; + asynStatus status=asynSuccess; + int addr; + static const char *functionName = "writeInt32"; + + if (isConnected_ == false) + return asynDisconnected; + + getAddress(pasynUser, &addr); + /* Set the parameter in the parameter library. */ + status = setIntegerParam(addr, command, value); + + if (command == mcaStartAcquire_){ + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Request to start acquiring\n"); + if (!acquiring_) { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Not acquiring yet, requesting"); + ret = CAEN_DGTZ_SWStartAcquisition(handle_); + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Requested"); + if (ret == CAEN_DGTZ_Success) { + acquiring_ = true; + setIntegerParam(mcaAcquiring_, acquiring_); + LastReadTime_ = get_time_ns(); + for(unsigned int i=0; ierrorMessage, pasynUser->errorMessageSize, + "Error starting acquisition"); + checkFailedComm("writeInt32"); + status = asynError; + } + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Done requesting"); + } + } + else if (command == mcaStopAcquire_){ + CAEN_DGTZ_ErrorCode ret; + ret = CAEN_DGTZ_SWStopAcquisition(handle_); + if (ret == CAEN_DGTZ_Success) { + acquiring_ = false; + setIntegerParam(mcaAcquiring_, acquiring_); + } + else { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Error stopping acquisition"); + checkFailedComm("writeInt32"); + status = asynError; + } + } + else if (command == mcaErase_){ + int numChannels; + StartTime_[addr] = LastReadTime_; + getIntegerParam(caenADC_NBits_,&numChannels); + numChannels = 1<errorMessage, pasynUser->errorMessageSize,"Setting threshold, ret = %d\n",ret); + } + else if (command == caenTrapRise_){ + DPPParams_.k[addr] = value; + ret = CAEN_DGTZ_SetDPPParameters(handle_, 1<errorMessage, pasynUser->errorMessageSize,"Setting trapezoid rise time, ret = %d\n",ret); + } + else if (command == caenTrapFlatTop_){ + DPPParams_.m[addr] = value; + ret = CAEN_DGTZ_SetDPPParameters(handle_, 1<errorMessage, pasynUser->errorMessageSize,"Setting trapezoid flat top time, ret = %d\n",ret); + } + else if (command == caenDecayTime_){ + DPPParams_.M[addr] = value; + ret = CAEN_DGTZ_SetDPPParameters(handle_, 1<errorMessage, pasynUser->errorMessageSize,"Setting decay time constant, ret = %d\n",ret); + } + else if (command == caenFlatTopDelay_){ + DPPParams_.ftd[addr] = value; + ret = CAEN_DGTZ_SetDPPParameters(handle_, 1<errorMessage, pasynUser->errorMessageSize,"Setting flat top delay, ret = %d\n",ret); + } + else if (command == caenTrigFiltSmoo_){ + DPPParams_.a[addr] = value; + ret = CAEN_DGTZ_SetDPPParameters(handle_, 1<errorMessage, pasynUser->errorMessageSize,"Setting trigger filter smoothing factor, ret = %d\n",ret); + } + else if (command == caenInputRiseTime_){ + DPPParams_.b[addr] = value; + ret = CAEN_DGTZ_SetDPPParameters(handle_, 1<errorMessage, pasynUser->errorMessageSize,"Setting input signal rise time, ret = %d\n",ret); + } + else if (command == caenTrigHoldOff_){ + DPPParams_.trgho[addr] = value; + ret = CAEN_DGTZ_SetDPPParameters(handle_, 1<errorMessage, pasynUser->errorMessageSize,"Setting trigger hold off, ret = %d\n",ret); + } + else if (command == caenNBaseline_){ + DPPParams_.nsbl[addr] = value; + ret = CAEN_DGTZ_SetDPPParameters(handle_, 1<errorMessage, pasynUser->errorMessageSize,"Setting number of baseline samples, ret = %d\n",ret); + } + else if (command == caenNSPeak_){ + DPPParams_.nspk[addr] = value; + ret = CAEN_DGTZ_SetDPPParameters(handle_, 1<errorMessage, pasynUser->errorMessageSize,"Setting number of sample to average for trapezoid height estimation, ret = %d\n",ret); + } + else if (command == caenPeakHoldOff_){ + DPPParams_.pkho[addr] = value; + ret = CAEN_DGTZ_SetDPPParameters(handle_, 1<errorMessage, pasynUser->errorMessageSize,"Setting peak hold off, ret = %d\n",ret); + } + else if (command == caenBLHoldOff_){ + DPPParams_.blho[addr] = value; + ret = CAEN_DGTZ_SetDPPParameters(handle_, 1<errorMessage, pasynUser->errorMessageSize,"Setting baseline hold off, ret = %d\n",ret); + } + else if (command == caenDecimation_){ + DPPParams_.decimation[addr] = value; + ret = CAEN_DGTZ_SetDPPParameters(handle_, 1<errorMessage, pasynUser->errorMessageSize,"Setting decimation factor, ret = %d\n",ret); + } + else if (command == caenDecGain_){ + DPPParams_.dgain[addr] = value; + ret = CAEN_DGTZ_SetDPPParameters(handle_, 1<errorMessage, pasynUser->errorMessageSize,"Setting decimation gain, ret = %d\n",ret); + } + else if (command == caenTrigWin_){ + DPPParams_.trgwin[addr] = value; + ret = CAEN_DGTZ_SetDPPParameters(handle_, 1<errorMessage, pasynUser->errorMessageSize,"Setting rise time discrimination, ret = %d\n",ret); + } + else if (command == caenTWWDT_){ + DPPParams_.twwdt[addr] = value; + ret = CAEN_DGTZ_SetDPPParameters(handle_, 1<errorMessage, pasynUser->errorMessageSize,"Setting rise time validation window, ret = %d\n",ret); + } + else if (command == caenDCOffset_){ + Params_.DCOffset[addr] = value; + ret = CAEN_DGTZ_SetChannelDCOffset(handle_, addr, Params_.DCOffset[addr]); + if (ret) { + asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, + "%s::%s error calling SetChannelDCOffset(). Err %d\n", + driverName, functionName, ret); + status = asynError; + } + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,"Setting DC offset, ret = %d\n",ret); + } + else if (command == caenPreTriggerSize_){ + Params_.PreTriggerSize[addr] = value; + ret = CAEN_DGTZ_SetDPPPreTriggerSize(handle_, addr, Params_.PreTriggerSize[addr]); + if (ret) { + asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, + "%s::%s error calling SetDPPPreTriggerSize(). Err %d\n", + driverName, functionName, ret); + status = asynError; + } + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,"Setting pre-trigger size, ret = %d\n",ret); + } + else if (command == caenPulsePolarity_){ + if (value == 0){ + Params_.PulsePolarity[addr] = CAEN_DGTZ_PulsePolarityPositive; + } + else if (value == 1){ + Params_.PulsePolarity[addr] = CAEN_DGTZ_PulsePolarityNegative; + } + else { + asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, + "%s::%s Invalid Option (%d) for Pulse Polarity (must be 0 or 1).\n", + driverName, functionName, value); + status = asynError; + } + + ret = CAEN_DGTZ_SetChannelPulsePolarity(handle_, addr, Params_.PulsePolarity[addr]); + if (ret) { + asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, + "%s::%s error calling SetChannelPulsePolarity(). Err %d\n", + driverName, functionName, ret); + status = asynError; + } + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,"Setting pulse-polarity, ret = %d\n",ret); + } + else if (command == caenRegAddr_){ + setIntegerParam(caenRegAddr_, value); + } + else if (command == caenRegister_){ + int regAddr; + getIntegerParam(caenRegAddr_, ®Addr); + ret = CAEN_DGTZ_WriteRegister(handle_, regAddr, value); + if (ret) { + asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, + "%s::%s error calling WriteRegister(). Err %d\n", + driverName, functionName, ret); + status = asynError; + } + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,"Writing register, ret = %d\n",ret); + } + //TODO + // else if (command == mcaNumChannels_) { + // if (value > 0) { + // numChannels_ = value; + // if (pData_[addr]) free(pData_[addr]); + // pData_[addr] = (epicsInt32 *)calloc(numChannels_, sizeof(epicsInt32)); + // } + // } + // // All other commands are parameters so we send the configuration + else { + //TODO + } + callParamCallbacks(addr); + return status; +} + +asynStatus drvCaen::readInt32(asynUser *pasynUser, epicsInt32 *value) +{ + int command = pasynUser->reason; + asynStatus status=asynSuccess; + int mcaEnable, liveTimeDone, realTimeDone, countDone, mcsDone; + static const char *functionName = "readInt32"; + int ret = 0; + + int addr; + + if (isConnected_ == false) + return asynDisconnected; + + getAddress(pasynUser, &addr); + + if (command == mcaAcquiring_) { + double Preset; + //TODO: Look into mcsDone/mcaEnable + //TODO: Not currently evaluating PCTL and PCTH for PresetCounts + getDoubleParam(addr, mcaPresetCounts_, &Preset); + if (Preset > 0) { + countDone = TrgCnt[addr] > Preset; + } + else { + countDone = 0; + } + getDoubleParam(addr, mcaPresetRealTime_, &Preset); + if (Preset > 0) { + realTimeDone = LastReadTime_ - StartTime_[addr] > 1000.0 * Preset; + } + else { + realTimeDone = 0; + } + getDoubleParam(addr, mcaPresetLiveTime_, &Preset); + if (Preset > 0) { + liveTimeDone = LastReadTime_ - StartTime_[addr] > 1000.0 * Preset; + } + else { + liveTimeDone = 0; + } + mcsDone = 0; + mcaEnable = 1; + if (countDone || realTimeDone || liveTimeDone || mcsDone || !mcaEnable) { + // Some preset is reached. If acquiring_ is true then stop detector + if (acquiring_) { + ret = CAEN_DGTZ_SWStopAcquisition(handle_); + if (ret == CAEN_DGTZ_Success) { + acquiring_ = false; + setIntegerParam(mcaAcquiring_, acquiring_); + } + else { + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "Error stopping acquisition"); + checkFailedComm("writeInt32"); + status = asynError; + } + } + } + *value = acquiring_; + } + else if (command == caenBoardTemp_){ + uint32_t board_temp; + ret = CAEN_DGTZ_ReadTemperature(handle_, addr, &board_temp); + if (ret) { + asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, + "%s::%s error calling ReadTemperature(). Err %d\n", + driverName, functionName, ret); + status = asynError; + } + *value = board_temp; + } + else if (command == caenTrigThresh_){ + *value = DPPParams_.thr[addr]; + } + else if (command == caenTrapRise_){ + *value = DPPParams_.k[addr]; + } + else if (command == caenTrapFlatTop_){ + *value = DPPParams_.m[addr]; + } + else if (command == caenDecayTime_){ + *value = DPPParams_.M[addr]; + } + else if (command == caenFlatTopDelay_){ + *value = DPPParams_.ftd[addr]; + } + else if (command == caenTrigFiltSmoo_){ + *value = DPPParams_.a[addr]; + } + else if (command == caenInputRiseTime_){ + *value = DPPParams_.b[addr]; + } + else if (command == caenTrigHoldOff_){ + *value = DPPParams_.trgho[addr]; + } + else if (command == caenNBaseline_){ + *value = DPPParams_.nsbl[addr]; + } + else if (command == caenNSPeak_){ + *value = DPPParams_.nspk[addr]; + } + else if (command == caenPeakHoldOff_){ + *value = DPPParams_.pkho[addr]; + } + else if (command == caenBLHoldOff_){ + *value = DPPParams_.blho[addr]; + } + else if (command == caenDecimation_){ + *value = DPPParams_.decimation[addr]; + } + else if (command == caenDecGain_){ + *value = DPPParams_.dgain[addr]; + } + else if (command == caenTrigWin_){ + *value = DPPParams_.trgwin[addr]; + } + else if (command == caenTWWDT_){ + *value = DPPParams_.twwdt[addr]; + } + else if (command == caenDCOffset_){ + *value = Params_.DCOffset[addr]; + } + else if (command == caenPreTriggerSize_){ + *value = Params_.PreTriggerSize[addr]; + } + else if (command == caenPulsePolarity_){ + *value = Params_.PulsePolarity[addr]; + } + else if (command == caenRegAddr_){ + getIntegerParam(caenRegAddr_, value); + } + else if (command == caenRegister_){ + int regAddr; + getIntegerParam(caenRegAddr_, ®Addr); + ret = CAEN_DGTZ_ReadRegister(handle_, regAddr, (uint32_t*) value); + if (ret) { + asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, + "%s::%s error calling ReadRegister(). Err %d\n", + driverName, functionName, ret); + status = asynError; + } + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,"Read register, ret = %d\n",ret); + } + else { + status = asynPortDriver::readInt32(pasynUser, value); + } + if (status != asynSuccess){ + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "%s::%s Digitizer (%s) Error reading Int32 (command = %d)\n", + driverName, functionName, portName, command); + } + return status; +} + +asynStatus drvCaen::readFloat64(asynUser *pasynUser, epicsFloat64 *value) +{ + int command = pasynUser->reason; + asynStatus status=asynSuccess; + static const char *functionName = "readFloat64"; + + int addr; + + if (isConnected_ == false) + return asynDisconnected; + getAddress(pasynUser, &addr); + + if (command == mcaElapsedLiveTime_) { + *value = 1e-9 * (LastReadTime_ - StartTime_[addr]); + } + else if (command == mcaElapsedRealTime_) { + *value = 1e-9 * (LastReadTime_ - StartTime_[addr]); + } + else if (command == mcaElapsedCounts_) { + *value = TrgCnt[addr]; + } + else if (command == caenEnergyNF_){ + *value = DPPParams_.enf[addr]; + } + else { + status = asynPortDriver::readFloat64(pasynUser, value); + } + if (status != asynSuccess){ + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "%s::%s Digitizer (%s) Error reading Float64 (command = %d)\n", + driverName, functionName, portName, command); + } + return status; +} + + +asynStatus drvCaen::writeFloat64(asynUser *pasynUser, epicsFloat64 value) +{ + int command = pasynUser->reason; + asynStatus status=asynSuccess; + static const char *functionName = "writeFloat64"; + int ret = 0; + + int addr; + if (isConnected_ == false) + return asynDisconnected; + + getAddress(pasynUser, &addr); + + if (command == caenEnergyNF_){ + DPPParams_.enf[addr] = value; + ret = CAEN_DGTZ_SetDPPParameters(handle_, 1<errorMessage, pasynUser->errorMessageSize,"Setting energy normalization factor, ret = %d\n",ret); + } +// else (command == caenPollPeriod_){ + + + /* Set the parameter in the parameter library. */ + status = setDoubleParam(addr, command, value); + + callParamCallbacks(addr); + if (status != asynSuccess){ + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "%s::%s Digitizer (%s) Error writing Float64 (command = %d)\n", + driverName, functionName, portName, command); + } + return status; +} + +asynStatus drvCaen::readInt32Array(asynUser *pasynUser, + epicsInt32 *data, size_t maxChans, + size_t *nactual) +{ + unsigned int numChannels; + static const char *functionName="readInt32Array"; + int addr; + + if (isConnected_ == false) + return asynDisconnected; + + getAddress(pasynUser, &addr); + /* Check ADC index */ + if(addr >= MAX_ADCS || addr < 0){ + *nactual = 0; + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "%s::%s Digitizer (%s) ADC Index %d does not exist\n", + driverName, functionName, portName, addr); + return asynError; + } + + /* If channel is disabled, don't process data */ + if (!(Params_.ChannelMask & (1< (unsigned int)maxChans){ + epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, + "%s::%s Digitizer (%s) Board provided more channels than available: cropping histogram.\n", + driverName, functionName, portName); + numChannels = maxChans; + } + for (unsigned int i=0; ierrorMessage, pasynUser->errorMessageSize,"Numchannels = %d\n",numChannels); + return asynSuccess; +} + +void readThread(void *drvPvt) +{ + drvCaen *pPvt = (drvCaen *)drvPvt; + pPvt->readThread(); +} + +void drvCaen::readThread(void) +{ + double pollPeriod; + int ret; + static const char *functionName = "readThread"; + + lock(); + /* Loop until it's time to exit */ + while (1) { + if (exiting_) break; + // TODO: make it so that pollPeriod accounts for thread run time + getDoubleParam(caenPollPeriod_, &pollPeriod); + // Release the lock while we wait for a command to start or wait for pollPeriod + unlock(); + if (acquiring_) epicsEventWaitWithTimeout(eventId_, pollPeriod); + else (void) epicsEventWait(eventId_); + // Take the lock again + lock(); + /* acquisition might have stopped while we were waiting */ + if (!acquiring_) continue; + ret = CAEN_DGTZ_ReadData(handle_, CAEN_DGTZ_SLAVE_TERMINATED_READOUT_MBLT, buffer_, &BufferSize_); + LastReadTime_ = get_time_ns(); + if (ret) { + asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, + "%s::%s error calling ReadData(). Err %d\n", + driverName, functionName, ret); + checkFailedComm(functionName); + } + + if(BufferSize_>0){ + ret |= CAEN_DGTZ_GetDPPEvents(handle_, buffer_, BufferSize_, (void**)Events_, NumEvents_); + if (ret) { + asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, + "%s::%s error calling GetDPPEvents(). Err %d\n", + driverName, functionName, ret); + } + epicsSnprintf(pasynUserSelf->errorMessage, pasynUserSelf->errorMessageSize,"Reading board, ret = %d\n",ret); + } + for (unsigned int addr = 0; addr < MAX_ADCS; addr++){ + /* If channel is disabled, don't process data */ + if (!(Params_.ChannelMask & (1<= 0) { + // Fill the histograms + //EHisto[addr][(Events[addr][ev].TimeTag)&BitMask]++; + EHisto[addr][(Events_[addr][ev].Energy)&BitMask_]++; + ECnt[addr]++; + THisto[addr][(Events_[addr][ev].TimeTag-PrevTime[addr])&BitMask_]++; + } else { /* PileUp */ + PurCnt[addr]++; + } + PrevTime[addr] = Events_[addr][ev].TimeTag; + } // loop on events + // Make sure events don't get read twice + //NumEvents_[addr] = 0; + } + } + unlock(); +} + +extern "C" { + int drvCaenConfigure(const char *portName, int LinkType, int LinkNum, int ConetNode, int VMEBaseAddress) + { + new drvCaen(portName, (CAEN_DGTZ_ConnectionType) LinkType, LinkNum, ConetNode, VMEBaseAddress); + return asynSuccess; + } + + static const iocshArg configArg0 = { "portName", iocshArgString}; + static const iocshArg configArg1 = { "LinkType", iocshArgInt}; + static const iocshArg configArg2 = { "LinkNum", iocshArgInt}; + static const iocshArg configArg3 = { "ConetNode", iocshArgInt}; + static const iocshArg configArg4 = { "VMEBaseAddress", iocshArgInt}; + static const iocshArg * const configArgs[] = {&configArg0, + &configArg1, + &configArg2, + &configArg3, + &configArg4}; + static const iocshFuncDef configFuncDef = {"drvCaenConfigure", 5, configArgs}; + static void configCallFunc(const iocshArgBuf *args) + { + drvCaenConfigure(args[0].sval, args[1].ival, args[2].ival, args[3].ival, args[4].ival); + } + + void drvCaenRegister(void) + { + iocshRegister(&configFuncDef,configCallFunc); + } + + epicsExportRegistrar(drvCaenRegister); + +} diff --git a/mcaApp/CaenSrc/drvCaen.h b/mcaApp/CaenSrc/drvCaen.h new file mode 100644 index 00000000..3abcf2f8 --- /dev/null +++ b/mcaApp/CaenSrc/drvCaen.h @@ -0,0 +1,240 @@ +/* File: drvCaen.cpp + * Author: Pedro Nariyoshi, Facility for Rare Isotope Beams + * Date: 18-January-2024 + * + * Purpose: + * This module provides the driver support for the MCA asyn device support layer + * for C.A.E.N. MCAs that support the CAENDigitizer library. + * + */ + +#ifndef DRVCAEN_H +#define DRVCAEN_H + +/************/ +/* Includes */ +/************/ + +/* EPICS includes */ +#include +#include +#include + +/* CAEN includes */ +#include +#include + +/* Local includes */ +#include "ParamStruct.h" +#include "DigitizerFunctions.h" + +/* Std libraries */ +#include +#include +#include +#include + +// CAEN-specific board parameter strings +#define caenModelNameString "CAEN_MODEL_NAME" +#define caenModelString "CAEN_MODEL" +#define caenNADCsString "CAEN_CHANNELS" +#define caenFormFactorString "CAEN_FORM_FACTOR" +#define caenFamilyCodeString "CAEN_FAMILY_CODE" +#define caenROCFirmwareString "CAEN_ROC_FIRMWARE" +#define caenAMCFirmwareString "CAEN_AMC_FIRMWARE" +#define caenSerialNumberString "CAEN_SERIAL_NUMBER" +#define caenMezzanineSerNumString "CAEN_MEZZ_SER_NUM" +#define caenPCBRevisionString "CAEN_PCB_REV" +#define caenADCNBITSString "CAEN_ADC_NBITS" +#define caenSAMCorrectionString "CAEN_SAM_CORRECTION" +#define caenCommHandleString "CAEN_COMM_HANDLE" +#define caenVMEHandleString "CAEN_VME_HANDLE" +#define caenLicenseString "CAEN_LICENSE" +#define caenDCOffsetString "CAEN_DC_OFFSET" +#define caenPreTriggerSizeString "CAEN_PRETRIG_SIZE" +#define caenPulsePolarityString "CAEN_PULSE_POL" +#define caenBoardTempString "CAEN_BOARD_TEMP" +// CAEN-specific channel parameter strings +#define caenTrigThreshString "CAEN_TRIG_THRESH" // Trigger Threshold (in LSB) +#define caenTrapRiseString "CAEN_TRAP_RISE" // Trapezoid Rise Time (ns) +#define caenTrapFlatTopString "CAEN_TRAP_FT" // Trapezoid Flat Top (ns) +#define caenDecayTimeString "CAEN_DECAY_TIME" // Decay Time Constant (ns) +#define caenFlatTopDelayString "CAEN_FLAT_DELAY" // Flat top delay (peaking time) (ns) +#define caenTrigFiltSmooString "CAEN_TRIG_FILT_SMOO" // Trigger Filter smoothing factor (number of samples to average for RC-CR2 filter) Options: 1; 2; 4; 8; 16; 32 +#define caenInputRiseTimeString "CAEN_INPUT_RISE" // Input Signal Rise time (ns) +#define caenTrigHoldOffString "CAEN_TRIG_HOFF" // Trigger Hold Off +#define caenNBaselineString "CAEN_NSBL" //number of samples for baseline average calculation. Options: 1->16 samples; 2->64 samples; 3->256 samples; 4->1024 samples; 5->4096 samples; 6->16384 samples +#define caenNSPeakString "CAEN_NSPK" //Peak mean (number of samples to average for trapezoid height calculation). Options: 0-> 1 sample; 1->4 samples; 2->16 samples; 3->64 samples +#define caenPeakHoldOffString "CAEN_PKHO" //peak holdoff (ns) +#define caenBLHoldOffString "CAEN_BLHO" //Baseline holdoff (ns) +#define caenEnergyNFString "CAEN_ENF" // Energy Normalization Factor +#define caenDecimationString "CAEN_DECIMATION" //decimation (the input signal samples are averaged within this number of samples): 0 ->disabled; 1->2 samples; 2->4 samples; 3->8 samples +#define caenDecGainString "CAEN_DEC_GAIN" //decimation gain. Options: 0->DigitalGain=1; 1->DigitalGain=2 (only with decimation >= 2samples); 2->DigitalGain=4 (only with decimation >= 4samples); 3->DigitalGain=8( only with decimation = 8samples). +#define caenTrigWinString "CAEN_TRIG_WIN" //Enable Rise time Discrimination. Options: 0->disabled; 1->enabled +#define caenTWWDTString "CAEN_TW_WDT" // Rise Time Validation Window (ns) + // CAEN-specific miscellaneous parameter strings +#define caenRegAddrString "CAEN_REGADDR" // Select the register address +#define caenRegisterString "CAEN_REGISTER" // Direct manipulation of registers +#define caenPollPeriodString "CAEN_POLLPERIOD" // Select the poll period for the internal thread + +// Maximum number of channels +#define MAX_ADCS MAX_DPP_PHA_CHANNEL_SIZE +// Number of failed sends needed to disconnect +#define MAX_FAILED_SENDS 10 + +class drvCaen : public asynPortDriver +{ + public: + drvCaen(const char *portName, CAEN_DGTZ_ConnectionType LinkType, int LinkNum, int ConetNode, unsigned int VMEBaseAddress); + ~drvCaen(); + void exitHandler(); + + // These are the methods we override from asynPortDriver + // virtual asynStatus getBounds(asynUser *pasynUser, epicsInt32 *low, epicsInt32 *high); + virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value); + virtual asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value); + virtual asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value); + virtual asynStatus readFloat64(asynUser *pasynUser, epicsFloat64 *value); + virtual asynStatus readInt32Array(asynUser *pasynUser, epicsInt32 *data, + size_t maxChans, size_t *nactual); + // virtual void report(FILE *fp, int details); + virtual asynStatus connect(asynUser *pasynUser); + // virtual asynStatus disconnect(asynUser *pasynUser); + // virtual asynStatus readOption(asynUser *pasynUser, const char *key, char *value, int maxChars); + // virtual asynStatus writeOption(asynUser *pasynUser, const char *key, const char *value); + + // These are the methods that are new to this class + void readThread(void); + + protected: + // These are the standard MCA commands +#define FIRST_CAEN_PARAM mcaStartAcquire_ + int mcaStartAcquire_; + int mcaStopAcquire_; + int mcaErase_; + int mcaData_; + int mcaReadStatus_; + int mcaChannelAdvanceSource_; + int mcaNumChannels_; + int mcaDwellTime_; + int mcaPresetLiveTime_; + int mcaPresetRealTime_; + int mcaPresetCounts_; + int mcaPresetLowChannel_; + int mcaPresetHighChannel_; + int mcaPresetSweeps_; + int mcaAcquireMode_; + int mcaSequence_; + int mcaPrescale_; + int mcaAcquiring_; + int mcaElapsedLiveTime_; + int mcaElapsedRealTime_; + int mcaElapsedCounts_; + + // These are the CAEN-specific board commands + int caenModelName_; + int caenModel_; + int caenNADCs_; + int caenFormFactor_; + int caenFamilyCode_; + int caenROC_FirmwareRel_; + int caenAMC_FirmwareRel_; + int caenSerialNumber_; + int caenMezzSerNum_; //used only for x743 boards + int caenPCB_Revision_; + int caenADC_NBits_; + int caenSAMCorrectionDataLoaded_; //used only for x743 boards; + int caenCommHandle_; + int caenVMEHandle_; + int caenLicense_; + int caenBoardTemp_; + + // CAEN-specific channel parameter strings + int caenDCOffset_; + int caenPulsePolarity_; + int caenPreTriggerSize_; + int caenTrigThresh_; + int caenTrapRise_; + int caenTrapFlatTop_; + int caenDecayTime_; + int caenFlatTopDelay_; + int caenTrigFiltSmoo_; + int caenInputRiseTime_; + int caenTrigHoldOff_; + int caenNBaseline_; + int caenNSPeak_; + int caenPeakHoldOff_; + int caenBLHoldOff_; + int caenEnergyNF_; + int caenDecimation_; + int caenDecGain_; + int caenOTRej_; + int caenTrigWin_; + int caenTWWDT_; + + // CAEN-specific miscellaneous parameter strings + int caenRegAddr_; + int caenRegister_; + int caenPollPeriod_; +#define LAST_CAEN_PARAM caenPollPeriod_ + + private: + epicsEventId eventId_; + epicsThreadId threadId_; + bool exiting_; + + // Setting/parameter variables + DigitizerParams_t Params_; // Parameter struct + CAEN_DGTZ_DPP_PHA_Params_t DPPParams_; // DPP Parameter struct + + // Data-analysis variables/buffers + uint64_t StartTime_[MAX_ADCS]; + uint64_t LastReadTime_; + uint32_t AllocatedSize_, BufferSize_; + char *buffer_ = NULL; // readout buffer + CAEN_DGTZ_DPP_PHA_Event_t *Events_[MAX_ADCS]; // events buffer + CAEN_DGTZ_DPP_PHA_Waveforms_t *Waveform_=NULL; // waveforms buffer + uint64_t PrevTime[MAX_ADCS]; + uint64_t ExtendedTT[MAX_ADCS]; + uint32_t NumEvents_[MAX_ADCS]; // Energy Histograms + uint32_t *EHisto[MAX_ADCS]; // Energy Histograms + uint32_t *THisto[MAX_ADCS]; // Timing Histograms + uint64_t TrgCnt[MAX_ADCS]; // Cumulative Trigger Counts + uint64_t ECnt[MAX_ADCS]; // Trigger Counts with valid energy + uint64_t PurCnt[MAX_ADCS]; // Trigger Counts with invalid energy (Pile-Up) + // Driver variables + int handle_; + int BitMask_; + // asynStatus disconnectDevice(); + asynStatus connectDevice(asynUser *pasynUser); + bool directConnect(char* address); + void checkFailedComm(const char *functionName); + // size_t numChannels_; + // asynStatus findModule(); + // asynStatus sendCommand(TRANSMIT_PACKET_TYPE command); + // asynStatus sendCommandString(string commandString); + // asynStatus sendConfiguration(); + // asynStatus sendSCAs(); + // asynStatus sendConfigurationFile(string fileName); + // asynStatus saveConfigurationFile(string fileName); + // asynStatus readConfigurationFromHardware(); + // asynStatus parseConfiguration(); + // asynStatus parseConfigDouble(const char *str, int param); + // asynStatus parseConfigInt(const char *str, int param); + asynStatus allocateBuffers(); + // asynStatus parseConfigEnum(const char *str, const char *enumStrs[], int numEnums, int param); + // dp5DppTypes dppType_; + bool acquiring_; + // bool haveConfigFromHW_; + // DppInterface_t interfaceType_; + // char *addressInfo_; + // bool directMode_; + int failedSends_; + bool isConnected_; + void setParamsAlarm(int alarmStatus, int alarmSeverity); +}; + +#define NUM_PARAMS (&LAST_CAEN_PARAM - &FIRST_CAEN_PARAM + 1) + +#endif + diff --git a/mcaApp/CaenSrc/mcaCaenAppMain.cpp b/mcaApp/CaenSrc/mcaCaenAppMain.cpp new file mode 100644 index 00000000..ae0ecb68 --- /dev/null +++ b/mcaApp/CaenSrc/mcaCaenAppMain.cpp @@ -0,0 +1,23 @@ +/* _APPNAME_Main.cpp */ +/* Author: Marty Kraimer Date: 17MAR2000 */ + +#include +#include +#include +#include +#include + +#include "epicsExit.h" +#include "epicsThread.h" +#include "iocsh.h" + +int main(int argc,char *argv[]) +{ + if(argc>=2) { + iocsh(argv[1]); + epicsThreadSleep(.2); + } + iocsh(NULL); + epicsExit(0); + return(0); +} diff --git a/mcaApp/CaenSrc/mcaCaenSupport.dbd b/mcaApp/CaenSrc/mcaCaenSupport.dbd new file mode 100644 index 00000000..f0b93cf7 --- /dev/null +++ b/mcaApp/CaenSrc/mcaCaenSupport.dbd @@ -0,0 +1,4 @@ +################ +# Register global functions +################ +registrar(drvCaenRegister) diff --git a/mcaApp/Db/Caen.db b/mcaApp/Db/Caen.db new file mode 100644 index 00000000..b315bef1 --- /dev/null +++ b/mcaApp/Db/Caen.db @@ -0,0 +1,144 @@ +record(stringin,"$(P)$(R)Model") { + field(DESC,"Caen Model Name") + field(DTYP, "asynOctetRead") + field(INP, "@asyn($(PORT))CAEN_MODEL_NAME") + field(SCAN, "I/O Intr") +} + +record(longin,"$(P)$(R)ModelNumber") { + field(DESC,"Caen Model Number") + field(DTYP, "asynInt32") + field(INP, "@asyn($(PORT))CAEN_MODEL") + field(SCAN, "I/O Intr") +} + +record(longin,"$(P)$(R)Channels") { + field(DESC,"Caen Number of Channels") + field(DTYP, "asynInt32") + field(INP, "@asyn($(PORT))CAEN_CHANNELS") + field(SCAN, "I/O Intr") +} + +record(mbbi,"$(P)$(R)FormFactor") { + field(DESC,"Caen Form Factor") + field(DTYP, "asynInt32") + field(INP, "@asyn($(PORT))CAEN_FORM_FACTOR") + field(SCAN, "I/O Intr") + field(ZRVL, "0") + field(ONVL, "1") + field(TWVL, "2") + field(THVL, "3") + field(ZRST, "VME64") + field(ONST, "VME64x") + field(TWST, "Desktop") + field(FRST, "NIM") +} + +# If they include new families in this library, a new approach might be needed. +record(mbbi,"$(P)$(R)FamilyCode") { + field(DESC,"Caen Family Code") + field(DTYP, "asynInt32") + field(INP, "@asyn($(PORT))CAEN_FAMILY_CODE") + field(SCAN, "I/O Intr") + field(ZRVL, "0") + field(ONVL, "1") + field(TWVL, "2") + field(THVL, "3") + field(FRVL, "4") + field(FVVL, "5") + field(SXVL, "6") + field(SVVL, "7") + field(EIVL, "8") + field(NIVL, "9") + field(TEVL, "11") + field(ELVL, "12") + field(TVVL, "13") + field(TTVL, "14") + field(FTVL, "15") + field(ZRST, "xx724") + field(ONST, "xx721") + field(TWST, "xx731") + field(THST, "xx720") + field(FRST, "xx740") + field(FVST, "xx751") + field(SXST, "xx742") + field(SVST, "xx780") + field(EIST, "xx761") + field(NIST, "xx743") + field(TEST, "xx730") + field(ELST, "xx790") + field(TVST, "xx781") + field(TTST, "xx725") + field(FTST, "xx782") +} + +record(stringin,"$(P)$(R)ROC_Firmware") { + field(DESC,"Caen ROC Firmware") + field(DTYP, "asynOctetRead") + field(INP, "@asyn($(PORT))CAEN_ROC_FIRMWARE") + field(SCAN, "I/O Intr") +} + +record(stringin,"$(P)$(R)AMC_Firmware") { + field(DESC,"Caen AMC Firmware") + field(DTYP, "asynOctetRead") + field(INP, "@asyn($(PORT))CAEN_AMC_FIRMWARE") + field(SCAN, "I/O Intr") +} + +record(longin,"$(P)$(R)SerialNumber") { + field(DESC,"Caen Serial Number") + field(DTYP, "asynInt32") + field(INP, "@asyn($(PORT))CAEN_SERIAL_NUMBER") + field(SCAN, "I/O Intr") +} + +record(stringin,"$(P)$(R)MezzanineSerNum") { + field(DESC,"Caen Mezzanine Serial Number") + field(DTYP, "asynOctetRead") + field(INP, "@asyn($(PORT))CAEN_MEZZ_SER_NUM") + field(SCAN, "I/O Intr") +} + +record(longin,"$(P)$(R)PCBRevision") { + field(DESC,"Caen Number of Channels") + field(DTYP, "asynInt32") + field(INP, "@asyn($(PORT))CAEN_PCB_REV") + field(SCAN, "I/O Intr") +} + +record(longin,"$(P)$(R)ADC_Nbits") { + field(DESC,"Caen ADC Number of Bits") + field(DTYP, "asynInt32") + field(INP, "@asyn($(PORT))CAEN_ADC_NBITS") + field(SCAN, "I/O Intr") +} + +record(longin,"$(P)$(R)SAM_Correction") { + field(DESC,"Caen SAM Correction") + field(DTYP, "asynInt32") + field(INP, "@asyn($(PORT))CAEN_SAM_CORRECTION") + field(SCAN, "I/O Intr") +} + +record(longin,"$(P)$(R)COMM_Handle") { + field(DESC,"Caen COMM Handle") + field(DTYP, "asynInt32") + field(INP, "@asyn($(PORT))CAEN_COMM_HANDLE") + field(SCAN, "I/O Intr") +} + +record(longin,"$(P)$(R)VME_Handle") { + field(DESC,"Caen VME Handle") + field(DTYP, "asynInt32") + field(INP, "@asyn($(PORT))CAEN_VME_HANDLE") + field(SCAN, "I/O Intr") +} + +record(stringin,"$(P)$(R)License") { + field(DESC,"Caen License Number") + field(DTYP, "asynOctetRead") + field(INP, "@asyn($(PORT))CAEN_LICENSE") + field(SCAN, "I/O Intr") +} + diff --git a/mcaApp/Db/CaenBoard.db b/mcaApp/Db/CaenBoard.db new file mode 100755 index 00000000..13ee358d --- /dev/null +++ b/mcaApp/Db/CaenBoard.db @@ -0,0 +1,143 @@ +grecord(calc,"$(P)$(M)CheckACQG") { + field(INPA,"$(P)$(M1).ACQG CP MS") + field(INPB,"$(P)$(M2).ACQG CP MS") + field(INPC,"$(P)$(M3).ACQG CP MS") + field(INPD,"$(P)$(M4).ACQG CP MS") + field(INPE,"$(P)$(M5).ACQG CP MS") + field(INPF,"$(P)$(M6).ACQG CP MS") + field(INPG,"$(P)$(M7).ACQG CP MS") + field(INPH,"$(P)$(M8).ACQG CP MS") + field(CALC,"(a||b||c||d||e||f||g||h)?1:0") +} + +grecord(dfanout,"$(P)$(M)EraseAll") { + field(OMSL,"closed_loop") + field(DOL,"1") + field(OUTA,"$(P)$(M1).ERAS PP MS") + field(OUTB,"$(P)$(M2).ERAS PP MS") + field(OUTC,"$(P)$(M3).ERAS PP MS") + field(OUTD,"$(P)$(M4).ERAS PP MS") + field(OUTE,"$(P)$(M5).ERAS PP MS") + field(OUTF,"$(P)$(M6).ERAS PP MS") + field(OUTG,"$(P)$(M7).ERAS PP MS") + field(OUTH,"$(P)$(M8).ERAS PP MS") +} + +grecord(dfanout,"$(P)$(M)EraseStartAll") { + field(OMSL,"closed_loop") + field(DOL,"1") + field(OUTA,"$(P)$(M1).ERST PP MS") + field(OUTB,"$(P)$(M2).ERST PP MS") + field(OUTC,"$(P)$(M3).ERST PP MS") + field(OUTD,"$(P)$(M4).ERST PP MS") + field(OUTE,"$(P)$(M5).ERST PP MS") + field(OUTF,"$(P)$(M6).ERST PP MS") + field(OUTG,"$(P)$(M7).ERST PP MS") + field(OUTH,"$(P)$(M8).ERST PP MS") +} + +grecord(dfanout,"$(P)$(M)StartAll") { + field(OMSL,"closed_loop") + field(DOL,"1") + field(OUTA,"$(P)$(M1).STRT PP MS") + field(OUTB,"$(P)$(M2).STRT PP MS") + field(OUTC,"$(P)$(M3).STRT PP MS") + field(OUTD,"$(P)$(M4).STRT PP MS") + field(OUTE,"$(P)$(M5).STRT PP MS") + field(OUTF,"$(P)$(M6).STRT PP MS") + field(OUTG,"$(P)$(M7).STRT PP MS") + field(OUTH,"$(P)$(M8).STRT PP MS") +} + +grecord(dfanout,"$(P)$(M)StopAll") { + field(OMSL,"closed_loop") + field(DOL,"1") + field(OUTA,"$(P)$(M1).STOP PP MS") + field(OUTB,"$(P)$(M2).STOP PP MS") + field(OUTC,"$(P)$(M3).STOP PP MS") + field(OUTD,"$(P)$(M4).STOP PP MS") + field(OUTE,"$(P)$(M5).STOP PP MS") + field(OUTF,"$(P)$(M6).STOP PP MS") + field(OUTG,"$(P)$(M7).STOP PP MS") + field(OUTH,"$(P)$(M8).STOP PP MS") +} + + +grecord(dfanout,"$(P)$(M)ReadAll") { + field(SCAN,"1 second") + field(OMSL,"closed_loop") + field(DOL,"1") + field(OUTA,"$(P)$(M1).READ PP MS") + field(OUTB,"$(P)$(M2).READ PP MS") + field(OUTC,"$(P)$(M3).READ PP MS") + field(OUTD,"$(P)$(M4).READ PP MS") + field(OUTE,"$(P)$(M5).READ PP MS") + field(OUTF,"$(P)$(M6).READ PP MS") + field(OUTG,"$(P)$(M7).READ PP MS") + field(OUTH,"$(P)$(M8).READ PP MS") +} + +grecord(bo,"$(P)$(M)Status") { + field(SDIS,"$(P)$(M)CheckACQG NPP NMS") + field(DISV,"0") + field(SCAN,".1 second") + field(OMSL,"closed_loop") + field(DOL,"1") + field(OUT,"$(P)$(M)StatusAll.PROC CA NMS") +} + +grecord(dfanout,"$(P)$(M)StatusAll") { + field(OMSL,"closed_loop") + field(DOL,"1") + field(OUTA,"$(P)$(M1).PROC PP MS") + field(OUTB,"$(P)$(M2).PROC PP MS") + field(OUTC,"$(P)$(M3).PROC PP MS") + field(OUTD,"$(P)$(M4).PROC PP MS") + field(OUTE,"$(P)$(M5).PROC PP MS") + field(OUTF,"$(P)$(M6).PROC PP MS") + field(OUTG,"$(P)$(M7).PROC PP MS") + field(OUTH,"$(P)$(M8).PROC PP MS") +} + +grecord(ao,"$(P)$(M)PollPeriod") { + field(DESC, "Polling period of internal thread") + field(EGU, "s") + field(DTYP, "asynFloat64") + field(OUT,"@asyn($(PORT),0)CAEN_POLLPERIOD") +} + +grecord(ai,"$(P)$(M)PollPeriod_RBV") { + field(DESC, "Polling period of internal thread") + field(EGU, "s") + field(DTYP, "asynFloat64") + field(INP,"@asyn($(PORT),0)CAEN_POLLPERIOD") + field(PINI, "YES") +} + +grecord(longout,"$(P)$(M)WhichRegister") { + field(DESC, "Select which register to manipulate") + field(DTYP, "asynInt32") + field(OUT,"@asyn($(PORT),0)CAEN_REGADDR") +} + +grecord(longin,"$(P)$(M)WriteRegisterValue") { + field(DESC, "Write register value") + field(UDF, "0") +} + +grecord(longout,"$(P)$(M)WriteRegister") { + field(DOL, "$(P)$(M)WriteRegisterValue") + field(OMSL, "closed_loop") + field(DESC, "Write register") + field(DTYP, "asynInt32") + field(OUT,"@asyn($(PORT),0)CAEN_REGISTER") + field(UDF, "0") +} + +grecord(longin,"$(P)$(M)ReadRegister") { + field(SDIS,"$(P)$(M)WhichRegister") + field(DISV,"0") + field(DESC, "Read register") + field(DTYP, "asynInt32") + field(INP,"@asyn($(PORT),0)CAEN_REGISTER") +} diff --git a/mcaApp/Db/CaenChannel.db b/mcaApp/Db/CaenChannel.db new file mode 100644 index 00000000..ad7ddab1 --- /dev/null +++ b/mcaApp/Db/CaenChannel.db @@ -0,0 +1,509 @@ +#TODO: Write correct description for each parameter +record(longin,"$(P)$(R):ADC_Temp") { + field(DESC,"ADC Temp for $(PORT) $(CHAN)") + field(DTYP, "asynInt32") + field(INP, "@asyn($(PORT) $(CHAN))CAEN_BOARD_TEMP") + field(SCAN, "1 second") +} + +grecord(calc,"$(P)$(R):CheckACQG") { + field(INPA,"$(P)$(R).ACQG CP MS") + field(CALC,"a?1:2") +} + +grecord(bo,"$(P)$(R):Erase") { + field(OMSL,"closed_loop") + field(DOL,"1") + field(OUT,"$(P)$(R).ERAS PP MS") + field(ONAM,"Erase") + field(ZNAM,"Done") +} + +grecord(bo,"$(P)$(R):EraseStart") { + field(OMSL,"closed_loop") + field(DOL,"1") + field(OUT,"$(P)$(R).ERST PP MS") + field(ONAM,"EraseStart") + field(ZNAM,"Done") +} +grecord(bo,"$(P)$(R):Start") { + field(OMSL,"closed_loop") + field(DOL,"1") + field(OUT,"$(P)$(R).STRT PP MS") + field(ONAM,"Start") + field(ZNAM,"Done") +} + +grecord(bo,"$(P)$(R):Stop") { + field(OMSL,"closed_loop") + field(DOL,"1") + field(OUT,"$(P)$(R).STOP CA MS") + field(ONAM,"Stop") + field(ZNAM,"Done") +} + +grecord(longout,"$(P)$(R):Threshold") { + field(DESC,"Slow threshold") + field(EGU, "LSB") + field(DRVL, "0") + field(DRVH, "65535") + field(DTYP, "asynInt32") + field(OUT, "@asyn($(PORT) $(CHAN))CAEN_TRIG_THRESH") + field(FLNK, "$(P)$(R):SlowThreshold_RBV") + alias("$(P)$(R):SlowThreshold") +} + +grecord(longin,"$(P)$(R):Threshold_RBV") { + field(DESC,"Slow threshold") + field(EGU, "LSB") + field(PINI,"YES") + field(DTYP, "asynInt32") + field(SCAN, "Passive") + field(INP,"@asyn($(PORT) $(CHAN))CAEN_TRIG_THRESH") + alias("$(P)$(R):SlowThreshold_RBV") +} + +grecord(longout,"$(P)$(R):TrapRise") { + field(DESC,"Slow threshold") + field(EGU, "ns") + field(DRVL, "0") + field(DRVH, "65535") + field(DTYP, "asynInt32") + field(OUT, "@asyn($(PORT) $(CHAN))CAEN_TRAP_RISE") + field(FLNK, "$(P)$(R):TrapRise_RBV") +} + +grecord(longin,"$(P)$(R):TrapRise_RBV") { + field(DESC,"Slow threshold") + field(EGU, "ns") + field(PINI,"YES") + field(DTYP, "asynInt32") + field(SCAN, "Passive") + field(INP,"@asyn($(PORT) $(CHAN))CAEN_TRAP_RISE") +} + +grecord(longout,"$(P)$(R):TrapFlatTop") { + field(DESC,"Slow threshold") + field(EGU, "ns") + field(DRVL, "0") + field(DRVH, "65535") + field(DTYP, "asynInt32") + field(OUT, "@asyn($(PORT) $(CHAN))CAEN_TRAP_FT") + field(FLNK, "$(P)$(R):TrapFlatTop_RBV") +} + +grecord(longin,"$(P)$(R):TrapFlatTop_RBV") { + field(DESC,"Slow threshold") + field(EGU, "ns") + field(PINI,"YES") + field(DTYP, "asynInt32") + field(SCAN, "Passive") + field(INP,"@asyn($(PORT) $(CHAN))CAEN_TRAP_FT") +} + +grecord(longout,"$(P)$(R):DecayTime") { + field(DESC,"Slow threshold") + field(EGU, "ns") + field(DRVL, "0") + field(DRVH, "65535") + field(DTYP, "asynInt32") + field(OUT, "@asyn($(PORT) $(CHAN))CAEN_DECAY_TIME") + field(FLNK, "$(P)$(R):DecayTime_RBV") +} + +grecord(longin,"$(P)$(R):DecayTime_RBV") { + field(DESC,"Slow threshold") + field(EGU, "ns") + field(PINI,"YES") + field(DTYP, "asynInt32") + field(SCAN, "Passive") + field(INP,"@asyn($(PORT) $(CHAN))CAEN_DECAY_TIME") +} + +grecord(longout,"$(P)$(R):FlatTopDelay") { + field(DESC,"Slow threshold") + field(EGU, "ns") + field(DRVL, "0") + field(DRVH, "65535") + field(DTYP, "asynInt32") + field(OUT, "@asyn($(PORT) $(CHAN))CAEN_FLAT_DELAY") + field(FLNK, "$(P)$(R):FlatTopDelay_RBV") +} + +grecord(longin,"$(P)$(R):FlatTopDelay_RBV") { + field(DESC,"Slow threshold") + field(EGU, "ns") + field(PINI,"YES") + field(DTYP, "asynInt32") + field(SCAN, "Passive") + field(INP,"@asyn($(PORT) $(CHAN))CAEN_FLAT_DELAY") +} + +grecord(longout,"$(P)$(R):TrigFiltSmoo") { + field(DESC,"Slow threshold") + field(EGU, "samples") + field(DRVL, "0") + field(DRVH, "65535") + field(DTYP, "asynInt32") + field(OUT, "@asyn($(PORT) $(CHAN))CAEN_TRIG_FILT_SMOO") + field(FLNK, "$(P)$(R):TrigFiltSmoo_RBV") +} + +grecord(longin,"$(P)$(R):TrigFiltSmoo_RBV") { + field(DESC,"Slow threshold") + field(EGU, "samples") + field(PINI,"YES") + field(DTYP, "asynInt32") + field(SCAN, "Passive") + field(INP,"@asyn($(PORT) $(CHAN))CAEN_TRIG_FILT_SMOO") +} + +grecord(longout,"$(P)$(R):InputRiseTime") { + field(DESC,"Slow threshold") + field(EGU, "ns") + field(DRVL, "0") + field(DRVH, "65535") + field(DTYP, "asynInt32") + field(OUT, "@asyn($(PORT) $(CHAN))CAEN_INPUT_RISE") + field(FLNK, "$(P)$(R):InputRiseTime_RBV") +} + +grecord(longin,"$(P)$(R):InputRiseTime_RBV") { + field(DESC,"Slow threshold") + field(EGU, "ns") + field(PINI,"YES") + field(DTYP, "asynInt32") + field(SCAN, "Passive") + field(INP,"@asyn($(PORT) $(CHAN))CAEN_INPUT_RISE") +} + +grecord(longout,"$(P)$(R):TrigHoldOff") { + field(DESC,"Slow threshold") + field(EGU, "ns") + field(DRVL, "0") + field(DRVH, "65535") + field(DTYP, "asynInt32") + field(OUT, "@asyn($(PORT) $(CHAN))CAEN_TRIG_HOFF") + field(FLNK, "$(P)$(R):TrigHoldOff_RBV") +} + +grecord(longin,"$(P)$(R):TrigHoldOff_RBV") { + field(DESC,"Slow threshold") + field(EGU, "ns") + field(PINI,"YES") + field(DTYP, "asynInt32") + field(SCAN, "Passive") + field(INP,"@asyn($(PORT) $(CHAN))CAEN_TRIG_HOFF") +} + +grecord(longout,"$(P)$(R):DCOffset") { + field(DESC,"Slow threshold") + field(EGU, "LSB") + field(DRVL, "0") + field(DRVH, "65535") + field(DTYP, "asynInt32") + field(OUT, "@asyn($(PORT) $(CHAN))CAEN_DC_OFFSET") + field(FLNK, "$(P)$(R):DCOffset_RBV") +} + +grecord(longin,"$(P)$(R):DCOffset_RBV") { + field(DESC,"Slow threshold") + field(EGU, "LSB") + field(PINI,"YES") + field(DTYP, "asynInt32") + field(SCAN, "Passive") + field(INP,"@asyn($(PORT) $(CHAN))CAEN_DC_OFFSET") +} + +grecord(longout,"$(P)$(R):PreTrigSize") { + field(DESC,"Slow threshold") + field(EGU, "samples") + field(DRVL, "0") + field(DRVH, "65535") + field(DTYP, "asynInt32") + field(OUT, "@asyn($(PORT) $(CHAN))CAEN_PRETRIG_SIZE") + field(FLNK, "$(P)$(R):PreTrigSize_RBV") +} + +grecord(longin,"$(P)$(R):PreTrigSize_RBV") { + field(DESC,"Slow threshold") + field(EGU, "samples") + field(PINI,"YES") + field(DTYP, "asynInt32") + field(SCAN, "Passive") + field(INP,"@asyn($(PORT) $(CHAN))CAEN_PRETRIG_SIZE") +} + +grecord(bo,"$(P)$(R):PulsePolarity") { + field(DESC,"Slow threshold") + field(ZNAM, "Positive") + field(ONAM, "Negative") + field(DTYP, "asynInt32") + field(OUT, "@asyn($(PORT) $(CHAN))CAEN_PULSE_POL") + field(FLNK, "$(P)$(R):PulsePolarity_RBV") +} + +grecord(bi,"$(P)$(R):PulsePolarity_RBV") { + field(DESC,"Slow threshold") + field(PINI,"YES") + field(ZNAM, "Positive") + field(ONAM, "Negative") + field(DTYP, "asynInt32") + field(SCAN, "Passive") + field(INP,"@asyn($(PORT) $(CHAN))CAEN_PULSE_POL") +} + +grecord(mbbo,"$(P)$(R):NBaseline") { + field(DESC,"Slow threshold") + field(ZRST, "0 samples") + field(ONST, "16 samples") + field(TWST, "64 samples") + field(THST, "256 samples") + field(FRST, "1024 samples") + field(FVST, "4096 samples") + field(SXST, "16384 samples") + field(ZRVL, "0") + field(ONVL, "1") + field(TWVL, "2") + field(THVL, "3") + field(FRVL, "4") + field(FVVL, "5") + field(SXVL, "6") + field(DTYP, "asynInt32") + field(OUT, "@asyn($(PORT) $(CHAN))CAEN_NSBL") + field(FLNK, "$(P)$(R):NBaseline_RBV") +} + +grecord(mbbi,"$(P)$(R):NBaseline_RBV") { + field(DESC,"Slow threshold") + field(PINI,"YES") + field(DTYP, "asynInt32") + field(SCAN, "Passive") + field(ZRST, "0 samples") + field(ONST, "16 samples") + field(TWST, "64 samples") + field(THST, "256 samples") + field(FRST, "1024 samples") + field(FVST, "4096 samples") + field(SXST, "16384 samples") + field(ZRVL, "0") + field(ONVL, "1") + field(TWVL, "2") + field(THVL, "3") + field(FRVL, "4") + field(FVVL, "5") + field(SXVL, "6") + field(INP,"@asyn($(PORT) $(CHAN))CAEN_NSBL") +} + +grecord(mbbo,"$(P)$(R):NSPeak") { + field(DESC,"Slow threshold") + field(ZRVL, "0") + field(ONVL, "1") + field(TWVL, "2") + field(THVL, "3") + field(ZRST, "1 sample") + field(ONST, "4 samples") + field(TWST, "16 samples") + field(THST, "64 samples") + field(DTYP, "asynInt32") + field(OUT, "@asyn($(PORT) $(CHAN))CAEN_NSPK") + field(FLNK, "$(P)$(R):NSPeak_RBV") +} + +grecord(mbbi,"$(P)$(R):NSPeak_RBV") { + field(DESC,"Slow threshold") + field(PINI,"YES") + field(ZRVL, "0") + field(ONVL, "1") + field(TWVL, "2") + field(THVL, "3") + field(ZRST, "1 sample") + field(ONST, "4 samples") + field(TWST, "16 samples") + field(THST, "64 samples") + field(DTYP, "asynInt32") + field(SCAN, "Passive") + field(INP,"@asyn($(PORT) $(CHAN))CAEN_NSPK") +} + +grecord(longout,"$(P)$(R):PeakHoldOff") { + field(DESC,"Slow threshold") + field(EGU, "ns") + field(DRVL, "0") + field(DRVH, "65535") + field(DTYP, "asynInt32") + field(OUT, "@asyn($(PORT) $(CHAN))CAEN_PKHO") + field(FLNK, "$(P)$(R):PeakHoldOff_RBV") +} + +grecord(longin,"$(P)$(R):PeakHoldOff_RBV") { + field(DESC,"Slow threshold") + field(EGU, "ns") + field(PINI,"YES") + field(DTYP, "asynInt32") + field(SCAN, "Passive") + field(INP,"@asyn($(PORT) $(CHAN))CAEN_PKHO") +} + +grecord(longout,"$(P)$(R):BLHoldOff") { + field(DESC,"Slow threshold") + field(EGU, "ns") + field(DRVL, "0") + field(DRVH, "65535") + field(DTYP, "asynInt32") + field(OUT, "@asyn($(PORT) $(CHAN))CAEN_BLHO") + field(FLNK, "$(P)$(R):BLHoldOff_RBV") +} + +grecord(longin,"$(P)$(R):BLHoldOff_RBV") { + field(DESC,"Slow threshold") + field(EGU, "ns") + field(PINI,"YES") + field(DTYP, "asynInt32") + field(SCAN, "Passive") + field(INP,"@asyn($(PORT) $(CHAN))CAEN_BLHO") +} + +grecord(ao,"$(P)$(R):EnergyNF") { + field(DESC,"Slow threshold") + field(DTYP, "asynFloat64") + field(OUT, "@asyn($(PORT) $(CHAN))CAEN_ENF") + field(FLNK, "$(P)$(R):EnergyNF_RBV") +} + +grecord(ai,"$(P)$(R):EnergyNF_RBV") { + field(DESC,"Slow threshold") + field(PINI,"YES") + field(DTYP, "asynFloat64") + field(SCAN, "Passive") + field(INP,"@asyn($(PORT) $(CHAN))CAEN_ENF") +} + +grecord(mbbo,"$(P)$(R):Decimation") { + field(DESC,"Slow threshold") + field(ZRVL, "0") + field(ONVL, "1") + field(TWVL, "2") + field(THVL, "3") + field(ZRST, "No decimation") + field(ONST, "2 samples (50 MSps)") + field(TWST, "4 samples (25 MSps)") + field(THST, "8 samples (12.5 MSps)") + field(DTYP, "asynInt32") + field(OUT, "@asyn($(PORT) $(CHAN))CAEN_DECIMATION") + field(FLNK, "$(P)$(R):Decimation_RBV") +} + +grecord(mbbi,"$(P)$(R):Decimation_RBV") { + field(DESC,"Slow threshold") + field(PINI,"YES") + field(ZRVL, "0") + field(ONVL, "1") + field(TWVL, "2") + field(THVL, "3") + field(ZRST, "No decimation") + field(ONST, "2 samples (50 MSps)") + field(TWST, "4 samples (25 MSps)") + field(THST, "8 samples (12.5 MSps)") + field(DTYP, "asynInt32") + field(SCAN, "Passive") + field(INP,"@asyn($(PORT) $(CHAN))CAEN_DECIMATION") +} + +grecord(mbbo,"$(P)$(R):DecGain") { + field(DESC,"Slow threshold") + field(ZRVL, "0") + field(ONVL, "1") + field(TWVL, "2") + field(THVL, "3") + field(ZRST, "1x Gain") + field(ONST, "2x Gain") + field(TWST, "4x Gain") + field(THST, "8x Gain") + field(DTYP, "asynInt32") + field(OUT, "@asyn($(PORT) $(CHAN))CAEN_DEC_GAIN") + field(FLNK, "$(P)$(R):DecGain_RBV") +} + +grecord(mbbi,"$(P)$(R):DecGain_RBV") { + field(DESC,"Slow threshold") + field(PINI,"YES") + field(ZRVL, "0") + field(ONVL, "1") + field(TWVL, "2") + field(THVL, "3") + field(ZRST, "1x Gain") + field(ONST, "2x Gain") + field(TWST, "4x Gain") + field(THST, "8x Gain") + field(DTYP, "asynInt32") + field(SCAN, "Passive") + field(INP,"@asyn($(PORT) $(CHAN))CAEN_DEC_GAIN") +} + +grecord(bo,"$(P)$(R):TrigWin") { + field(DESC,"Slow threshold") + field(ZNAM, "Disabled") + field(ONAM, "Enabled") + field(DTYP, "asynInt32") + field(OUT, "@asyn($(PORT) $(CHAN))CAEN_TRIG_WIN") + field(FLNK, "$(P)$(R):TrigWin_RBV") +} + +grecord(bi,"$(P)$(R):TrigWin_RBV") { + field(DESC,"Slow threshold") + field(ZNAM, "Disabled") + field(ONAM, "Enabled") + field(PINI,"YES") + field(DTYP, "asynInt32") + field(SCAN, "Passive") + field(INP,"@asyn($(PORT) $(CHAN))CAEN_TRIG_WIN") +} + +grecord(longout,"$(P)$(R):TWWDT") { + field(DESC,"Slow threshold") + field(EGU, "ns") + field(DRVL, "0") + field(DRVH, "65535") + field(DTYP, "asynInt32") + field(OUT, "@asyn($(PORT) $(CHAN))CAEN_TW_WDT") + field(FLNK, "$(P)$(R):TWWDT_RBV") +} + +grecord(longin,"$(P)$(R):TWWDT_RBV") { + field(DESC,"Slow threshold") + field(EGU, "ns") + field(PINI,"YES") + field(DTYP, "asynInt32") + field(SCAN, "Passive") + field(INP,"@asyn($(PORT) $(CHAN))CAEN_TW_WDT") +} + +# This is the MCA record itself +grecord(mca,"$(P)$(R)") { + field(DTYP,"$(DTYP)") + field(FLNK,"0") + field(PINI,"YES") + field(NMAX,"$(NCHAN)") + field(PREC,"2") + field(NUSE,"$(NCHAN)") + field(INP, "@asyn($(PORT) $(CHAN))") +# Alarm setpoints, severity and hysteresis for deadtime + field(HIHI,"70.") + field(HHSV,"MAJOR") + field(HIGH,"40.") + field(HSV,"MINOR") + field(LOLO,"0.") + field(LLSV,"NO_ALARM") + field(LOW,"0.") + field(LSV,"NO_ALARM") + field(HYST,"2.") +} + +record(longin,"$(P)$(R):Counts") { + field(DESC,"Slow counts") + field(EGU, "counts") + field(INP,"$(P)$(R).ACT CP") + alias("$(P)$(R):SlowCounts") +} diff --git a/mcaApp/Makefile b/mcaApp/Makefile index 3c597b06..98ba273d 100644 --- a/mcaApp/Makefile +++ b/mcaApp/Makefile @@ -23,6 +23,10 @@ RontecSrc_DEPEND_DIRS = mcaSrc DIRS += AmptekSrc AmptekSrc_DEPEND_DIRS = mcaSrc +# Support for CAEN Digitizers +DIRS += CaenSrc +CaenSrc_DEPEND_DIRS = mcaSrc + DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *db*)) DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *Db*)) DIRS := $(DIRS) $(filter-out $(DIRS), $(wildcard *op*)) From 0761264ed029eeb5a441d81c8a1206d7f5acf99d Mon Sep 17 00:00:00 2001 From: Pedro Nariyoshi Date: Wed, 18 Jun 2025 14:07:06 -0400 Subject: [PATCH 2/2] Cleanup CAEN driver for publication --- mcaApp/CaenSrc/drvCaen.cpp | 35 ----------------------------------- mcaApp/CaenSrc/drvCaen.h | 19 ------------------- 2 files changed, 54 deletions(-) diff --git a/mcaApp/CaenSrc/drvCaen.cpp b/mcaApp/CaenSrc/drvCaen.cpp index 9210786a..427546d2 100644 --- a/mcaApp/CaenSrc/drvCaen.cpp +++ b/mcaApp/CaenSrc/drvCaen.cpp @@ -6,7 +6,6 @@ // This module provides the driver support for the MCA asyn device support layer // for C.A.E.N. MCAs that support the CAENDigitizer library. // -// #include #include @@ -257,38 +256,6 @@ asynStatus drvCaen::connect(asynUser *pasynUser) return asynSuccess; } -//asynStatus drvCaen::disconnect(asynUser *pasynUser) -//{ -// static const char *functionName = "disconnectDevice"; -// asynStatus ret; -// -// // Disconnect from the digitizer -// if(isConnected_ == true){ -// ret = disconnectDevice(); -// -// int addr; -// getAddress(pasynUser, &addr); -// -// if (ret == asynSuccess){ -// isConnected_ = false; -// asynPrint(pasynUser, ASYN_TRACEIO_DRIVER, -// "%s::%s Digitizer (%s) disconnected\n", -// driverName, functionName, portName); -// } -// else{ -// epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, -// "%s::%s Digitizer (%s) not disconnected\nError code = %d\n", -// driverName, functionName, portName, ret); -// return asynError; -// } -// } -// -// pasynManager->exceptionDisconnect(pasynUser); -// setParamsAlarm(COMM_ALARM, INVALID_ALARM); -// -// return asynSuccess; -//} - void drvCaen::setParamsAlarm(int alarmStatus, int alarmSeverity) { for (int addr = 0; addr < MAX_ADCS; ++addr) { @@ -989,8 +956,6 @@ asynStatus drvCaen::writeFloat64(asynUser *pasynUser, epicsFloat64 value) } epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,"Setting energy normalization factor, ret = %d\n",ret); } -// else (command == caenPollPeriod_){ - /* Set the parameter in the parameter library. */ status = setDoubleParam(addr, command, value); diff --git a/mcaApp/CaenSrc/drvCaen.h b/mcaApp/CaenSrc/drvCaen.h index 3abcf2f8..7e7790ce 100644 --- a/mcaApp/CaenSrc/drvCaen.h +++ b/mcaApp/CaenSrc/drvCaen.h @@ -205,30 +205,11 @@ class drvCaen : public asynPortDriver // Driver variables int handle_; int BitMask_; - // asynStatus disconnectDevice(); asynStatus connectDevice(asynUser *pasynUser); bool directConnect(char* address); void checkFailedComm(const char *functionName); - // size_t numChannels_; - // asynStatus findModule(); - // asynStatus sendCommand(TRANSMIT_PACKET_TYPE command); - // asynStatus sendCommandString(string commandString); - // asynStatus sendConfiguration(); - // asynStatus sendSCAs(); - // asynStatus sendConfigurationFile(string fileName); - // asynStatus saveConfigurationFile(string fileName); - // asynStatus readConfigurationFromHardware(); - // asynStatus parseConfiguration(); - // asynStatus parseConfigDouble(const char *str, int param); - // asynStatus parseConfigInt(const char *str, int param); asynStatus allocateBuffers(); - // asynStatus parseConfigEnum(const char *str, const char *enumStrs[], int numEnums, int param); - // dp5DppTypes dppType_; bool acquiring_; - // bool haveConfigFromHW_; - // DppInterface_t interfaceType_; - // char *addressInfo_; - // bool directMode_; int failedSends_; bool isConnected_; void setParamsAlarm(int alarmStatus, int alarmSeverity);