Skip to content
Snippets Groups Projects
Commit d34ce6d9 authored by tzhang74's avatar tzhang74
Browse files

initial

parents
Branches master
No related tags found
No related merge requests found
Showing
with 1634 additions and 0 deletions
# basic makefile
HERE=$(shell pwd)
CXX = g++
RM = rm -rf
INCLUDEDIRS = -I$(XXUSBDIR)/include -I./include
LIBDIRS = -L$(XXUSBDIR)/lib
LIBS = -lxx_usb -lm -lusb
CXXFLAGS = -g -O2 -Wall `root-config --cflags`
LDFLAGS = -O2 `root-config --glibs` -Wl,-rpath=$(XXUSBDIR)/lib
SOURCES = MyDaq.cpp MyMainFrame.cpp GenericModule.cpp Phillips2249W.cpp SharedData.cpp CC-DAQ.cpp
INCLUDES = MyDaq.h MyMainFrame.h GenericModule.h Phillips2249W.h SharedData.h Module.h Common.h LinkDef.h
OBJ = runMyDaq
SOURCEDIR = src/
INCLUDEDIR = include/
CSOURCES = $(addprefix $(SOURCEDIR),$(SOURCES))
CINCLUDES = $(addprefix $(INCLUDEDIR),$(INCLUDES))
RUNDIR = run/
all: $(CSOURCES) $(CINCLUDES) $(SOURCEDIR)MyMainFrameDict.cpp
$(CXX) $(CXXFLAGS) $(INCLUDEDIRS) $(CSOURCES) $(SOURCEDIR)MyMainFrameDict.cpp \
$(LIBDIRS) $(LIBS) $(LDFLAGS) -o $(OBJ)
[ -d $(RUNDIR) ] || mkdir $(RUNDIR)
mv $(OBJ) $(RUNDIR)
[ -f $(RUNDIR)env.sh ] || echo "export XXUSBDIR="$(XXUSBDIR) >> $(RUNDIR)env.sh
@echo "Done"
$(SOURCEDIR)MyMainFrameDict.cpp: $(SOURCEDIR)MyMainFrame.cpp $(INCLUDEDIR)MyMainFrame.h
rootcling -f $(SOURCEDIR)MyMainFrameDict.cpp -c $(INCLUDEDIRS) MyMainFrame.h $(INCLUDEDIR)LinkDef.h
[ -d $(RUNDIR) ] || mkdir $(RUNDIR)
cp $(SOURCEDIR)MyMainFrameDict* $(RUNDIR)
clean:
$(RM) $(RUNDIR)MyMainFrameDict* $(RUNDIR)$(OBJ) $(SOURCEDIR)MyMainFrameDict*
#ifndef COMMON_H
#define COMMON_H
#include <vector>
#include <map>
#include <string>
#define CONTINUATION_BIT (0x8000) // 15th bit = 32768
#define LONG_MODE_BIT (0x4000) // 14th bit = 16384
#define ADDRESS_SCAN_BIT (0x0020) // 5th bit = 32
#define Q_STOP_BIT (0x0010) // 4th bit = 16
#define STACK_END_MARKER (0xFFFF)
#define MODULE_END_MARKER (0xDDDD)
#define MAX_STACK_SIZE (256)
class TTree;
class TFile;
class TH1;
class TF1;
class TApplication;
class MyDaq;
class SharedData;
class Module;
class Phillips_2249W;
class MyDaq;
class MyMainFrame;
#endif
#ifndef GENERICMODULE_H
#define GENERICMODULE_H
#include "Common.h"
#include "Module.h"
/**
@brief GenericModule class. Most basic kind of module.
Has standard reading, writing, clearing commands.
Example is Lecroy 2249W. Data is most simple 12bit.
*/
class GenericModule : public Module{
public:
/**
@brief Default constructor for GenericModule.
*/
GenericModule();
/**
@brief Overloaded constructor for GenericModule.
@param param1 GenericModule name
@param param2 Number of channels in this module
@param param3 Slot number of this module in CAMAC
@param param4 Command (F) used for reading
@param param5 Number of digits for data
*/
GenericModule( std::string, int, int, int, int);
/**
@brief Default destructor for GenericModule
*/
virtual ~GenericModule();
/**
@brief Function to connect to MyDaq's SharedData
@param param1 Pointer to shared data
*/
virtual void RegisterSharedData( SharedData* );
/**
@brief Function adds reading with clear to stack.
@param param1 Reference to stack being built
*/
virtual void AddClearingReadToStack( std::vector<long>& );
/**
@brief Function creates simple CAMAC (N,A,F) command.
@param param1 N value
@param param2 A value
@param param3 F value
@return long representing CAMAC command
*/
virtual long CreateSimpleCommand( int, int, int );
/**
@brief Function adds output for given module
*/
virtual void AddOutput ();
/**
@brief Function reads data from module
@param param1 Address where module's data beings
*/
virtual void ReadData( short* );
/**
@brief Function to fill histograms for module
*/
virtual void FillHistograms();
/**
@brief Function prints info about module
*/
virtual void Print();
};
#endif
#pragma link C++ class MyMainFrame+;
#ifndef MODULE_H
#define MODULE_H
#include "Common.h"
/**
@brief Module class. Pure virtual class;
*/
class Module{
public:
/**
@brief Default constructor for Module.
*/
Module() {};
/**
@brief Overloaded constructor for Module.
@param param1 Module name
@param param2 Number of channels in this module
@param param3 Slot number of this module in CAMAC
@param param4 Command (F) used for reading
@param param5 Number of digits for data
*/
Module( std::string, int, int, int, int) {};
/**
@brief Default destructor for Module
*/
virtual ~Module() {};
/**
@brief Function to connect to MyDaq's SharedData
@param param1 Pointer to shared data
*/
virtual void RegisterSharedData( SharedData* ) = 0;
/**
@brief Function adds reading with clear to stack.
@param param1 Reference to stack being built
*/
virtual void AddClearingReadToStack( std::vector<long>& ) = 0;
/**
@brief Function creates simple CAMAC (N,A,F) command.
@param param1 N value
@param param2 A value
@param param3 F value
@return long representing CAMAC command
*/
virtual long CreateSimpleCommand( int, int, int ) = 0;
/**
@brief Function adds output for given module
*/
virtual void AddOutput () = 0;
/**
@brief Function reads data from module
@param param1 Address where module's data beings
*/
virtual void ReadData( short* ) = 0;
/**
@brief Function to fill histograms for module
*/
virtual void FillHistograms() = 0;
/**
@brief Function prints info about module
*/
virtual void Print() = 0;
/**
@brief Accessor for number of channels
*/
int GetNchannels(){ return m_nChannels; }
protected:
std::string m_moduleName;
int m_nChannels;
int m_slotNumber;
int m_readCommand;
int m_nDigitsData;
/// pointer to dataBank
short* m_dataBank;
SharedData* m_sd;
// histograms belonging to this module
std::vector<TH1*> m_hists;
};
#endif
#ifndef MYDAQ_H
#define MYDAQ_H
#include "Common.h"
#include <libxxusb.h>
#include <thread>
#include <atomic>
#include <TString.h>
/**
@brief MyDaq is the main class for the DAQ system.
It can be though of as the CAMAC crate and controller.
From here, we do the control of the whole system.
This class is instanciated by the user, and modules are added
by the user. The user can then Run the DAQ with the rest of
the interface hidden from them.
*/
class MyDaq{
friend class MyMainFrame;
public:
/**
@brief Default constructor for MyDaq.
*/
MyDaq();
/**
@brief Default destructor for MyDaq.
*/
~MyDaq();
public:
/**
@brief Function to add modules to MyDaq
@param param1 Pointer to module being added
*/
void AddModule( Module* );
/**
@brief Main function in MyDaq. Called by user.
*/
int Run();
private:
/**
@brief Function to print info about DAQ
*/
void PrintInfo();
/**
@brief Function to initialize CAMAC
*/
int InitializeCAMAC();
/**
@brief Function to Prepare and load stack into DAQ
*/
int PrepareAndLoadStack();
/**
@brief Function to Initialize output data for modules
*/
void InitializeModulesOutput();
/**
@brief Function to initialize DAQ
*/
void InitializeDAQ();
/**
@brief Function to take data
*/
void TakeData();
/**
@brief Function processes data bank into ROOT
*/
void ProcessDataIntoROOT();
/**
@brief Function to finalize data taking
*/
void Finalize();
private:
xxusb_device_type devices[100];
struct usb_device *dev; // Device
usb_dev_handle *udev; // Device Handle
/// collection of modules in DAQ
std::vector< Module* > m_modules;
long m_firmware_id;
long m_nWordsExpectedPerEvent;
/// Pointer to Data Class
SharedData* m_sd;
// Application Stuff
TApplication* m_theApp;
MyMainFrame* m_myMainFrame;
TString m_fout_name;
// thread things
std::thread* m_t_app;
std::thread* m_t_daq;
std::atomic<bool> m_start_flag;
std::atomic<bool> m_stop_flag;
public:
/**
@brief Getter for shared data
*/
SharedData* GetSharedData(){ return m_sd; }
};
#endif
#ifndef MYMAINFRAME_H
#define MYMAINFRAME_H
#include "Common.h"
#include <TString.h>
#include <TGFrame.h>
class TGHorizontalFrame;
class TGTextButton;
class TGTextButton;
class TGTextEntry;
class TRootEmbeddedCanvas;
class TTimer;
/**
@brief This class is made to control the program from a GUI.
This way, the user can start and stop the run at any time with just
a click of the mouse. Taken from online.
*/
class MyMainFrame : public TGMainFrame {
private:
TRootEmbeddedCanvas *m_fEcanvas;
TTimer* fTimer;
TGHorizontalFrame* m_hframe;
TGTextButton* m_startB;
TGTextButton* m_stopB;
TGTextEntry* m_fTextEntry;
MyDaq* m_daq;
public:
/**
@brief Constructor for MyMainFrame
*/
MyMainFrame(const TGWindow*, UInt_t , UInt_t, MyDaq* daq);
/**
@brief Default destructor for MyMainFrame
*/
virtual ~MyMainFrame();
/**
@brief Handle timer - do updates on canvas
*/
Bool_t HandleTimer(TTimer *);
/**
@brief Function to start Run
*/
void DoStart();
/**
@brief Function to stop Run
*/
void DoStop();
public:
ClassDef(MyMainFrame,0)
};
#endif
#ifndef PHILLIPS2249W_H
#define PHILLIPS2249W_H
#include "Common.h"
#include "GenericModule.h"
/**
@brief Phillips2249W (TDC) class. Inherits from Module.
Mostly the same except for reading data. It has
a default read command which.
*/
class Phillips2249W : public GenericModule{
public:
/**
@brief Overloaded constructor for Phillips2249W.
@param param1 Module name
@param param2 Number of channels in this module
@param param3 Slot number of this module in CAMAC
*/
Phillips2249W( std::string, int, int );
/**
@brief Default destructor for Phillips2249W
*/
virtual ~Phillips2249W();
/**
@brief Function adds output for a Phillips2249W
*/
virtual void AddOutput ();
/**
@brief Function reads data from a Phillips2249W
@param param1 Address where module's data beings
*/
virtual void ReadData( short* p );
/**
@brief Function to fill histograms for a Phillips2249W
*/
virtual void FillHistograms();
private:
short m_tdcsum;
TH1* m_h_tdcsum;
};
#endif
#ifndef SHAREDDATA_H
#define SHAREDDATA_H
#include "Common.h"
/**
@brief This class is made so that all modules can
connect to a common database that can only be created
from MyDaq.
This way, all modules can add to the tree,
and add their histograms to a common collection.
At the end, this tree and histograms will be written to file.
*/
class SharedData{
friend class MyDaq;
private:
/**
@brief Default destructor for SharedData
*/
SharedData();
/**
@brief Default destructor for SharedData
*/
~SharedData();
/**
@brief Function to finalize and write all data to file.
*/
void Finalize();
TFile* m_fout;
TTree* m_tree;
std::map< std::string, TH1* > m_m_hists;
public:
/**
@brief Getter for output file
*/
TFile* GetFout(){ return m_fout; }
/**
@brief Getter for ttree
*/
TTree* GetTree(){ return m_tree; }
/**
@brief Getter for map of string to histos
*/
std::map< std::string, TH1* >& GetHists()
{ return m_m_hists; }
/**
@brief Setter for output file
*/
void SetFout( TFile* f ){ m_fout = f; }
};
#endif
#include "MyDaq.h"
#include "GenericModule.h"
#include "Phillips2249W.h"
#include <TApplication.h>
#include <iostream>
int main (int argc, char *argv[])
{
MyDaq* daq = new MyDaq();
// Add ADC module with 12 channels to slot 1. Has 10 bit output
daq->AddModule( new GenericModule( "ADC", 12, 1, 2, 1024) );
// Add ADC module with 12 channels to slot 2. Has 10 bit output
daq->AddModule( new GenericModule( "ADC", 12, 2, 2, 1024) );
// Add STDC module with 16 channels to slot 8. Has 12 bit output
daq->AddModule( new Phillips2249W( "STDC", 16, 8 ) );
// Add FTDC module with 8 channels to slot 9. Has 11 bit output
daq->AddModule( new GenericModule( "FTDC", 8, 9, 2, 2048) );
// Add ADC Lecroy 2259A module with 12 channels to slot 16. Has ??? bit output. TZ
daq->AddModule( new GenericModule( "FTDC", 12, 16, 2, 4096) );
daq->Run();
return 0;
}
/**
* @file GenericModule.cpp
* Implementation for GenericModule class
*
* @brief
*
* @author Yakov Kulinich
* @version 1.0
*/
#include "GenericModule.h"
#include "SharedData.h"
#include <stdio.h>
#include <TTree.h>
#include <TFile.h>
#include <TH1.h>
#include <TSystem.h>
#include <TCanvas.h>
#include <iostream>
//--------------------------------
// GenericModule
//--------------------------------
GenericModule :: GenericModule() {
m_moduleName = "NONE"; m_nChannels = 0; m_slotNumber = 0; m_dataBank = NULL; m_readCommand = 0; m_tdcsum = 0; m_h_tdcsum = NULL;
}
GenericModule :: GenericModule( std::string moduleName, int nChannels, int slotNumber, int readCommand, int nDigitsData ) {
m_moduleName = moduleName;
m_nChannels = nChannels;
m_slotNumber = slotNumber;
m_readCommand = readCommand;
m_nDigitsData = nDigitsData;
m_dataBank = new short[nChannels];
m_tdcsum = 0;
m_h_tdcsum = NULL;
}
GenericModule :: ~GenericModule(){
delete [] m_dataBank;
m_dataBank = NULL;
}
void GenericModule :: RegisterSharedData( SharedData* sd ) {
m_sd = sd;
}
/**
Adds series of read commands to stack.
These depend on module's slot number and read command.
Stop bits (16) are added before and after the commands.
*/
void GenericModule :: AddClearingReadToStack( std::vector<long>& stack ){
stack.push_back( Q_STOP_BIT );
for( int i = 0; i < m_nChannels; i++ ){
stack.push_back( CreateSimpleCommand( m_slotNumber, i, m_readCommand) );
}
stack.push_back( CreateSimpleCommand( m_slotNumber, 0, 9 ) ); // N,0,9 (N,A,F)
stack.push_back( Q_STOP_BIT );
}
/**
CAMAC Commands are constructed as follows.
command = N*512 + A*32 + F
equivalent to
command = N*2^9 + A*2^5 + F
*/
long GenericModule :: CreateSimpleCommand( int N, int A, int F){
return ( N<<9 ) + ( A<<5 ) + F;
}
/**
Add output for this module. This means adding branches
to the tree and creating histograms.
For basic module, we assume a 10 bit module even though its a 12
bit data word. (Front 2 bits are for?)
10 bit module means 0-1024 channels.
*/
void GenericModule :: AddOutput(){
char name [128];
for( int ch = 0; ch < m_nChannels; ch++){
sprintf( name, "h_%s_%d_%d", m_moduleName.c_str(), m_slotNumber, ch );
m_hists.push_back( new TH1F( name, name, m_nDigitsData + 10 , 0, m_nDigitsData + 10 ) );
m_sd->GetHists()[ name ] = m_hists.back();
sprintf( name, "%s_%d_%d", m_moduleName.c_str(), m_slotNumber, ch );
m_sd->GetTree()->Branch( name, &m_dataBank[ch] );
}
sprintf( name, "h_%s_%d_SUM", m_moduleName.c_str(), m_slotNumber );
m_h_tdcsum = new TH1F( name, name, m_nDigitsData + 10 , 0, m_nDigitsData + 10 );
m_sd->GetHists()[ name ] = m_h_tdcsum;
sprintf( name, "%s_%d_SUM", m_moduleName.c_str(), m_slotNumber );
m_sd->GetTree()->Branch( name, &m_tdcsum );
}
/**
For a simple module the data is simple. We read the
word and the data is that!
p is going to point at first actual data member.
This is the first channel in most modules. First data
member is next item after the Q_STOP_BIT.
*/
void GenericModule :: ReadData( short* p ){
for( int i = 0; i < m_nChannels; i++ ){
m_dataBank[i] = *(p + i);
}
}
/**
Here we just go and fill histograms based on our
data bank information.
These histograms are for monitoring, so if the value
is 0 or m_nDigitsData we dont fill (so we only see useful info).
One can then compare total number of events to number of entries
in the histogram to see how well the module is working.
*/
void GenericModule :: FillHistograms(){
for( int ch = 0; ch < m_nChannels; ch++){
short data = m_dataBank[ch];
if( data > 0 && data < m_nDigitsData)
m_hists.at(ch)->Fill( m_dataBank[ch] );
}
}
void GenericModule :: Print() {
std::cerr << m_moduleName << " with "
<< m_nChannels << " channels in "
<< m_slotNumber << " slot number." << std::endl;
}
/**
* @file MyDaq.cpp
* Implementation for MyDaq class
*
* @brief
*
* @author Yakov Kulinich
* @version 1.0
*/
#include "MyDaq.h"
#include "Module.h"
#include "SharedData.h"
#include "MyMainFrame.h"
#include <stdio.h>
#include <time.h>
#include <math.h>
#include <unistd.h>
#include <TTree.h>
#include <TFile.h>
#include <TH1.h>
#include <TSystem.h>
#include <TCanvas.h>
#include <TApplication.h>
#include <TGClient.h>
#include <iostream>
static const int STACK_VERBOSE = 0;
//--------------------------------
// MyDaq
//--------------------------------
/**
Adds a module to the collection of MyDaq's modules.
MyDaq, who is the only one that can make SharedData,
lets the modules know about the shared data by passing
them a copy of the pointer.
*/
MyDaq :: MyDaq () {
m_sd = new SharedData();
m_nWordsExpectedPerEvent = 0;
m_t_app = NULL;
m_t_daq = NULL;
m_start_flag = false;
m_stop_flag = false;
}
MyDaq :: ~MyDaq() {
delete m_sd;
delete m_t_app;
delete m_t_daq;
delete m_theApp;
delete m_myMainFrame;
m_sd = NULL;
}
void MyDaq :: AddModule( Module* module ) {
m_modules.push_back( module );
module->RegisterSharedData( m_sd );
}
void MyDaq :: PrintInfo(){
std::cerr << "Firmware ID : " << m_firmware_id << std::endl;
std::cerr << "Available modules are : \n" << std::endl;
for( auto& module : m_modules ) module->Print();
}
/**
Here the DAQ is initialized, stack loaded, and running started.
At the end of the run, output is finalized and the program exits.
*/
int MyDaq :: Run(){
std::cerr << "\n MyDaq :: Run\n" << std::endl;
if( !InitializeCAMAC() ) return 0;
PrintInfo();
if( !PrepareAndLoadStack() ) return 0;
InitializeModulesOutput();
m_theApp = new TApplication("App", NULL, NULL);
m_myMainFrame = new MyMainFrame( gClient->GetRoot(), 400, 400, this);
m_t_app = new std::thread( [this] { m_theApp->Run( kTRUE ); } );
while( !m_start_flag && !m_stop_flag ) continue;
if( m_start_flag && !m_stop_flag ){
InitializeDAQ();
m_t_daq = new std::thread( [this] { TakeData(); } );
// We have a start, and we join the threads, now MyDaq::Run waits until both threads finish
m_t_app->join();
m_t_daq->join();
}
else if( !m_start_flag && m_stop_flag ){
std::cerr << "\nNever started DAQ. Quitting!" << std::endl;
return 0;
}
// Both threads are done, we can finalize (write output and quit).
Finalize();
return 1;
}
/**
First, attempt to find a cc-usb device. If it is found,
and it responds, try to open/connect to it.
Once all this is successful, the device handle, which is a hook
from our device to this code, is used throughout the program in
function calls that go to cc-usb.
Some read, write, clear, inhibit calls are tested
Also, the trigger delay (100 us) and buffer size (4k) are set.
*/
int MyDaq :: InitializeCAMAC(){
std::cerr << "\n MyDaq :: InitializeCAMAC\n" << std::endl;
int CamQ, CamX; // X, Q dataway info, D is dummy
long CamD; // Dummy for CAMAC_read which shouldnt read anything
std::cerr << "Finding XX_USB devices and opening first one found" << std::endl;;
//Find XX_USB devices and open the first one found
xxusb_devices_find(devices);
dev = devices[0].usbdev;
if( dev <= 0 ){
std::cerr << "\n\nDevice not xxusb\n\n" << std::endl;
return 0;
}
udev = xxusb_device_open(dev);
if(!udev) {
std::cerr << "\n\nFailedto Open CC_USB \n\n" << std::endl;
return 0;
}
else{
std::cerr << "Found XX_USB device" << std::endl;;
CAMAC_read( udev, 25, 0, 0, &m_firmware_id, &CamQ, &CamX);
}
std::cerr << "\nTesting data lines...." << std::endl;
short ret = -1;
// Fix this up ??
ret = CAMAC_Z(udev);
if( ret > 0 ) ret = CAMAC_I(udev, true);
if( ret > 0 ) ret = CAMAC_write(udev, 1, 0, 16, 0xa,&CamQ, &CamX);
if( ret > 0 ) ret = CAMAC_read(udev, 1, 0, 0, &CamD,&CamQ, &CamX);
if( ret > 0 ) ret = CAMAC_C(udev);
if( ret > 0 ) ret = CAMAC_I(udev, false);
if( ret > 0 ) ret = CAMAC_Z(udev);
if( ret <= 0 ) {
std::cerr << "Some data lines didnt work" << std::endl;
return 0;
}
std::cerr << "Done testing data lines....\n" << std::endl;;
// Define Trigger to be Crate Trigger (L1)
CAMAC_write( udev, 25, 9, 16, 0x0, &CamQ, &CamX );
// Define Trigger Delay to 100us. Bits 0 to 15 in Delay Register N(25) A(2) F(16)
ret = CAMAC_write(udev, 25, 2, 16, 0x64,&CamQ, &CamX);
// Set buffer size to 4k BuffOpt in Global Mode register N(25) A(1) F(16)
ret = CAMAC_write(udev, 25, 1, 16, 0x02,&CamQ, &CamX);
return 1;
}
/**
Prepare the stack. Loop through the modules in this DAQ
And add their clearing read commands to stack. Commands
are preceeded and followed by q-stop bits. Q-stop bit also
added after first element of stack. Final marker word added at bottom.
Stack is then written to the cc-usb, and read for verification.
*/
int MyDaq :: PrepareAndLoadStack(){
std::cerr << "\n MyDaq :: PrepareAndLoadStack\n" << std::endl;
// prepare stack and load to CC-USB
std::vector< long > writeStack; // leave this dynamic, easier
long readStack[MAX_STACK_SIZE]; // max stack size = 256 for now
writeStack.push_back(0);
writeStack.push_back( Q_STOP_BIT );
for( auto& module : m_modules ){ // Loop over all modules
module->AddClearingReadToStack( writeStack );
}
// End Marker
writeStack.push_back( STACK_END_MARKER ); // marker = ffff
long nStackCommands = writeStack.size() - 1;
writeStack[0] = nStackCommands;
// Load stack into CC-USB
short nBytesSent = xxusb_stack_write(udev, 2, &(writeStack[0]) );
// verify stack
short nBytesRecieved = xxusb_stack_read(udev, 2, readStack);
long nReadStackCommands = readStack[0];
if( nStackCommands != nReadStackCommands ||
(nBytesSent - 2 - nBytesRecieved) != 0 ){
std::cerr << "Something wrong with stack " << std::endl;
return 0;
}
if( STACK_VERBOSE){
std::cerr << "Stack Size = " << nStackCommands << std::endl;
std::cerr << " WRITE STACK" << std::endl;
for( int i = 0; i < nStackCommands; i++){
std::cerr << i << " command = " << writeStack[i] << std::endl;
}
std::cerr << " VERIFY STACK" << std::endl;
for( int i = 0; i < nReadStackCommands; i++){
std::cerr << i << " command = " << readStack[i] << std::endl;
}
std::cerr << "Verified Stack Size = " << nStackCommands << std::endl;
}
short ret = xxusb_stack_execute(udev, &(writeStack[0]) );
std::cerr << ret << " Stack executed once" << std::endl;
return 1;
}
void MyDaq :: InitializeModulesOutput(){
std::cerr << "\n MyDaq :: InitializeModulesOutput\n" << std::endl;
for( auto& module : m_modules ) {
module->AddOutput();
m_nWordsExpectedPerEvent += (module->GetNchannels() + 1);
}
// one for first word (nwords expected)
// and one for negative one at end
m_nWordsExpectedPerEvent += 2;
std::cerr << "Number of words expected per even is " << m_nWordsExpectedPerEvent << std::endl;
}
/**
Function to start acquisition ( write to xxusb register )
Also create output filename based on either user input
or default (output.root).
*/
void MyDaq :: InitializeDAQ(){
// START DAQ
xxusb_register_write(udev, 1, 0x1); // start acquisition
// got a start, inform that we are begining reading
std::cerr << "Switch to DAQ & Reading data\n" << std::endl;
std::cerr << "Output Filename = " << m_fout_name.Data() << std::endl;
m_sd->SetFout( new TFile( m_fout_name.Data(),"RECREATE") );
}
/**
Main loop for reading data from CC-USB.
Once we enter daq mode, we start taking data continuously.
The crate will write out only when its buffer is full.
The main GUI application and the TakeData() run on separate threads
and there are some flags that the GUI application controls which
indicate in TakeData() when to start and when to stop.
These flags are atomic variables so there should not be any lock problems.
*/
void MyDaq :: TakeData() {
std::cerr << "\n MyDaq :: TakeData\n" << std::endl;
short ret = -1;
short dataStream[100000];
long wordsReturned = 0;
long bytesReturned = 0;
int nLoopsRead = 0;
unsigned int nModules = m_modules.size();
int loop = 0;
int totalEvents = 0;
while(true){
bytesReturned = xxusb_bulk_read(udev, dataStream, 2056, 100); // use for32-bit data
wordsReturned = bytesReturned / 2;
if( bytesReturned > 0 ) {
int nEvents = (dataStream[0] & 0xffff);
totalEvents += nEvents;
printf("Events in loop %i : %i bytesReturned : %ld totalEvents : %d\n", loop, nEvents, bytesReturned, totalEvents);
nLoopsRead++;
// Check if number of recieved words in the packet matches how much
// we expect for a given number of events (dataStream[0] element)
if( (m_nWordsExpectedPerEvent * nEvents + 2 ) != wordsReturned ){
std::cerr << "Bad Packet - Dropping" << std::endl;
continue;
}
// We have recieved our data packet, we know number of data lines
// and we know number of events in that packet.
// [0] element in package is number of events. We set
// out data pointer to look there
short* dataPtr = dataStream;
// Check to see if we have a a -1 (trailer last event), -1, 0. (End of packet)
// at the end of the packet. If we do, we can consider the packet
// to probably be correct. additional checks to be performed
// on per-event basis
if( *( dataPtr + m_nWordsExpectedPerEvent * nEvents ) == -1 &&
*( dataPtr + m_nWordsExpectedPerEvent * nEvents + 1) == -1 &&
*( dataPtr + m_nWordsExpectedPerEvent * nEvents + 2) == 0) {
// !!! GOOD PACKET !!!
// First event in packet...
//W
// Now we set our dataPtr to look at [1] element.
// This is the number of data in our event.
// This includes a Q_STOP_BIT for every module, and a -1 trailer,
// plus number of channels in every module.
//
// I.e. for one 12 channel ADC and 16 channel TDC we expect
// 12 + 1 + 16 + 1 + 1 (for -1) = 31 words
dataPtr++;
// we know we have a good packet...
// but are all the events inside good?
// so far assume yes
bool isBadEvent = false;
// START EVENT LOOP.
// should now be looking at dataStream[1]
for( int ev = 0; ev < nEvents; ev++ ){
if( isBadEvent ) break;
// At the beginning of every event, the dataPtr should be looking at
// the first element of the event, which is number of words expected.
//
// Check if m_nWordsExpectedPerEvent - 1 matches what we read
// the Minus one because the number which tells us how many words there are
// is also a word in the event.
//
// I.e. for our example of one ADC and one TDC we expect 32 words per event,
// so we echeck if *dataPtr is equal to 32 - 1 = 31
if( *( dataPtr ) == ( m_nWordsExpectedPerEvent - 1) &&
*( dataPtr + m_nWordsExpectedPerEvent - 1) == -1 &&
*( dataPtr + 1 ) == Q_STOP_BIT ){
// !!! GOOD EVENT !!!
// dataPtr should now jump to zeroth data element
// of zeroth module
dataPtr += 2;
for( unsigned int moduleNumber = 0; moduleNumber < nModules; moduleNumber++){
m_modules[ moduleNumber ]->ReadData( dataPtr );
dataPtr += m_modules[ moduleNumber ]->GetNchannels();
dataPtr++;
}
} // END GOOD EVENT
else{
std::cerr << "Bad Event " << ev << " - Dropping" << std::endl;
isBadEvent = true;
}
// m_dataBanks are filled, now lets
// fill ROOT Tree and histos.
ProcessDataIntoROOT();
} // END EVENT LOOP
}
else{
std::cerr << "Bad Packet - Dropping" << std::endl;
continue;
}
}
if( m_stop_flag ){
std::cerr << "\n\nFinishing Run!" << std::endl;
std::cerr << "Took " << totalEvents << " Events\n\n" << std::endl;
break;
}
loop ++;
}
// leave DAQ mode
xxusb_register_write(udev, 1, 0x0);
// CLEAN UP!!
// drain all data from fifo
ret=1;
loop = 0;
while(ret > 0) {
ret = xxusb_bulk_read(udev, dataStream, 2048, 100);
if(ret > 0){
printf("drain loops: %i (result %i)\n", loop, ret);
loop++;
if (loop > 100) ret=0;
}
}
xxusb_register_write(udev, 1, 0x0);
}
/**
Done on a per-event basis
This function processes each modules m_dataBank to add
information to ROOT Tree and histos.
This can be added onto later, or a function such as
ProcessDataIntoBinary can be added. Also, if in the future
a user wants to add additional branches to the ROOT tree,
they can do it here.
ReadData should be left alone, as it
does the most basic thing.
*/
void MyDaq :: ProcessDataIntoROOT(){
for( auto& module : m_modules ) module->FillHistograms();
m_sd->m_tree->Fill();
}
void MyDaq :: Finalize() {
std::cerr << "\n MyDaq :: Finalize \n" << std::endl;
m_sd->Finalize();
}
/**
* @file MyMainFrame.cpp
* Implementation for MyMainFrame class
*
* @brief
*
* @author Yakov Kulinich
* @version 1.0
*/
#include "MyMainFrame.h"
#include "SharedData.h"
#include "MyDaq.h"
#include <stdio.h>
#include <TTree.h>
#include <TFile.h>
#include <TH1.h>
#include <TString.h>
#include <TSystem.h>
#include <TCanvas.h>
#include <TApplication.h>
#include <TGClient.h>
#include <TGButton.h>
#include <TGTextEntry.h>
#include <TRootEmbeddedCanvas.h>
#include <TTimer.h>
#include <iostream>
MyMainFrame::MyMainFrame(const TGWindow *p, UInt_t w, UInt_t h, MyDaq* daq) :
TGMainFrame(p, w, h), m_daq(daq) {
// Create canvas widget
m_fEcanvas = new TRootEmbeddedCanvas("Ecanvas", this, w/2, h);
AddFrame(m_fEcanvas, new TGLayoutHints(kLHintsExpandX | kLHintsExpandY,
10,10,10,1));
// timer handling.
TCanvas *fCanvas = m_fEcanvas->GetCanvas();
fCanvas->Divide(1,2);
fCanvas->cd(1);
m_daq->GetSharedData()->GetHists()["h_STDC_8_SUM"]->Draw();
fCanvas->cd(2);
m_daq->GetSharedData()->GetHists()["h_FTDC_9_SUM"]->Draw();
// Create a horizontal frame widget with buttons
m_hframe = new TGHorizontalFrame(this,200,40);
m_startB = new TGTextButton( m_hframe,"&Start");
m_startB->Connect("Clicked()","MyMainFrame",this,"DoStart()");
m_hframe->AddFrame(m_startB, new TGLayoutHints( kLHintsLeft, 5, 5, 3, 4 ) );
m_stopB = new TGTextButton( m_hframe,"&Stop");
m_stopB->Connect("Clicked()","MyMainFrame",this,"DoStop()");
m_hframe->AddFrame(m_stopB, new TGLayoutHints( kLHintsRight, 5, 5, 3, 4 ) );
m_fTextEntry = new TGTextEntry( m_hframe, new TGTextBuffer(40));
m_hframe->AddFrame(m_fTextEntry, new TGLayoutHints( kLHintsLeft, 5, 5, 3, 4 ) );
AddFrame(m_hframe, new TGLayoutHints( kLHintsCenterX, 2, 2, 2, 2 ) );
// Set a name to the main frame
SetWindowName("MUON DAQ");
// Map all subwindows of main frame
MapSubwindows();
// Initialize the layout algorithm
Resize(GetDefaultSize());
// Map main frame
MapWindow();
// create a timer firing every 100 ms
fTimer = new TTimer(this, 500);
}
MyMainFrame::~MyMainFrame() {
// Clean up used widgets: frames, buttons, layout hints
Cleanup();
}
/**
Just tells the canvas to refresh
whenever the timer fires
*/
Bool_t MyMainFrame::HandleTimer(TTimer *)
{
// timer handling.
TCanvas *fCanvas = m_fEcanvas->GetCanvas();
fCanvas->cd();
fCanvas->Update();
fCanvas->Modified();
fCanvas->Update();
fTimer->Reset();
return kTRUE;
}
void MyMainFrame::DoStart() {
TString nm = m_fTextEntry->GetBuffer()->GetString();
/*
if( nm == "" )
m_daq->m_fout_name = (TString)"output.root";
*/
if( nm == "" ){
//counter file
TFile file("../_counter_DO_NOT_REMOVE.root","UPDATE","counter");
TTree *tree = (TTree*)file.Get("counter");
if (tree == NULL) {
std::cerr<<"NO TREE EXIST"<<std::endl;
TTree *tree = new TTree("counter","tree title");
Float_t count;
tree->Branch("count",&count,"count/F");
count = 414; //first run of this testbeam is Run 414
tree->Fill();
tree->Write();
delete tree;
}
else {
Float_t count;
tree->SetBranchAddress("count", &count);
int nEntries = tree->GetEntries();
tree->GetEntry(nEntries-1);
count++;
delete tree;
file.Close();
TFile file("../_counter_DO_NOT_REMOVE.root","RECREATE","counter");
TTree *tree = new TTree("counter","tree title");
tree->Branch("count",&count,"px/F");
tree->Fill();
tree->Write();
delete tree;
}
file.Close();
m_daq->m_fout_name = (TString)Form("run_%08d-0000.root", (int)count);
}
else{
m_daq->m_fout_name = (TString)Form("%s.root", nm.Data() );
}
fTimer->Reset();
fTimer->TurnOn();
m_daq->m_start_flag = true;
}
void MyMainFrame::DoStop() {
m_daq->m_stop_flag = true;
fTimer->TurnOff();
gApplication->Terminate(0);
}
/**
* @file Phillips2249W.cpp
* Implementation for Phillips2249W class
*
* @brief
*
* @author Yakov Kulinich
* @version 1.0
*/
#include "Phillips2249W.h"
#include "SharedData.h"
#include <stdio.h>
#include <TTree.h>
#include <TFile.h>
#include <TH1.h>
#include <TSystem.h>
#include <TCanvas.h>
#include <iostream>
//--------------------------------
// Phillips2249W
//--------------------------------
Phillips2249W :: Phillips2249W ( std::string moduleName, int nChannels, int slotNumber ) :
GenericModule( moduleName, nChannels, slotNumber, 0, 4095 ){
m_tdcsum = 0;
m_h_tdcsum = NULL;
}
Phillips2249W :: ~Phillips2249W () {}
/**
Add output for this Phillips2249W. This means adding branches
to the tree and creating histograms.
Phillips TDC data represents a 12 bit TDC so data go from
0 to 4095 channels.
*/
void Phillips2249W :: AddOutput(){
char name [128];
// same thing we would do here
GenericModule::AddOutput();
// This is the "TDC SUM"
// we need some additional output
/*
sprintf( name, "h_%s_%d_SUM", m_moduleName.c_str(), m_slotNumber );
m_h_tdcsum = new TH1F( name, name, m_nDigitsData + 10 , 0, m_nDigitsData + 10 );
m_sd->GetHists()[ name ] = m_h_tdcsum;
sprintf( name, "%s_%d_SUM", m_moduleName.c_str(), m_slotNumber );
m_sd->GetTree()->Branch( name, &m_tdcsum );
*/
}
/**
Phillips TDC data is 16 bit.
First Front 4 bits (highest bits) are channel number
Lowests 12 bits are data.
Also find a non 0 or 4095 value (if it exists)
*/
void Phillips2249W :: ReadData( short* p ){
int ch, tdcdata;
short data;
m_tdcsum = 0;
for( int i = 0; i < m_nChannels; i++ ){
data = *(p + i);
tdcdata = (data & 0x000FFF);
ch = (data & 0x00F000)>>12;
m_dataBank[ch] = tdcdata;
// get a useful tdc value
if( tdcdata < m_nDigitsData && !m_tdcsum )
m_tdcsum = tdcdata;
}
}
/**
Fill the TDC histograms for each channel.
Since it is a Phillips TDC, we have an additional histogram
of the TDC sum we need to to override the function.
These histograms are for monitoring, so if the value
is 0 or m_nDigitsData we dont fill (so we only see useful info).
One can then compare total number of events to number of entries
in the histogram to see how well the module is working.
*/
void Phillips2249W :: FillHistograms(){
GenericModule::FillHistograms();
// This is the "TDC SUM"
if( m_tdcsum ) m_h_tdcsum->Fill( m_tdcsum );
}
/**
* @file SharedData.cpp
* Implementation for SharedData class
*
* @brief
*
* @author Yakov Kulinich
* @version 1.0
*/
#include "SharedData.h"
#include <stdio.h>
#include <TTree.h>
#include <TFile.h>
#include <TH1.h>
#include <TSystem.h>
#include <TCanvas.h>
#include <iostream>
//--------------------------------
// SharedData
//--------------------------------
SharedData :: SharedData() {
m_fout = NULL;
m_tree = new TTree("tree","Muon Tree");
m_tree->SetAutoSave(1000000);
}
SharedData :: ~SharedData() {
delete m_tree;
delete m_fout;
}
void SharedData :: Finalize() {
m_tree->Write();
for( auto& psh1 : m_m_hists ) psh1.second->Write();
m_fout->Close();
}
README 0 → 100755
README FOR MUON LAB USING CC-USB CRATE CONTROLLER
WRITTEN BY YAKOV KULINICH SPRING 2016
------------------------------------------------------
------------------------------------------------------
Simple Installation Instructions
1) First, you need root loaded on this machine, type
module load root/6.02.08
Note: root might be upgraded and versions change
Best bet is to type
module load root/6[TAB]
Do not type [TAB] but instead autocomplete root/6*.**.**
2) install
source setup.sh
3) load environment variable XXUSBDIR
echo env.sh (from run directory)
4) Run directory is in MyDaq/run
cd MyDaq/run
------------------------------------------------------
------------------------------------------------------
General Installation Instructions
For users with Linux Experience
1) Copy xxusb_3.22 to some local directory
I.E. ~/soft
(You can put this anywhere, but for the sake of the instructions
I will continue assuming this directory.)
2) Go to ~/soft/xxusb_3.22/src
make
make install
Now, xxusb libraries are installed. Next, you need to add
xxusb and it's libraries to your environment variables.
3) Using favorite editor, open ~/.bashrc
4) At bottom, add (USERNAME is your username)
export XXUSBDIR=/home/USERNAME/soft/xxusb_3.22
Again, if you put the xxusb_3.22 somewhere else, change the path
appropriately.
5) Close terminal and open new one.
(Alternitavely, run source ~/.bashrc)
6) Load root every time you have a new terminal
module load root/6.02.08
7) Take MyDaq (from the tar package) and copy it to directory of choice
Inside DIRECTORY_OF_CHOICE/MyDaq
make
8) ./runMyDaq
A GUI will pop up. There is a text entry field.
You can enter a name for your run (i.e. run_04_18_15)
Otherwise, default name (output) will be used.
Note: .root will be appended to the run name.
So, in above examples, the outputs will be
run_04_18_15.root or output.root
Click Start.
Do not exit using X at top. Finish with Stop first.
Enjoy!
------------------------------------------------------
------------------------------------------------------
TROUBLESHOOTING
1) If you get
Finding XX_USB devices and opening first one found
Found XX_USB device
Segmentation fault
You need to turn on and off the CAMAC crate.
2) If you get
Finding XX_USB devices and opening first one found
Device not xxusb
... Followed by a Seg Fault
There is something wrong with the permissions to
access the usb.
This can be solved by going as some super user
and typing
udevadm control --reload-rules
udevadm trigger
Alternatively, contact IT support and explain to them
the USB udev rules are incorrect somehow.
3) If above does not work, might need to update udev rules.
Add following lines into
/etc/udev/rules.d
/lib/udev/rules.d
SUBSYSTEM=="usb", ATTR{idVendor}=="16dc", MODE=="0666"
4) If during setup you get something about usb.h not found. You probably dont have libusb-devel
sudo yum install libusb*
setup.sh 0 → 100755
#!/bin/bash
MUONLABDIR=`pwd`
printf "\nMUONLABDIR = " $MUONLABDIR
MYDAQ='MyDaq'
XXUSB='xxusb_3.22'
MYDAQDIR=$MUONLABDIR/$MYDAQ
printf "\nMYDAQDIR = " $MYDAQDIR
export XXUSBDIR=$MUONLABDIR/$XXUSB
printf "\nXXUSBDIR = " $XXUSBDIR
printf "\n\nInstalling XXUSB\n\n"
cd $XXUSBDIR/src
make -j4
printf "\n\nInstalling MyDaq\n\n"
cd $MYDAQDIR
make -j4
printf "\nDone\n"
\ No newline at end of file
File added
File added
File added
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment