Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CAENMCAApp/Db/CAENMCADev.db
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down Expand Up @@ -155,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")
}
163 changes: 106 additions & 57 deletions CAENMCAApp/src/CAENMCADriver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<FILE*, FILE*>{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);
Expand Down Expand Up @@ -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);

Expand All @@ -585,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);
Expand All @@ -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];
Expand Down Expand Up @@ -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;
Expand All @@ -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<double> energyHist_x(driver->m_energy_spec[i].size());
for(int j=0; j<energyHist_x.size(); ++j) {
energyHist_x[j] = scaleA * j + scaleB;
}
hf::DataSet energyHist = energyHist_group.createDataSet("energy", energyHist_x);
driver->getIntegerParam(i, driver->P_energySpecCounts, &nevents);
energyHist.createAttribute("scaleA", scaleA);
energyHist.createAttribute("scaleB", scaleB);
energyHist_group.createDataSet("num_events", nevents);

++k;
}
}
Expand Down Expand Up @@ -1226,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);
Expand All @@ -1239,8 +1275,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
{
Expand Down Expand Up @@ -1636,68 +1674,79 @@ 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, warn_timing_reg = true;
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;
warn_timing_reg = true;
}
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<std::string> configs_v;
listConfigurations(configs_v);
std::string configs;

for(int i=0; i<configs_v.size(); ++i)
{
configs += configs_v[i];
if (i != configs_v.size() - 1)
for(int i=0;i<2; ++i)
{
configs += ",";
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);
}
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);
}
}
setStringParam(P_availableConfigurations, configs.c_str());
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<std::string> configs_v;
listConfigurations(configs_v);
std::string configs;

for(int i=0; i<configs_v.size(); ++i)
{
configs += configs_v[i];
if (i != configs_v.size() - 1)
{
configs += ",";
}
}
setStringParam(P_availableConfigurations, configs.c_str());
}
catch(const std::exception& ex) {
std::cerr << "exception in pollerTask: " << deviceName << ": " << ex.what() << std::endl;
setParamStatus(0, P_eventsSpecNTriggers, asynError); // to flag an alarm in the DB
reconnect = true;
}
callParamCallbacks(0);
unlock();
epicsThreadSleep(1.0);
}
callParamCallbacks(0);
unlock();
epicsThreadSleep(1.0);
}
}

asynStatus CAENMCADriver::readOctet(asynUser *pasynUser, char *value, size_t maxChars, size_t *nActual, int *eomReason)
Expand Down
4 changes: 4 additions & 0 deletions CAENMCAApp/src/CAENMCADriver.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class epicsShareClass CAENMCADriver : public ADDriver
virtual void report(FILE* fp, int details);

private:
void connectDevice();
void updateAD(int addr, bool new_events);
void clearEnergySpectrum(int channel_id);
NDArray* m_pRaw;
Expand All @@ -39,6 +40,7 @@ class epicsShareClass CAENMCADriver : public ADDriver
template <typename epicsTypeOut, typename epicsTypeIn>
int computeArray(int addr, const std::vector<epicsTypeIn>& 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<CAEN_MCA_HANDLE> m_chan_h;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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"
Expand Down