diff --git a/config/config_scaler.xml b/config/config_scaler.xml new file mode 100644 index 0000000..b02568b --- /dev/null +++ b/config/config_scaler.xml @@ -0,0 +1,5 @@ + + + 4294967295 + 26bit + diff --git a/include/VMEReader.h b/include/VMEReader.h index b70e412..9bda654 100644 --- a/include/VMEReader.h +++ b/include/VMEReader.h @@ -10,6 +10,7 @@ #include "VME_CFDV812.h" #include "VME_CAENETControllerV288.h" #include "VME_TDCV1x90.h" +#include "VME_ScalerV8x0.h" #include "NIM_HVModuleN470.h" @@ -58,6 +59,23 @@ class VMEReader : public Client inline size_t GetNumTDC() const { return fTDCCollection.size(); } inline VME::TDCCollection GetTDCCollection() { return fTDCCollection; } + /** + * \brief Add a scaler to handle + * \param[in] address 32-bit address of the scaler module on the VME bus + * Create a new scaler handler for the VME bus + */ + void AddScaler(uint32_t address); + /** + * \brief Get a scaler on the VME bus + * Return a pointer to the scaler object, given its physical address on the VME bus + */ + inline VME::ScalerV8x0* GetScaler(uint32_t address) { + if (fScalerCollection.count(address)==0) return 0; + return fScalerCollection[address]; + } + inline size_t GetNumScaler() const { return fScalerCollection.size(); } + inline VME::ScalerCollection GetScalerCollection() { return fScalerCollection; } + void AddIOModule(uint32_t address); inline VME::IOModuleV262* GetIOModule() { return fSG; } @@ -166,8 +184,10 @@ class VMEReader : public Client VME::CFDCollection fCFDCollection; /// Pointer to the VME input/output module object VME::IOModuleV262* fSG; - /// Pointer to the VME general purpose FPGA unit object + /// A set of pointers to VME general purpose FPGA unit objects indexed by their physical VME address VME::FPGAUnitCollection fFPGACollection; + /// A set of pointers to scaler objects indexed by their physical VME address + VME::ScalerCollection fScalerCollection; /// Pointer to the VME CAENET controller VME::CAENETControllerV288* fCAENET; /// Pointer to the NIM high voltage module (passing through the CAENET controller) diff --git a/include/VME_ScalerV8x0.h b/include/VME_ScalerV8x0.h new file mode 100644 index 0000000..e9c9658 --- /dev/null +++ b/include/VME_ScalerV8x0.h @@ -0,0 +1,195 @@ +#ifndef VME_ScalerV8x0_h +#define VME_ScalerV8x0_h + +#include +#include +#include + +#include "VME_GenericBoard.h" + +#define TDC_ACQ_STOP 20001 + +namespace VME +{ + /** + * \date 17 Sep 2015 + * \author Laurent Forthomme + */ + enum ScalerV8x0DataFormat { DF32bit=0x0, DF26bit=0x1 }; + enum ScalerV8x0TriggerSource { TSExternalTrigger=0x0, TSTimerTrigger=0x1, TSVMETrigger=0x2 }; + + /** + * \brief Parser for a scaler event/header + * \date 17 Sep 2015 + * \author Laurent Forthomme + */ + class ScalerEvent + { + public: + inline ScalerEvent(unsigned int word) : fWord(word) {;} + inline ~ScalerEvent() {;} + + inline unsigned int GetWord() const { return fWord; } + + inline unsigned short GetGEO() const { return ((fWord>>27)&0x1f); } + inline bool IsHeader(unsigned short geo=0) const { + bool header_bit = (fWord>>26)&0x1; + if (geo>0) return (header_bit and GetGEO()==geo); + return header_bit; + } + + inline unsigned short GetTriggerNumber(unsigned short geo=0) const { + if (!IsHeader(geo)) throw Exception(__PRETTY_FUNCTION__, "Trying to extract the trigger number from a non-header ScalerEvent word", JustWarning); + return (fWord&0xffff); + } + inline ScalerV8x0TriggerSource GetTriggerSource(unsigned short geo=0) const { + if (!IsHeader(geo)) throw Exception(__PRETTY_FUNCTION__, "Trying to extract the trigger source from a non-header ScalerEvent word", JustWarning); + return static_cast((fWord>>16)&0x3); + } + inline unsigned short GetNumChannels(unsigned short geo=0) const { + if (!IsHeader(geo)) throw Exception(__PRETTY_FUNCTION__, "Trying to extract the number of enabled channels from a non-header ScalerEvent word", JustWarning); + return ((fWord>>18)&0x3f); + } + + inline unsigned short GetChannelId() const { return ((fWord>>27)&0x1f); } + inline unsigned int GetChannelCounter(const ScalerV8x0DataFormat& df) const { + switch (df) { + case DF32bit: return fWord; + case DF26bit: return (fWord&0x3ffffff); + } + } + + private: + unsigned int fWord; + }; + + /// A collection of ScalerEvent objects + typedef std::vector ScalerEventCollection; + + /** + * \brief List of registers to handle a CAEN V8x0 scaler module + * \date 17 Sep 2015 + * \author Laurent Forthomme + */ + enum ScalerV8x0Register { + kV8x0OutputBuffer = 0x0000, + kV8x0ChannelValue = 0x1000, + kV8x0ChannelEnable = 0x1100, + kV8x0Control = 0x1108, + kV8x0Status = 0x110e, + kV8x0GEO = 0x1110, + kV8x0TriggerCounter = 0x1128, + kV8x0FWVersion = 0x1132, + kV8x0OUI = 0x402a, + kV8x0ModelVersion = 0x4032, + kV8x0HWRevision = 0x404e, + kV8x0SerialMSB = 0x4f02, + kV8x0SerialLSB = 0x4f06 + }; + + /** + * \date 17 Sep 2015 + * \author Laurent Forthomme + */ + class ScalerV8x0Control + { + public: + inline ScalerV8x0Control(unsigned short word): fWord(word) {;} + inline ~ScalerV8x0Control() {;} + + inline unsigned short GetWord() const { return fWord; } + + enum AcquisitionMode { TriggerDisabled=0x0, TriggerRandom=0x1, PeriodicalTrigger=0x2 }; + inline void SetAcquisitionMode(const AcquisitionMode& mode) { SetBit(0, mode&0x1); SetBit(1, (mode>>1)&0x1); } + inline AcquisitionMode GetAcquisitionMode() const { + unsigned short word1 = GetBit(0), word2 = GetBit(1); + return static_cast(word1+(word2<<1)); + } + + inline void SetDataFormat(const ScalerV8x0DataFormat& fmt) { SetBit(2, fmt); } + inline ScalerV8x0DataFormat GetDataFormat() const { return static_cast(GetBit(2)); } + + inline void SetBusError(bool enable) { SetBit(4, enable); } + inline bool GetBusError() const { return GetBit(4); } + + inline void SetHeader(bool enable) { SetBit(5, enable); } + inline bool GetHeader() const { return GetBit(5); } + + inline void SetClearMEB(bool enable) { SetBit(6, enable); } + inline bool GetClearMEB() const { return GetBit(6); } + + inline void SetAutoReset(bool enable) { SetBit(7, enable); } + inline bool GetAutoReset() const { return GetBit(7); } + + private: + inline bool GetBit(unsigned short id) const { return static_cast((fWord>>id)&0x1); } + inline void SetBit(unsigned short id, unsigned short value=0x1) { + if (value==GetBit(id)) return; + unsigned short sign = (value==0x0) ? -1 : 1; fWord += sign*(0x1< + */ + class ScalerV8x0Status + { + public: + inline ScalerV8x0Status(unsigned short word): fWord(word) {;} + inline ~ScalerV8x0Status() {;} + + inline bool DataReady() const { return fWord&0x1; } + inline bool AlmostFull() const { return (fWord>>1)&0x1; } + inline bool Full() const { return (fWord>>2)&0x1; } + inline bool GlobalDataReady() const { return (fWord>>3)&0x1; } + inline bool GlobalBusy() const { return (fWord>>4)&0x1; } + inline bool TermOn() const { return (fWord>>5)&0x1; } + inline bool TermOff() const { return (fWord>>6)&0x1; } + inline bool BusError() const { return (fWord>>7)&0x1; } + private: + unsigned short fWord; + }; + + /** + * \brief Handler object for a CAEN V8x0 scaler module + * \date 17 Sep 2015 + * \author Laurent Forthomme + */ + class ScalerV8x0 : public GenericBoard + { + public: + ScalerV8x0(int32_t bhandle, uint32_t baseaddr); + ~ScalerV8x0(); + + unsigned int GetSerialNumber() const; + unsigned short GetModuleVersion() const; + unsigned short GetModuleType() const; + unsigned short GetManufacturerId() const; + //unsigned short GetIdentifier() const; + unsigned short GetGEO() const; + + void SetPOI(unsigned int poi) const; + unsigned int GetPOI() const; + + unsigned int GetTriggerCounter() const; + + unsigned int GetChannelValue(unsigned short channel_id) const; + ScalerEventCollection FetchEvents(); + + ScalerV8x0Status GetStatus() const; + ScalerV8x0Control GetControl() const; + void SetControl(const ScalerV8x0Control& control) const; + + void abort(); + + private: + unsigned int* fBuffer; + bool gEnd; + }; + + typedef std::map ScalerCollection; +} + +#endif diff --git a/src/VMEReader.cpp b/src/VMEReader.cpp index cbd3f16..26bf833 100644 --- a/src/VMEReader.cpp +++ b/src/VMEReader.cpp @@ -188,6 +188,27 @@ VMEReader::ReadXML(const char* filename) } catch (Exception& e) { throw e; } } } + for (tinyxml2::XMLElement* asca=doc.FirstChildElement("scaler"); asca!=NULL; asca=asca->NextSiblingElement("scaler")) { + if (const char* address=asca->Attribute("address")) { + unsigned long addr = static_cast(strtol(address, NULL, 0)); + if (!addr) throw Exception(__PRETTY_FUNCTION__, "Failed to parse scaler's base address", Fatal); + try { + try { AddScaler(addr); } catch (Exception& e) { if (fOnSocket) Client::Send(e); } + VME::ScalerV8x0* sca = GetScaler(addr); + VME::ScalerV8x0Control control = sca->GetControl(); + if (const char* hdr=asca->Attribute("header")) { + if (!strcmp(hdr, "true") or !strcmp(hdr, "True") or !strcmp(hdr, "1")) control.SetHeader(true); + if (!strcmp(hdr, "false") or !strcmp(hdr, "False") or !strcmp(hdr, "0")) control.SetHeader(false); + } + if (tinyxml2::XMLElement* poi=asca->FirstChildElement("poi")) { sca->SetPOI(atoi(poi->GetText())); } + if (tinyxml2::XMLElement* df=asca->FirstChildElement("data_format")) { + if (!strcmp(df->GetText(), "26bit")) control.SetDataFormat(VME::DF26bit); + if (!strcmp(df->GetText(), "32bit")) control.SetDataFormat(VME::DF32bit); + } + sca->SetControl(control); + } catch (Exception& e) { throw e; } + } + } std::cout << "Global acquisition mode: " << fGlobalAcqMode << std::endl; unsigned int run = GetRunNumber(); std::ifstream source(filename, std::ios::binary); @@ -232,6 +253,24 @@ VMEReader::AddTDC(uint32_t address) throw Exception(__PRETTY_FUNCTION__, os.str(), Info, TDC_ACQ_START); } +void +VMEReader::AddScaler(uint32_t address) +{ + if (!fBridge) throw Exception(__PRETTY_FUNCTION__, "No bridge detected! Aborting...", Fatal); + try { + fScalerCollection.insert(std::pair( + address, + new VME::ScalerV8x0(fBridge->GetHandle(), address) + )); + } catch (Exception& e) { + e.Dump(); + if (fOnSocket) Client::Send(e); + } + std::ostringstream os; + os << "Scaler with base address 0x" << std::hex << address << " successfully built"; + throw Exception(__PRETTY_FUNCTION__, os.str(), Info, TDC_ACQ_START); +} + void VMEReader::AddCFD(uint32_t address) { diff --git a/src/VME_ScalerV8x0.cpp b/src/VME_ScalerV8x0.cpp new file mode 100644 index 0000000..9946bd9 --- /dev/null +++ b/src/VME_ScalerV8x0.cpp @@ -0,0 +1,215 @@ +#include "VME_ScalerV8x0.h" + +namespace VME +{ + ScalerV8x0::ScalerV8x0(int32_t bhandle, uint32_t baseaddr) : + GenericBoard(bhandle, baseaddr), gEnd(false) + { + std::ostringstream os; + os << "New Scaler module added:" << "\n\t" + //<< " Identifier: 0x" << std::hex << GetIdentifier() << "\n\t" + << " Serial number: " << std::dec << GetSerialNumber() << "\n\t" + << " Version: " << std::dec << GetModuleVersion() << "\n\t" + << " Type: " << std::dec << GetModuleType() << "\n\t" + << " Manufacturer: 0x" << std::hex << GetManufacturerId(); + PrintInfo(os.str()); + fBuffer = (unsigned int*)malloc(32*1024*1024); // 32MB of buffer! + if (fBuffer==NULL) { + throw Exception(__PRETTY_FUNCTION__, "Output buffer has not been allocated!", Fatal); + } + + // Default values + SetPOI(0xffffffff); + + ScalerV8x0Control control = GetControl(); + control.SetDataFormat(DF26bit); + control.SetAcquisitionMode(ScalerV8x0Control::TriggerDisabled); + control.SetBusError(false); + control.SetHeader(true); + control.SetClearMEB(false); + control.SetAutoReset(false); + SetControl(control); + } + + ScalerV8x0::~ScalerV8x0() + { + free(fBuffer); + fBuffer = NULL; + } + + unsigned int + ScalerV8x0::GetSerialNumber() const + { + uint16_t word1, word2; + try { + ReadRegister(kV8x0SerialMSB, &word1); + ReadRegister(kV8x0SerialLSB, &word2); + return static_cast(((word1&0xffff)<<16)+(word2&0xffff)); + } catch (Exception& e) { e.Dump(); } + return 0; + } + + unsigned short + ScalerV8x0::GetModuleVersion() const + { + uint16_t word; + try { + ReadRegister(kV8x0HWRevision, &word); + return static_cast(word&0xffff); + } catch (Exception& e) { e.Dump(); } + return 0; + } + + unsigned short + ScalerV8x0::GetModuleType() const + { + uint16_t word; + try { + ReadRegister(kV8x0ModelVersion, &word); + return static_cast(word&0xffff); + } catch (Exception& e) { e.Dump(); } + return 0; + } + + unsigned short + ScalerV8x0::GetManufacturerId() const + { + uint16_t word; + try { + ReadRegister(kV8x0OUI, &word); + return static_cast(word&0xffff); + } catch (Exception& e) { e.Dump(); } + return 0; + } + + /*unsigned short + ScalerV8x0::GetIdentifier() const + { + uint16_t word; + try { + ReadRegister(kIdentifier, &word); + return word; + } catch (Exception& e) { e.Dump(); } + return 0; + }*/ + + unsigned short + ScalerV8x0::GetGEO() const + { + uint16_t word; + try { + ReadRegister(kV8x0GEO, &word); + return static_cast(word&0x1f); + } catch (Exception& e) { e.Dump(); } + return 0; + } + + void + ScalerV8x0::SetPOI(unsigned int poi) const + { + try { + WriteRegister(kV8x0ChannelEnable, poi); + } catch (Exception& e) { e.Dump(); } + } + + unsigned int + ScalerV8x0::GetPOI() const + { + uint32_t word; + try { + ReadRegister(kV8x0ChannelEnable, &word); + return static_cast(word); + } catch (Exception& e) { e.Dump(); } + return 0; + } + + unsigned int + ScalerV8x0::GetTriggerCounter() const + { + uint32_t word; + try { + ReadRegister(kV8x0TriggerCounter, &word); + return static_cast(word); + } catch (Exception& e) { e.Dump(); } + return 0; + } + + unsigned int + ScalerV8x0::GetChannelValue(unsigned short channel_id) const + { + if (channel_id<0 or channel_id>31) { + std::ostringstream os; os << "Trying to extract the value of a channel outside allowed range: " << channel_id; + throw Exception(__PRETTY_FUNCTION__, os.str(), JustWarning); + } + uint32_t word; + ScalerV8x0Register reg = static_cast(kV8x0ChannelValue+(channel_id*4)); + try { + ReadRegister(reg, &word); + return static_cast(word); + } catch (Exception& e) { e.Dump(); } + return 0; + } + + ScalerEventCollection + ScalerV8x0::FetchEvents() + { + if (gEnd) + throw Exception(__PRETTY_FUNCTION__, "Abort state detected... quitting", JustWarning, TDC_ACQ_STOP); + ScalerEventCollection ec; ec.clear(); + + memset(fBuffer, 0, sizeof(unsigned int)); + + int count = 0; + const int blts = 4096; // size of the transfer in bytes + bool finished; + std::ostringstream o; + + // Start Readout (check if BERR is set to 0) + CVErrorCodes ret = CAENVME_BLTReadCycle(fHandle, fBaseAddr+kV8x0OutputBuffer, (char*)fBuffer, blts, cvA32_U_BLT, cvD32, &count); + finished = ((ret==cvSuccess)||(ret==cvBusError)||(ret==cvCommError)); //FIXME investigate... + if (finished && gEnd) { + throw Exception(__PRETTY_FUNCTION__, "Abort state detected... quitting", JustWarning, TDC_ACQ_STOP); + } + for (int i=0; i