From 09a9276c9421f3f79b9b04f3ebe6d13ef9b205ed Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Tue, 10 Mar 2026 15:02:12 +0000 Subject: [PATCH 1/4] Reconnect on error and save total energy histogram --- CAENMCAApp/Db/CAENMCADev.db | 9 ++ CAENMCAApp/src/CAENMCADriver.cpp | 143 +++++++++++++++++++------------ CAENMCAApp/src/CAENMCADriver.h | 4 + 3 files changed, 101 insertions(+), 55 deletions(-) diff --git a/CAENMCAApp/Db/CAENMCADev.db b/CAENMCAApp/Db/CAENMCADev.db index eba2632..b04eff5 100644 --- a/CAENMCAApp/Db/CAENMCADev.db +++ b/CAENMCAApp/Db/CAENMCADev.db @@ -22,6 +22,15 @@ record(waveform, "$(P)$(Q)DEVICE:ADDR") info(archive, "VAL") } +record(longin, "$(P)$(Q)NUMRECONNECT") +{ + field(DTYP, "asynInt32") + field(INP, "@asyn($(PORT),0,0)NUMRECONNECT") + field(SCAN, "I/O Intr") + field(EGU, "") + info(archive, "VAL") +} + record(stringin, "$(P)$(Q)FILEDIRPREFIX") { field(DESC, "File Dir Prefix") diff --git a/CAENMCAApp/src/CAENMCADriver.cpp b/CAENMCAApp/src/CAENMCADriver.cpp index f885540..1cecf31 100644 --- a/CAENMCAApp/src/CAENMCADriver.cpp +++ b/CAENMCAApp/src/CAENMCADriver.cpp @@ -390,12 +390,14 @@ CAENMCADriver::CAENMCADriver(const char *portName, const char* deviceAddr, const 0, /* Default priority */ 0), /* Default stack size*/ m_famcode(CAEN_MCA_FAMILY_CODE_UNKNOWN),m_device_h(NULL),m_old_list_filename(2),m_file_fd(2, std::tuple{NULL,NULL}), - m_event_file_last_pos(2, 0),m_frame_time(2, 0),m_max_event_time(2, 0),m_pRaw(NULL), m_file_dir("ibex") + m_event_file_last_pos(2, 0),m_frame_time(2, 0),m_max_event_time(2, 0),m_pRaw(NULL), m_file_dir("ibex"), + m_device_addr(deviceAddr) { const char *functionName = "CAENMCADriver"; createParam(P_deviceNameString, asynParamOctet, &P_deviceName); createParam(P_deviceAddrString, asynParamOctet, &P_deviceAddr); + createParam(P_numReconnectString, asynParamInt32, &P_numReconnect); createParam(P_availableConfigurationsString, asynParamOctet, &P_availableConfigurations); createParam(P_configurationString, asynParamOctet, &P_configuration); createParam(P_numEnergySpecString, asynParamInt32, &P_numEnergySpec); @@ -565,13 +567,10 @@ CAENMCADriver::CAENMCADriver(const char *portName, const char* deviceAddr, const setStringParam(P_deviceName, deviceName); setStringParam(P_deviceAddr, deviceAddr); - m_device_h = CAENMCA::OpenDevice(deviceAddr, NULL); + setIntegerParam(P_numReconnect, 0); + connectDevice(); CAENMCA::GetData(m_device_h, CAEN_MCA_DATA_BOARD_INFO, DATAMASK_BRDINFO_FAMCODE, &m_famcode); getBoardInfo(); - - CAENMCA::getHandlesFromCollection(m_device_h, CAEN_MCA_HANDLE_CHANNEL, m_chan_h); - CAENMCA::getHandlesFromCollection(m_device_h, CAEN_MCA_HANDLE_HVCHANNEL, m_hv_chan_h); - getHVInfo(0); getHVInfo(1); @@ -604,6 +603,23 @@ CAENMCADriver::CAENMCADriver(const char *portName, const char* deviceAddr, const } } + +void CAENMCADriver::connectDevice() +{ + int nconnect = 0; + getIntegerParam(P_numReconnect, &nconnect); + setIntegerParam(P_numReconnect, ++nconnect); + if (m_device_h != NULL) { + CAENMCA::closeDevice(m_device_h); + m_device_h = NULL; + } + std::cerr << "Opening connection to " << m_device_addr << std::endl; + m_device_h = CAENMCA::OpenDevice(m_device_addr, NULL); + CAENMCA::getHandlesFromCollection(m_device_h, CAEN_MCA_HANDLE_CHANNEL, m_chan_h); + CAENMCA::getHandlesFromCollection(m_device_h, CAEN_MCA_HANDLE_HVCHANNEL, m_hv_chan_h); + std::cerr << "Successfully connected to " << m_device_addr << std::endl; +} + void CAENMCADriver::setRunNumberFromIRunNumber() { char runNumber[16]; @@ -934,7 +950,7 @@ std::string CAENMCADriver::createTemplateNexusFile(const std::string& filePrefix event2_energy_group.createDataSet("event_time_max", tmax); event2_energy_group.createDataSet("num_events", nevents); event2_energy_group.createDataSet("desc", desc); - + std::string event_energy2d_group_name = "detector_" + std::to_string(k) + "_energy2D"; hf::Group event_energy2d_group = createNeXusGroup(raw_data_1, event_energy2d_group_name, "NXdata"); int eventSpec_2d_nTBins = 0, eventSpec_2d_engBinGroup = 1; @@ -947,6 +963,21 @@ std::string CAENMCADriver::createTemplateNexusFile(const std::string& filePrefix if (driver->m_event_spec_2d[i].size() > 0) { counts2d.write_raw(driver->m_event_spec_2d[i].data()); } + + std::string energyHist_group_name = "detector_" + std::to_string(k) + "_energyHist"; + hf::Group energyHist_group = createNeXusGroup(raw_data_1, energyHist_group_name, "NXdata"); + hf::DataSet hist_counts = energyHist_group.createDataSet("counts", driver->m_energy_spec[i]); + hist_counts.createAttribute("signal", 1); + std::vector energyHist_x(driver->m_energy_spec[i].size()); + for(int j=0; jgetIntegerParam(i, driver->P_energySpecCounts, &nevents); + energyHist.createAttribute("scaleA", scaleA); + energyHist.createAttribute("scaleB", scaleB); + energyHist_group.createDataSet("num_events", nevents); + ++k; } } @@ -1636,68 +1667,70 @@ void CAENMCADriver::energySpectrumSetProperty(CAEN_MCA_HANDLE channel, int32_t s void CAENMCADriver::pollerTask() { - bool new_data; - epicsThreadSleep(0.2); // to allow class constructror to complete + bool new_data, reconnect = false; + epicsThreadSleep(0.2); // to allow class constructror to complete lock(); std::string deviceName; getStringParam(P_deviceName, deviceName); unlock(); - while(true) - { - lock(); + while(true) + { + lock(); try { - - //std::cerr << "hv0 on " << isHVOn(m_hv_chan_h[0]) << std::endl; - //std::cerr << "hv1 on " << isHVOn(m_hv_chan_h[1]) << std::endl; - - //std::cerr << isAcqRunning() << " " << isAcqRunning(m_chan_h[0]) << " " << isAcqRunning(m_chan_h[1]) << std::endl; - for(int i=0;i<2; ++i) - { - getEnergySpectrum(i, 0, m_energy_spec[i]); - doCallbacksInt32Array(m_energy_spec[i].data(), m_energy_spec[i].size(), P_energySpec, i); - getHVInfo(i); - getChannelInfo(i); - getLists(i); - if (!isAcqRunning(m_chan_h[i])) { - setDoubleParam(i, P_eventSpecRate, 0.0); - setDoubleParam(i, P_eventsSpecTriggerRate, 0.0); + if (reconnect) { + epicsThreadSleep(5.0); // sleep to avoid too many reconnections + connectDevice(); + setParamStatus(0, P_eventsSpecNTriggers, asynSuccess); // to clear an alarm in the DB + reconnect = false; } - new_data = processListFile(i); - setIntegerParam(i, P_loadDataStatus, 2); - callParamCallbacks(i); - updateAD(i, new_data); - doCallbacksFloat64Array(m_event_spec_x[i].data(), m_event_spec_x[i].size(), P_eventsSpecX, i); - doCallbacksFloat64Array(m_event_spec_y[i].data(), m_event_spec_y[i].size(), P_eventsSpecY, i); - doCallbacksInt32Array(m_energy_spec_event[i].data(), m_energy_spec_event[i].size(), P_energySpecEvent, i); - doCallbacksInt32Array(m_energy_spec2_event[i].data(), m_energy_spec2_event[i].size(), P_energySpec2Event, i); - setIntegerParam(i, P_loadDataStatus, 0); - callParamCallbacks(i); - } - bool acqRunning = isAcqRunning(); - setIntegerParam(P_acqRunning, (acqRunning ? 1 : 0)); - std::vector configs_v; - listConfigurations(configs_v); - std::string configs; - - for(int i=0; i configs_v; + listConfigurations(configs_v); + std::string configs; + + for(int i=0; i int computeArray(int addr, const std::vector& data, int maxSizeX, int maxSizeY); CAEN_MCA_HANDLE m_device_h; + std::string m_device_addr; epicsTime m_start_time[2]; epicsTime m_stop_time[2]; std::vector m_chan_h; @@ -123,6 +125,7 @@ class epicsShareClass CAENMCADriver : public ADDriver int P_deviceName; // string int P_deviceAddr; // string + int P_numReconnect; // int int P_availableConfigurations; // string int P_configuration; // string int P_numEnergySpec; // int @@ -257,6 +260,7 @@ class epicsShareClass CAENMCADriver : public ADDriver #define P_deviceNameString "DEVICENAME" #define P_deviceAddrString "DEVICEADDR" +#define P_numReconnectString "NUMRECONNECT" #define P_availableConfigurationsString "CONFIG_AVAIL" #define P_configurationString "CONFIG" #define P_numEnergySpecString "NUMENERGYSPEC" From 1457eb3eea1662a8df460e366c41d8148b3c74f7 Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Fri, 27 Mar 2026 23:44:39 +0000 Subject: [PATCH 2/4] print hexagon name on timing reg error --- CAENMCAApp/Db/CAENMCADev.db | 1 + CAENMCAApp/src/CAENMCADriver.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CAENMCAApp/Db/CAENMCADev.db b/CAENMCAApp/Db/CAENMCADev.db index b04eff5..ac4ef4e 100644 --- a/CAENMCAApp/Db/CAENMCADev.db +++ b/CAENMCAApp/Db/CAENMCADev.db @@ -164,5 +164,6 @@ record(bi, "$(P)$(Q)TIMEREGS") field(INP, "@asyn($(PORT),0,0)TIMINGREGISTERS") field(ZNAM, "Error") field(ONAM, "OK") + field(ZSV, "MAJOR") field(SCAN, "I/O Intr") } diff --git a/CAENMCAApp/src/CAENMCADriver.cpp b/CAENMCAApp/src/CAENMCADriver.cpp index 1cecf31..3c69484 100644 --- a/CAENMCAApp/src/CAENMCADriver.cpp +++ b/CAENMCAApp/src/CAENMCADriver.cpp @@ -584,7 +584,7 @@ CAENMCADriver::CAENMCADriver(const char *portName, const char* deviceAddr, const // setTimingRegisters(); if (!checkTimingRegisters()) { - std::cerr << "WARNING: Timing registers not set" << std::endl; + std::cerr << "WARNING: Timing registers not set on " << deviceName << std::endl; } std::string ethPrefix = "eth://", deviceAddr_s(deviceAddr); @@ -1270,8 +1270,10 @@ void CAENMCADriver::stopAcquisition(int addr, int value) void CAENMCADriver::startAcquisition(int addr, int value) { // setTimingRegisters(); + std::string deviceName; + getStringParam(P_deviceName, deviceName); if (!checkTimingRegisters()) { - std::cerr << "WARNING: Timing registers not set" << std::endl; + std::cerr << "WARNING: Timing registers not set on " << deviceName << std::endl; } if (value < 2) // is it a bo record sending 0 or 1, if so single channel and use asyn addr for channel { From 892757c2a147812c5251a506bd4fd158d18fe3e1 Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Sat, 28 Mar 2026 00:01:58 +0000 Subject: [PATCH 3/4] print hexagon name on timing reg error --- CAENMCAApp/src/CAENMCADriver.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CAENMCAApp/src/CAENMCADriver.cpp b/CAENMCAApp/src/CAENMCADriver.cpp index 3c69484..106bb11 100644 --- a/CAENMCAApp/src/CAENMCADriver.cpp +++ b/CAENMCAApp/src/CAENMCADriver.cpp @@ -1257,6 +1257,11 @@ void CAENMCADriver::getHVInfo(uint32_t hv_chan_id) void CAENMCADriver::stopAcquisition(int addr, int value) { + std::string deviceName; + getStringParam(P_deviceName, deviceName); + if (!checkTimingRegisters()) { + std::cerr << "WARNING: Timing registers not set on " << deviceName << std::endl; + } if (value < 2) // is it a bo record sending 0 or 1, if so single channel and use asyn addr for channel { controlAcquisition(1 << addr, false); From 4613f4fb842d8daa646da28658c808b4b5464911 Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Thu, 2 Apr 2026 23:51:40 +0100 Subject: [PATCH 4/4] Check timing registers evry loop --- CAENMCAApp/src/CAENMCADriver.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/CAENMCAApp/src/CAENMCADriver.cpp b/CAENMCAApp/src/CAENMCADriver.cpp index 106bb11..28f4429 100644 --- a/CAENMCAApp/src/CAENMCADriver.cpp +++ b/CAENMCAApp/src/CAENMCADriver.cpp @@ -1674,7 +1674,7 @@ void CAENMCADriver::energySpectrumSetProperty(CAEN_MCA_HANDLE channel, int32_t s void CAENMCADriver::pollerTask() { - bool new_data, reconnect = false; + bool new_data, reconnect = false, warn_timing_reg = true; epicsThreadSleep(0.2); // to allow class constructror to complete lock(); std::string deviceName; @@ -1690,6 +1690,7 @@ void CAENMCADriver::pollerTask() connectDevice(); setParamStatus(0, P_eventsSpecNTriggers, asynSuccess); // to clear an alarm in the DB reconnect = false; + warn_timing_reg = true; } for(int i=0;i<2; ++i) { @@ -1713,6 +1714,14 @@ void CAENMCADriver::pollerTask() setIntegerParam(i, P_loadDataStatus, 0); callParamCallbacks(i); } + if (!checkTimingRegisters()) { + if (warn_timing_reg) { + std::cerr << "WARNING: Timing registers not set on " << deviceName << std::endl; + warn_timing_reg = false; + } + } else { + warn_timing_reg = true; + } bool acqRunning = isAcqRunning(); setIntegerParam(P_acqRunning, (acqRunning ? 1 : 0)); std::vector configs_v; @@ -1727,7 +1736,7 @@ void CAENMCADriver::pollerTask() configs += ","; } } - setStringParam(P_availableConfigurations, configs.c_str()); + setStringParam(P_availableConfigurations, configs.c_str()); } catch(const std::exception& ex) { std::cerr << "exception in pollerTask: " << deviceName << ": " << ex.what() << std::endl;