SPS_SABRE_EventBuilder/src/evb/CompassFile.cpp

200 lines
5.1 KiB
C++

/*
CompassFile.cpp
Wrapper class around a shared pointer to an ifstream. Here the shared pointer is used
to overcome limitations of the ifstream class, namely that it is written such that ifstream
cannot be modified by move semantics. Contains all information needed to parse a single binary
CompassFile. Currently has a class wide defined buffer size; may want to make this user input
in the future.
Written by G.W. McCann Oct. 2020
*/
#include "EventBuilder.h"
#include "CompassFile.h"
namespace EventBuilder {
CompassFile::CompassFile() :
m_filename(""), m_bufferIter(nullptr), m_bufferEnd(nullptr), m_smap(nullptr), m_hitUsedFlag(true), m_hitsize(0), m_buffersize(0),
m_file(std::make_shared<std::ifstream>()), m_eofFlag(false)
{
}
CompassFile::CompassFile(const std::string& filename) :
m_filename(""), m_bufferIter(nullptr), m_bufferEnd(nullptr), m_smap(nullptr), m_hitUsedFlag(true), m_hitsize(0), m_buffersize(0),
m_file(std::make_shared<std::ifstream>()), m_eofFlag(false)
{
Open(filename);
}
CompassFile::CompassFile(const std::string& filename, int bsize) :
m_filename(""), m_bufferIter(nullptr), m_bufferEnd(nullptr), m_smap(nullptr), m_hitUsedFlag(true), m_bufsize(bsize), m_hitsize(0),
m_buffersize(0), m_file(std::make_shared<std::ifstream>()), m_eofFlag(false)
{
Open(filename);
}
CompassFile::~CompassFile()
{
Close();
}
void CompassFile::Open(const std::string& filename)
{
m_eofFlag = false;
m_hitUsedFlag = true;
m_filename = filename;
m_file->open(m_filename, std::ios::binary | std::ios::in);
m_file->seekg(0, std::ios_base::end);
m_size = m_file->tellg();
if(m_size == 0)
{
m_eofFlag = true;
}
else
{
m_file->seekg(0, std::ios_base::beg);
ReadHeader();
m_nHits = m_size/m_hitsize;
m_buffersize = m_hitsize*m_bufsize;
m_hitBuffer.resize(m_buffersize);
}
}
void CompassFile::Close()
{
if(IsOpen())
{
m_file->close();
}
}
void CompassFile::ReadHeader()
{
if(!IsOpen())
{
EVB_WARN("Unable to read header from file. State not validated", m_filename);
return;
}
char* header = new char[2];
m_file->read(header, 2);
m_header = *((uint16_t*)header);
m_hitsize = 16; //default hitsize of 16 bytes
if(IsEnergy())
m_hitsize += 2;
if(IsEnergyCalibrated())
m_hitsize += 8;
if(IsEnergyShort())
m_hitsize += 2;
if(IsWaves())
{
EVB_ERROR("Waveforms are not supported by the SPS_SABRE_EventBuilder. The wave data will be skipped.");
m_hitsize += 5;
char* firstHit = new char[m_hitsize]; //A compass hit by default has 24 bytes (at least in our setup)
m_file->read(firstHit, 24);
firstHit += m_hitsize - 4;
uint32_t nsamples = *((uint32_t*) firstHit);
m_hitsize += nsamples * 2; //Each sample is a 2 byte data value
m_file->seekg(0, std::ios_base::beg);
m_file->read(header, 2);
delete[] firstHit;
}
delete[] header;
}
/*
GetNextHit() is the function which... gets the next hit
Has to check if the buffer needs refilled/filled for the first time
Upon pulling a hit, sets the UsedFlag to false, letting the next level know
that the hit should be free game.
If the file cannot be opened, signals as though file is EOF
*/
bool CompassFile::GetNextHit()
{
if(!IsOpen()) return true;
if((m_bufferIter == nullptr || m_bufferIter == m_bufferEnd) && !IsEOF())
{
GetNextBuffer();
}
if(!IsEOF())
{
ParseNextHit();
m_hitUsedFlag = false;
}
return m_eofFlag;
}
/*
GetNextBuffer() ... self-explanatory name
Note tht this is where the EOF flag is set. The EOF is only singaled
after the LAST buffer is completely read (i.e literally no more data). ifstream sets its eof
bit upon pulling the last buffer, but this class waits until that entire
last buffer is read to singal EOF (the true end of file).
*/
void CompassFile::GetNextBuffer()
{
if(m_file->eof())
{
m_eofFlag = true;
return;
}
m_file->read(m_hitBuffer.data(), m_hitBuffer.size());
m_bufferIter = m_hitBuffer.data();
m_bufferEnd = m_bufferIter + m_file->gcount(); //one past the last datum
}
void CompassFile::ParseNextHit()
{
m_currentHit.board = *((uint16_t*)m_bufferIter);
m_bufferIter += 2;
m_currentHit.channel = *((uint16_t*)m_bufferIter);
m_bufferIter += 2;
m_currentHit.timestamp = *((uint64_t*)m_bufferIter);
m_bufferIter += 8;
if(IsEnergy())
{
m_currentHit.energy = *((uint16_t*)m_bufferIter);
m_bufferIter += 2;
}
if(IsEnergyCalibrated())
{
m_currentHit.energyCalibrated = *((uint64_t*)m_bufferIter);
m_bufferIter += 8;
}
if(IsEnergyShort())
{
m_currentHit.energyShort = *((uint16_t*)m_bufferIter);
m_bufferIter += 2;
}
m_currentHit.flags = *((uint32_t*)m_bufferIter);
m_bufferIter += 4;
if(IsWaves())
{
m_currentHit.waveCode = *((uint8_t*)m_bufferIter);
m_bufferIter += 1;
m_currentHit.Ns = *((uint32_t*)m_bufferIter);
m_bufferIter += 4;
m_bufferIter += 2*m_currentHit.Ns;
//Skip wavedata for SPS_SABRE_EventBuilder
}
if(m_smap != nullptr)
{ //memory safety
int gchan = m_currentHit.channel + m_currentHit.board*16;
m_currentHit.timestamp += m_smap->GetShift(gchan);
}
}
}