1
0
Fork 0
mirror of https://github.com/gwm17/Specter.git synced 2024-11-26 20:28:49 -05:00

Compare commits

..

2 Commits

28 changed files with 813 additions and 134 deletions

View File

@ -75,6 +75,15 @@ target_sources(Specter PRIVATE
Specter/Physics/Caen/CompassOnlineSource.h Specter/Physics/Caen/CompassOnlineSource.h
Specter/Physics/Caen/CompassRun.cpp Specter/Physics/Caen/CompassRun.cpp
Specter/Physics/Caen/CompassRun.h Specter/Physics/Caen/CompassRun.h
Specter/Physics/nscldaq/CharonOnlineSource.h
Specter/Physics/nscldaq/CharonOnlineSource.cpp
Specter/Physics/nscldaq/CharonClient.h
Specter/Physics/nscldaq/CharonClient.cpp
Specter/Physics/nscldaq/Unpackers/Unpacker.h
Specter/Physics/nscldaq/Unpackers/CaenUnpacker.h
Specter/Physics/nscldaq/Unpackers/CaenUnpacker.cpp
Specter/Physics/nscldaq/Unpackers/MesyTecUnpacker.h
Specter/Physics/nscldaq/Unpackers/MesyTecUnpacker.cpp
Specter/Editor/EditorLayer.cpp Specter/Editor/EditorLayer.cpp
Specter/Editor/EditorLayer.h Specter/Editor/EditorLayer.h
Specter/Editor/FileDialog.cpp Specter/Editor/FileDialog.cpp
@ -106,6 +115,7 @@ target_sources(Specter PRIVATE
Specter/Utils/Functions.h Specter/Utils/Functions.h
Specter/Utils/Functions.cpp Specter/Utils/Functions.cpp
Specter/Utils/RandomGenerator.h Specter/Utils/RandomGenerator.h
Specter/Utils/ThreadSafeQueue.h
) )
#ImPlot sources #ImPlot sources

View File

@ -32,7 +32,7 @@ namespace Specter {
static bool onlineFlag = false; static bool onlineFlag = false;
static bool offlineFlag = false; static bool offlineFlag = false;
static std::vector<DataSource::SourceType> availTypes = { DataSource::SourceType::CompassOnline, DataSource::SourceType::CompassOffline, DataSource::SourceType::DaqromancyOnline, static std::vector<DataSource::SourceType> availTypes = { DataSource::SourceType::CompassOnline, DataSource::SourceType::CompassOffline, DataSource::SourceType::DaqromancyOnline,
DataSource::SourceType::DaqromancyOffline }; DataSource::SourceType::DaqromancyOffline, DataSource::SourceType::CharonOnline };
if (m_openFlag) if (m_openFlag)
{ {
@ -78,6 +78,7 @@ namespace Specter {
{ {
m_bitflags = m_bitflags ^ CompassHeaders::EnergyCalibrated; m_bitflags = m_bitflags ^ CompassHeaders::EnergyCalibrated;
} }
ImGui::InputInt("Coinc. Window (ps)", &m_chosenWindow);
} }
else if (m_chosenType == DataSource::SourceType::CompassOffline) else if (m_chosenType == DataSource::SourceType::CompassOffline)
{ {
@ -90,11 +91,13 @@ namespace Specter {
auto temp = m_fileDialog.RenderFileDialog(); auto temp = m_fileDialog.RenderFileDialog();
if (!temp.first.empty() && temp.second == FileDialog::Type::OpenDir) if (!temp.first.empty() && temp.second == FileDialog::Type::OpenDir)
m_chosenLocation = temp.first; m_chosenLocation = temp.first;
ImGui::InputInt("Coinc. Window (ps)", &m_chosenWindow);
} }
else if (m_chosenType == DataSource::SourceType::DaqromancyOnline) else if (m_chosenType == DataSource::SourceType::DaqromancyOnline)
{ {
ImGui::InputText("Hostname", &m_chosenLocation); ImGui::InputText("Hostname", &m_chosenLocation);
ImGui::InputText("Port", &m_chosenPort); ImGui::InputText("Port", &m_chosenPort);
ImGui::InputInt("Coinc. Window (ps)", &m_chosenWindow);
} }
else if (m_chosenType == DataSource::SourceType::DaqromancyOffline) else if (m_chosenType == DataSource::SourceType::DaqromancyOffline)
{ {
@ -107,22 +110,19 @@ namespace Specter {
auto temp = m_fileDialog.RenderFileDialog(); auto temp = m_fileDialog.RenderFileDialog();
if (!temp.first.empty() && temp.second == FileDialog::Type::OpenDir) if (!temp.first.empty() && temp.second == FileDialog::Type::OpenDir)
m_chosenLocation = temp.first; m_chosenLocation = temp.first;
}
ImGui::InputInt("Coinc. Window (ps)", &m_chosenWindow); ImGui::InputInt("Coinc. Window (ps)", &m_chosenWindow);
}
else if (m_chosenType == DataSource::SourceType::CharonOnline)
{
ImGui::InputText("Hostname", &m_chosenLocation);
ImGui::InputText("Port", &m_chosenPort);
}
if (ImGui::Button("Ok")) if (ImGui::Button("Ok"))
{ {
if (m_chosenType == DataSource::SourceType::CompassOffline || m_chosenType == DataSource::SourceType::DaqromancyOffline) PhysicsStartEvent event(m_chosenLocation, m_chosenType, m_chosenWindow, m_chosenPort, m_bitflags);
{
PhysicsStartEvent event(m_chosenLocation, m_chosenType, m_chosenWindow, m_chosenPort, false, 0U);
Application::Get().OnEvent(event); Application::Get().OnEvent(event);
}
else if (m_chosenType == DataSource::SourceType::CompassOnline || m_chosenType == DataSource::SourceType::DaqromancyOnline)
{
PhysicsStartEvent event(m_chosenLocation, m_chosenType, m_chosenWindow, m_chosenPort, true, m_bitflags);
Application::Get().OnEvent(event);
}
ImGui::CloseCurrentPopup(); ImGui::CloseCurrentPopup();
} }
ImGui::SameLine(); ImGui::SameLine();

View File

@ -21,15 +21,14 @@ namespace Specter {
{ {
public: public:
//Bitflags is a final option for random crap needed for a source. Currently used for compass online to indicate header state. //Bitflags is a final option for random crap needed for a source. Currently used for compass online to indicate header state.
PhysicsStartEvent(const std::string& loc, DataSource::SourceType type, uint64_t window, const std::string& port = "51489", bool sortFlag=false, uint16_t bitflags = 0) : PhysicsStartEvent(const std::string& loc, DataSource::SourceType type, uint64_t window, const std::string& port = "51489", uint16_t bitflags = 0) :
m_sourceLocation(loc), m_port(port), m_sourceType(type), m_coincidenceWindow(window), m_sortFlag(sortFlag), m_bitflags(bitflags) m_sourceLocation(loc), m_port(port), m_sourceType(type), m_coincidenceWindow(window), m_bitflags(bitflags)
{} {}
inline const std::string GetSourceLocation() const { return m_sourceLocation; } inline const std::string GetSourceLocation() const { return m_sourceLocation; }
inline const std::string GetSourcePort() const { return m_port; } inline const std::string GetSourcePort() const { return m_port; }
inline const DataSource::SourceType GetSourceType() const { return m_sourceType; } inline const DataSource::SourceType GetSourceType() const { return m_sourceType; }
inline const uint64_t GetCoincidenceWindow() const { return m_coincidenceWindow; } inline const uint64_t GetCoincidenceWindow() const { return m_coincidenceWindow; }
inline const bool GetSortFlag() const { return m_sortFlag; }
inline const uint16_t GetBitFlags() const { return m_bitflags; } inline const uint16_t GetBitFlags() const { return m_bitflags; }
std::string ToString() const override std::string ToString() const override
@ -45,7 +44,6 @@ namespace Specter {
std::string m_port; std::string m_port;
DataSource::SourceType m_sourceType; DataSource::SourceType m_sourceType;
uint64_t m_coincidenceWindow; uint64_t m_coincidenceWindow;
bool m_sortFlag;
uint16_t m_bitflags; uint16_t m_bitflags;
}; };

View File

@ -126,7 +126,7 @@ namespace Specter {
void ImGuiLayer::OnImGuiRender() void ImGuiLayer::OnImGuiRender()
{ {
//Demo's used to figure out how to do things. //Demo's used to figure out how to do things.
//Should not be on for actual NavProject for //Should not be on for actual SpecProject for
//real use //real use
//static bool show = true; //static bool show = true;
//ImGui::ShowDemoWindow(&show); //ImGui::ShowDemoWindow(&show);

View File

@ -22,9 +22,10 @@
namespace Specter { namespace Specter {
CompassOnlineSource::CompassOnlineSource(const std::string& hostname, const std::string& port, uint16_t header) : CompassOnlineSource::CompassOnlineSource(const std::string& hostname, const std::string& port, uint16_t header, uint64_t coincidenceWindow) :
DataSource(), m_bufferIter(nullptr), m_bufferEnd(nullptr), m_header(header) DataSource(coincidenceWindow), m_bufferIter(nullptr), m_bufferEnd(nullptr), m_header(header)
{ {
m_eventBuilder.SetSortFlag(true);
InitConnection(hostname, port); InitConnection(hostname, port);
} }
@ -52,15 +53,14 @@ namespace Specter {
} }
} }
const SpecData& CompassOnlineSource::GetData() void CompassOnlineSource::ProcessData()
{ {
SPEC_PROFILE_FUNCTION(); SPEC_PROFILE_FUNCTION();
size_t range = m_bufferEnd - m_bufferIter; //how much buffer we have left size_t range = m_bufferEnd - m_bufferIter; //how much buffer we have left
if (!IsValid()) if (!IsValid())
{ {
SPEC_ERROR("Attempting to access invalid source at CompassOnlineSource!"); SPEC_ERROR("Attempting to access invalid source at CompassOnlineSource!");
m_datum = SpecData(); return;
return m_datum;
} }
else if (m_bufferIter == nullptr || range < m_datasize || m_bufferIter == m_bufferEnd) //If no buffer/buffer completely used/buffer fragmented fill else if (m_bufferIter == nullptr || range < m_datasize || m_bufferIter == m_bufferEnd) //If no buffer/buffer completely used/buffer fragmented fill
{ {
@ -71,8 +71,7 @@ namespace Specter {
GetHit(); GetHit();
else else
{ {
m_datum = SpecData(); return;
return m_datum;
} }
m_datum.longEnergy = m_currentHit.energy; m_datum.longEnergy = m_currentHit.energy;
@ -81,7 +80,10 @@ namespace Specter {
m_datum.timestamp = m_currentHit.timestamp; m_datum.timestamp = m_currentHit.timestamp;
m_datum.id = Utilities::GetBoardChannelUUID(m_currentHit.board, m_currentHit.channel); m_datum.id = Utilities::GetBoardChannelUUID(m_currentHit.board, m_currentHit.channel);
return m_datum; if(m_eventBuilder.AddDatum(m_datum))
{
m_isEventReady = true;
}
} }
void CompassOnlineSource::FillBuffer() void CompassOnlineSource::FillBuffer()

View File

@ -36,10 +36,15 @@ namespace Specter {
class CompassOnlineSource : public DataSource class CompassOnlineSource : public DataSource
{ {
public: public:
CompassOnlineSource(const std::string& hostname, const std::string& port, uint16_t header); CompassOnlineSource(const std::string& hostname, const std::string& port, uint16_t header, uint64_t coincidenceWindow);
virtual ~CompassOnlineSource() override; virtual ~CompassOnlineSource() override;
virtual const SpecData& GetData() override; virtual void ProcessData() override;
virtual const std::vector<SpecEvent>& GetEvents() override
{
m_isEventReady = false;
return m_eventBuilder.GetReadyEvents();
}
private: private:
void InitConnection(const std::string& hostname, const std::string& port); void InitConnection(const std::string& hostname, const std::string& port);

View File

@ -26,13 +26,8 @@
namespace Specter { namespace Specter {
CompassRun::CompassRun() : CompassRun::CompassRun(const std::string& dir, uint64_t coincidenceWindow) :
DataSource(), m_directory(""), m_startIndex(0) DataSource(coincidenceWindow), m_directory(dir), m_startIndex(0)
{
}
CompassRun::CompassRun(const std::string& dir) :
DataSource(), m_directory(dir), m_startIndex(0)
{ {
CollectFiles(); CollectFiles();
} }
@ -129,32 +124,32 @@ namespace Specter {
return true; return true;
} }
const SpecData& CompassRun::GetData() void CompassRun::ProcessData()
{ {
SPEC_PROFILE_FUNCTION(); SPEC_PROFILE_FUNCTION();
if(!IsValid()) if(!IsValid())
{ {
SPEC_ERROR("Trying to access CompassRun data when invalid, bug detected!"); SPEC_ERROR("Trying to access CompassRun data when invalid, bug detected!");
m_datum = SpecData(); return;
return m_datum;
} }
if (!GetHitsFromFiles()) if (!GetHitsFromFiles())
{ {
m_validFlag = false; m_validFlag = false;
m_datum = SpecData(); return;
} }
else
{
//Convert data from CoMPASS format to universal Specter format. //Convert data from CoMPASS format to universal Specter format.
m_datum.longEnergy = m_hit.energy; m_datum.longEnergy = m_hit.energy;
m_datum.shortEnergy = m_hit.energyShort; m_datum.shortEnergy = m_hit.energyShort;
m_datum.calEnergy = m_hit.energyCalibrated; m_datum.calEnergy = m_hit.energyCalibrated;
m_datum.timestamp = m_hit.timestamp; m_datum.timestamp = m_hit.timestamp;
m_datum.id = Utilities::GetBoardChannelUUID(m_hit.board, m_hit.channel); m_datum.id = Utilities::GetBoardChannelUUID(m_hit.board, m_hit.channel);
}
return m_datum; if(m_eventBuilder.AddDatum(m_datum))
{
m_isEventReady = true;
}
} }
} }

View File

@ -33,12 +33,15 @@ namespace Specter {
class CompassRun : public DataSource class CompassRun : public DataSource
{ {
public: public:
CompassRun(); CompassRun(const std::string& dir, uint64_t coincidenceWindow);
CompassRun(const std::string& dir);
virtual ~CompassRun(); virtual ~CompassRun();
virtual const SpecData& GetData() override; virtual void ProcessData() override;
virtual const std::vector<SpecEvent>& GetEvents() override
{
m_isEventReady = false;
return m_eventBuilder.GetReadyEvents();
}
inline void SetDirectory(const std::string& dir) { m_directory = dir; CollectFiles(); } inline void SetDirectory(const std::string& dir) { m_directory = dir; CollectFiles(); }
inline void SetShiftMap(const std::string& filename) { m_smap.SetFile(filename); } inline void SetShiftMap(const std::string& filename) { m_smap.SetFile(filename); }
@ -58,6 +61,7 @@ namespace Specter {
CompassHit m_hit; CompassHit m_hit;
unsigned int m_totalHits; unsigned int m_totalHits;
}; };
} }

View File

@ -2,8 +2,8 @@
namespace Specter { namespace Specter {
DYFileSource::DYFileSource(const std::string& directory) : DYFileSource::DYFileSource(const std::string& directory, uint64_t coicidenceWindow) :
DataSource(), m_directory(directory) DataSource(coicidenceWindow), m_directory(directory)
{ {
CollectFiles(); CollectFiles();
} }
@ -88,28 +88,26 @@ namespace Specter {
return true; return true;
} }
const SpecData& DYFileSource::GetData() void DYFileSource::ProcessData()
{ {
if (!IsValid()) if (!IsValid())
{ {
SPEC_ERROR("Trying to access DYFileSource data when invalid, bug detected!"); SPEC_ERROR("Trying to access DYFileSource data when invalid, bug detected!");
m_datum = SpecData(); return;
return m_datum;
} }
if (!GetNextHit()) if (!GetNextHit())
{ {
m_validFlag = false; m_validFlag = false;
m_datum = SpecData();
} }
else
{
//Convert data from Daqromancy format to universal Specter format. //Convert data from Daqromancy format to universal Specter format.
m_datum.longEnergy = m_dyHit.energy; m_datum.longEnergy = m_dyHit.energy;
m_datum.shortEnergy = m_dyHit.energyShort; m_datum.shortEnergy = m_dyHit.energyShort;
m_datum.timestamp = m_dyHit.timestamp; m_datum.timestamp = m_dyHit.timestamp;
m_datum.id = Utilities::GetBoardChannelUUID(m_dyHit.board, m_dyHit.channel); m_datum.id = Utilities::GetBoardChannelUUID(m_dyHit.board, m_dyHit.channel);
} if(m_eventBuilder.AddDatum(m_datum))
return m_datum; {
m_isEventReady = true;
}
} }
} }

View File

@ -10,10 +10,15 @@ namespace Specter {
class DYFileSource : public DataSource class DYFileSource : public DataSource
{ {
public: public:
DYFileSource(const std::string& directory); DYFileSource(const std::string& directory, uint64_t coincidenceWindow);
virtual ~DYFileSource(); virtual ~DYFileSource();
virtual const SpecData& GetData() override; virtual void ProcessData() override;
virtual const std::vector<SpecEvent>& GetEvents() override
{
m_isEventReady = false;
return m_eventBuilder.GetReadyEvents();
}
private: private:
void CollectFiles(); void CollectFiles();

View File

@ -2,9 +2,10 @@
namespace Specter { namespace Specter {
DYOnlineSource::DYOnlineSource(const std::string& hostname, const std::string& port) : DYOnlineSource::DYOnlineSource(const std::string& hostname, const std::string& port, uint64_t coincidenceWindow) :
DataSource(), m_clientConnection(hostname, port) DataSource(coincidenceWindow), m_clientConnection(hostname, port)
{ {
m_eventBuilder.SetSortFlag(true);
m_validFlag = m_clientConnection.IsConnected(); m_validFlag = m_clientConnection.IsConnected();
} }
@ -12,13 +13,12 @@ namespace Specter {
{ {
} }
const SpecData& DYOnlineSource::GetData() void DYOnlineSource::ProcessData()
{ {
if (!m_clientConnection.IsConnected()) if (!m_clientConnection.IsConnected())
{ {
m_validFlag = false; m_validFlag = false;
m_datum = SpecData(); return;
return m_datum;
} }
if (m_clientConnection.GetNextEvent(m_dyHit)) if (m_clientConnection.GetNextEvent(m_dyHit))
@ -28,12 +28,8 @@ namespace Specter {
m_datum.shortEnergy = m_dyHit.energyShort; m_datum.shortEnergy = m_dyHit.energyShort;
m_datum.timestamp = m_dyHit.timestamp; m_datum.timestamp = m_dyHit.timestamp;
m_datum.id = Utilities::GetBoardChannelUUID(m_dyHit.board, m_dyHit.channel); m_datum.id = Utilities::GetBoardChannelUUID(m_dyHit.board, m_dyHit.channel);
} if(m_eventBuilder.AddDatum(m_datum))
else m_isEventReady = true;
{ }
m_datum = SpecData();
}
return m_datum;
} }
} }

View File

@ -9,15 +9,19 @@ namespace Specter {
class DYOnlineSource : public DataSource class DYOnlineSource : public DataSource
{ {
public: public:
DYOnlineSource(const std::string& hostname, const std::string& port); DYOnlineSource(const std::string& hostname, const std::string& port, uint64_t coincidenceWindow);
~DYOnlineSource(); virtual ~DYOnlineSource();
virtual const SpecData& GetData() override; virtual void ProcessData() override;
virtual const std::vector<SpecEvent>& GetEvents() override
{
m_isEventReady = false;
return m_eventBuilder.GetReadyEvents();
}
private: private:
DaqGrimoire::DYClient m_clientConnection; DaqGrimoire::DYClient m_clientConnection;
DaqGrimoire::DYListData m_dyHit; DaqGrimoire::DYListData m_dyHit;
int m_channelsPerBoard;
}; };
} }

View File

@ -11,18 +11,20 @@
#include "Caen/CompassOnlineSource.h" #include "Caen/CompassOnlineSource.h"
#include "Daqromancy/DYFileSource.h" #include "Daqromancy/DYFileSource.h"
#include "Daqromancy/DYOnlineSource.h" #include "Daqromancy/DYOnlineSource.h"
#include "nscldaq/CharonOnlineSource.h"
namespace Specter { namespace Specter {
//loc=either an ip address or a file location, port=address port, or unused in case of file //loc=either an ip address or a file location, port=address port, or unused in case of file
DataSource* CreateDataSource(const std::string& location, const std::string& port, uint16_t header, DataSource::SourceType type) DataSource* CreateDataSource(const std::string& location, const std::string& port, uint16_t header, DataSource::SourceType type, uint64_t coincidenceWindow)
{ {
switch(type) switch(type)
{ {
case DataSource::SourceType::CompassOffline : return new CompassRun(location); case DataSource::SourceType::CompassOffline: return new CompassRun(location, coincidenceWindow);
case DataSource::SourceType::CompassOnline : return new CompassOnlineSource(location, port, header); case DataSource::SourceType::CompassOnline: return new CompassOnlineSource(location, port, header, coincidenceWindow);
case DataSource::SourceType::DaqromancyOffline: return new DYFileSource(location); case DataSource::SourceType::DaqromancyOffline: return new DYFileSource(location, coincidenceWindow);
case DataSource::SourceType::DaqromancyOnline: return new DYOnlineSource(location, port); case DataSource::SourceType::DaqromancyOnline: return new DYOnlineSource(location, port, coincidenceWindow);
case DataSource::SourceType::CharonOnline: return new CharonOnlineSource(location, port);
case DataSource::SourceType::None: return nullptr; case DataSource::SourceType::None: return nullptr;
} }
SPEC_WARN("Invalid DataSourceType at CreateDataSource!"); SPEC_WARN("Invalid DataSourceType at CreateDataSource!");
@ -38,6 +40,7 @@ namespace Specter {
case DataSource::SourceType::CompassOffline: return "CompassOffline"; case DataSource::SourceType::CompassOffline: return "CompassOffline";
case DataSource::SourceType::DaqromancyOffline: return "DaqromancyOffline"; case DataSource::SourceType::DaqromancyOffline: return "DaqromancyOffline";
case DataSource::SourceType::DaqromancyOnline: return "DaqromancyOnline"; case DataSource::SourceType::DaqromancyOnline: return "DaqromancyOnline";
case DataSource::SourceType::CharonOnline: return "CharonOnline";
} }
return "None"; return "None";

View File

@ -10,6 +10,7 @@
#define DATA_SOURCE_H #define DATA_SOURCE_H
#include "Specter/Core/SpecCore.h" #include "Specter/Core/SpecCore.h"
#include "Specter/Physics/PhysicsEventBuilder.h"
#include "SpecData.h" #include "SpecData.h"
namespace Specter { namespace Specter {
@ -23,24 +24,29 @@ namespace Specter {
CompassOnline, CompassOnline,
CompassOffline, CompassOffline,
DaqromancyOnline, DaqromancyOnline,
DaqromancyOffline DaqromancyOffline,
CharonOnline
}; };
DataSource() : DataSource(uint64_t coincidenceWindow = 0) :
m_validFlag(false) m_validFlag(false), m_isEventReady(false), m_eventBuilder(coincidenceWindow)
{ {
} }
virtual ~DataSource() {}; virtual ~DataSource() {};
virtual const SpecData& GetData() = 0; virtual void ProcessData() = 0;
virtual const std::vector<SpecEvent>& GetEvents() = 0;
inline bool IsValid() { return m_validFlag; } inline bool IsValid() { return m_validFlag; }
inline bool IsEventReady() { return m_isEventReady; }
protected: protected:
bool m_validFlag; bool m_validFlag;
bool m_isEventReady;
SpecData m_datum; SpecData m_datum;
PhysicsEventBuilder m_eventBuilder;
}; };
DataSource* CreateDataSource(const std::string& location, const std::string& port, uint16_t bitflags, DataSource::SourceType type); DataSource* CreateDataSource(const std::string& location, const std::string& port, uint16_t bitflags, DataSource::SourceType type, uint64_t coincidenceWindow);
std::string ConvertDataSourceTypeToString(DataSource::SourceType type); std::string ConvertDataSourceTypeToString(DataSource::SourceType type);
} }

View File

@ -12,6 +12,11 @@
namespace Specter { namespace Specter {
PhysicsEventBuilder::PhysicsEventBuilder() :
m_sortFlag(false), m_coincWindow(0), m_bufferIndex(0)
{
}
PhysicsEventBuilder::PhysicsEventBuilder(uint64_t windowSize) : PhysicsEventBuilder::PhysicsEventBuilder(uint64_t windowSize) :
m_sortFlag(false), m_coincWindow(windowSize), m_bufferIndex(0) m_sortFlag(false), m_coincWindow(windowSize), m_bufferIndex(0)
{ {

View File

@ -18,6 +18,7 @@ namespace Specter {
class PhysicsEventBuilder class PhysicsEventBuilder
{ {
public: public:
PhysicsEventBuilder();
PhysicsEventBuilder(uint64_t windowSize); PhysicsEventBuilder(uint64_t windowSize);
~PhysicsEventBuilder(); ~PhysicsEventBuilder();
inline void SetCoincidenceWindow(uint64_t windowSize) { m_coincWindow = windowSize; } inline void SetCoincidenceWindow(uint64_t windowSize) { m_coincWindow = windowSize; }

View File

@ -13,7 +13,7 @@
namespace Specter { namespace Specter {
PhysicsLayer::PhysicsLayer(const SpectrumManager::Ref& manager) : PhysicsLayer::PhysicsLayer(const SpectrumManager::Ref& manager) :
m_manager(manager), m_activeFlag(false), m_source(nullptr), m_eventBuilder(0), m_physThread(nullptr) m_manager(manager), m_activeFlag(false), m_source(nullptr), m_physThread(nullptr)
{ {
} }
@ -29,12 +29,6 @@ namespace Specter {
void PhysicsLayer::OnAttach() void PhysicsLayer::OnAttach()
{ {
/* For debugging
NavParameter par("joseph");
par.SetValue(8);
NAV_INFO("Does the par exist? {0}", ParameterMap::GetInstance().IsParameterValid("joseph"));
NAV_INFO("What is its value? {0}", ParameterMap::GetInstance().GetParameterValue("joseph"));
*/
} }
void PhysicsLayer::OnDetach() void PhysicsLayer::OnDetach()
@ -114,10 +108,7 @@ namespace Specter {
{ {
SPEC_PROFILE_FUNCTION(); SPEC_PROFILE_FUNCTION();
std::scoped_lock<std::mutex> guard(m_sourceMutex); //Shouldn't matter for this, but safety first std::scoped_lock<std::mutex> guard(m_sourceMutex); //Shouldn't matter for this, but safety first
m_source.reset(CreateDataSource(event.GetSourceLocation(), event.GetSourcePort(), event.GetBitFlags(), event.GetSourceType())); m_source.reset(CreateDataSource(event.GetSourceLocation(), event.GetSourcePort(), event.GetBitFlags(), event.GetSourceType(), event.GetCoincidenceWindow()));
m_eventBuilder.SetCoincidenceWindow(event.GetCoincidenceWindow());
m_eventBuilder.SetSortFlag(event.GetSortFlag());
m_eventBuilder.ClearAll(); //Protect against stopping mid-event
if (m_source->IsValid()) if (m_source->IsValid())
{ {
SPEC_INFO("Attach successful. Enabling data pull..."); SPEC_INFO("Attach successful. Enabling data pull...");
@ -145,32 +136,24 @@ namespace Specter {
SPEC_PROFILE_FUNCTION(); SPEC_PROFILE_FUNCTION();
std::vector<SpecEvent> events; std::vector<SpecEvent> events;
SpecData datum;
while(m_activeFlag) while(m_activeFlag)
{ {
//Scope to encapsulate access to the data source //Scope to encapsulate access to the data source
{ {
std::scoped_lock<std::mutex> guard(m_sourceMutex); std::scoped_lock<std::mutex> guard(m_sourceMutex);
if (m_source == nullptr || !m_source->IsValid()) if (m_source == nullptr || !m_source->IsValid())
{
return;
}
/*
Looks funny, but two conditions lead to !IsValid(). Either source prev. shutdown,
OR we reached end of source, indicated after prev. data grab
*/
datum = m_source->GetData();
if(!m_source->IsValid())
{ {
SPEC_INFO("End of data source."); SPEC_INFO("End of data source.");
return; return;
} }
m_source->ProcessData();
if(m_source->IsEventReady())
{
events = m_source->GetEvents();
}
} }
//Pass data from source to event builder. True from AddDatum indicates events are ready
if (m_eventBuilder.AddDatum(datum))
{
events = m_eventBuilder.GetReadyEvents();
for (auto& event : events) for (auto& event : events)
{ {
for (auto& stage : m_physStack) for (auto& stage : m_physStack)
@ -181,7 +164,9 @@ namespace Specter {
//Invalidate all parameters to get ready for next event //Invalidate all parameters to get ready for next event
m_manager->InvalidateParameters(); m_manager->InvalidateParameters();
} }
}
if(!events.empty())
events.clear();
} }
} }
} }

View File

@ -16,7 +16,6 @@
#include "AnalysisStack.h" #include "AnalysisStack.h"
#include "AnalysisStage.h" #include "AnalysisStage.h"
#include "DataSource.h" #include "DataSource.h"
#include "PhysicsEventBuilder.h"
#include "Specter/Core/SpectrumManager.h" #include "Specter/Core/SpectrumManager.h"
#include <thread> #include <thread>
@ -55,8 +54,6 @@ namespace Specter {
std::mutex m_sourceMutex; std::mutex m_sourceMutex;
std::unique_ptr<DataSource> m_source; std::unique_ptr<DataSource> m_source;
PhysicsEventBuilder m_eventBuilder;
std::thread* m_physThread; std::thread* m_physThread;
}; };

View File

@ -0,0 +1,96 @@
#include "CharonClient.h"
namespace Specter {
CharonClient::CharonClient(const std::string& hostname, const std::string& port) :
m_socket(m_context)
{
Connect(hostname, port);
}
CharonClient::~CharonClient()
{
Disconnect();
}
bool CharonClient::GetNextEvent(std::vector<uint8_t>& event)
{
if(m_queue.IsEmpty())
return false;
event = m_queue.Front().body;
m_queue.PopFront();
return true;
}
void CharonClient::Connect(const std::string& hostname, const std::string& port)
{
try
{
asio::ip::tcp::resolver resolver(m_context);
auto end_points = resolver.resolve(hostname, port);
asio::async_connect(m_socket, end_points,
[this](std::error_code ec, asio::ip::tcp::endpoint endpoint)
{
if (!ec)
{
ReadHeader();
}
}
);
m_ioThread = std::thread([this]() { m_context.run(); });
SPEC_WARN("Connected CharonClient to {0}:{1}", hostname, port);
}
catch (asio::system_error& e)
{
SPEC_WARN("Unable to connect CharonClient to {0}:{1}", hostname, port);
return;
}
}
void CharonClient::Disconnect()
{
if (IsConnected())
{
asio::post(m_context, [this]() { m_socket.close(); });
}
m_context.stop();
if (m_ioThread.joinable())
m_ioThread.join();
}
void CharonClient::ReadHeader()
{
asio::async_read(m_socket, asio::buffer(&m_tempMessage.size, sizeof(m_tempMessage.size)),
[this](std::error_code ec, std::size_t size)
{
if (!ec)
{
if (m_tempMessage.size > 0)
{
m_tempMessage.body.resize(m_tempMessage.size);
ReadBody();
}
else
ReadHeader();
}
}
);
}
void CharonClient::ReadBody()
{
asio::async_read(m_socket, asio::buffer(m_tempMessage.body.data(), m_tempMessage.body.size()),
[this](std::error_code ec, std::size_t size)
{
if (!ec)
{
m_queue.PushBack(m_tempMessage);
}
ReadHeader();
}
);
}
}

View File

@ -0,0 +1,43 @@
#ifndef CHARON_CLIENT_H
#define CHARON_CLIENT_H
#include "Specter/Utils/ThreadSafeQueue.h"
#include <asio.hpp>
#include <thread>
namespace Specter {
struct StygianMessage
{
uint64_t size;
std::vector<uint8_t> body;
};
class CharonClient
{
public:
CharonClient(const std::string& hostname, const std::string& port);
~CharonClient();
bool GetNextEvent(std::vector<uint8_t>& event);
void Connect(const std::string& hostname, const std::string& port);
void Disconnect();
const bool IsConnected() const { return m_socket.is_open(); }
private:
void ReadHeader();
void ReadBody();
asio::io_context m_context;
asio::ip::tcp::socket m_socket;
std::thread m_ioThread;
StygianMessage m_tempMessage;
ThreadSafeQueue<StygianMessage> m_queue;
};
}
#endif

View File

@ -0,0 +1,67 @@
#include "CharonOnlineSource.h"
#include "Unpackers/CaenUnpacker.h"
#include "Unpackers/MesyTecUnpacker.h"
namespace Specter {
CharonOnlineSource::CharonOnlineSource(const std::string& hostname, const std::string& port) :
DataSource(0), m_client(hostname, port)
{
m_validFlag = m_client.IsConnected();
m_readyEvents.emplace_back();
m_unpackers.push_back(std::make_shared<CaenUnpacker>());
m_unpackers.push_back(std::make_shared<MesyTecUnpacker>());
}
CharonOnlineSource::~CharonOnlineSource()
{
}
void CharonOnlineSource::ProcessData()
{
if(!m_client.IsConnected())
{
m_validFlag = false;
return;
}
if(m_client.GetNextEvent(m_rawBuffer))
{
m_event.clear();
UnpackRawBuffer();
m_isEventReady = true;
}
}
void CharonOnlineSource::UnpackRawBuffer()
{
uint32_t* iter = (uint32_t*) m_rawBuffer.data();
uint32_t* end = iter + m_rawBuffer.size();
bool wasUnpacked = false;
UnpackerResult result;
while(iter < end)
{
wasUnpacked = false;
for(auto& unpacker : m_unpackers)
{
if(unpacker->IsHeader(*iter))
{
result = unpacker->Unpack(iter, end);
iter = result.finalPosition;
wasUnpacked = true;
m_event.insert(m_event.end(), result.data.begin(), result.data.end());
break;
}
}
if(!wasUnpacked)
{
iter++;
}
}
m_readyEvents[0] = m_event;
}
}

View File

@ -0,0 +1,35 @@
#ifndef CHARON_ONLINE_SOURCE
#define CHARON_ONLINE_SOURCE
#include "Specter/Physics/DataSource.h"
#include "CharonClient.h"
#include "Unpackers/Unpacker.h"
namespace Specter {
class CharonOnlineSource : public DataSource
{
public:
CharonOnlineSource(const std::string& hostname, const std::string& port);
virtual ~CharonOnlineSource();
virtual void ProcessData() override;
virtual const std::vector<SpecEvent>& GetEvents() override
{
m_isEventReady = false;
return m_readyEvents;
}
private:
void UnpackRawBuffer();
CharonClient m_client;
std::vector<uint8_t> m_rawBuffer;
SpecEvent m_event;
std::vector<SpecEvent> m_readyEvents;
std::vector<Unpacker::Ref> m_unpackers;
};
}
#endif

View File

@ -0,0 +1,65 @@
#include "CaenUnpacker.h"
#include "Specter/Utils/Functions.h"
namespace Specter {
CaenUnpacker::CaenUnpacker() :
Unpacker()
{
}
CaenUnpacker::~CaenUnpacker() {}
void CaenUnpacker::UnpackHeader(uint32_t* word)
{
if(!IsHeader(*word))
{
SPEC_WARN("In CaenADCUnpacker::UnpackHeader() found non-header word!");
m_bodyWordCount = 0;
m_moduleID = s_illegalModuleID;
return;
}
m_bodyWordCount = (*word & s_headerCountMask) >> s_headerCountShift;
m_moduleID = (*word & s_geoAddressMask) >> s_geoAddressShift;
}
void CaenUnpacker::UnpackEnd(uint32_t* word)
{
if(!IsEnd(*word))
{
SPEC_WARN("In CaenADCUnpacker::UnpackEnd() found non-end word!");
}
//CAEN doesnt really put anything useful here
}
void CaenUnpacker::UnpackDatum(uint32_t* word)
{
if(!IsBody(*word))
{
SPEC_WARN("In CaenADCUnpacker::UnpackDatum() found non-body word!");
return;
}
SpecData datum;
uint32_t channel = (*word & s_dataChannelMask) >> s_dataChannelShift;
datum.id = Utilities::GetBoardChannelUUID(m_moduleID, channel);
datum.longEnergy = (*word & s_dataMask);
m_parsedEvent.data.push_back(datum);
}
bool CaenUnpacker::IsHeader(uint32_t word) const
{
return ((word & s_typeMask) == s_typeHeader);
}
bool CaenUnpacker::IsBody(uint32_t word) const
{
return ((word & s_typeMask) == s_typeBody);
}
bool CaenUnpacker::IsEnd(uint32_t word) const
{
return ((word & s_typeMask) == s_typeEnd);
}
}

View File

@ -0,0 +1,46 @@
#ifndef CAEN_UNPACKER_H
#define CAEN_UNPACKER_H
#include "Unpacker.h"
namespace Specter {
class CaenUnpacker : public Unpacker
{
public:
CaenUnpacker();
virtual ~CaenUnpacker();
virtual bool IsHeader(uint32_t word) const override;
private:
virtual bool IsBody(uint32_t word) const override;
virtual bool IsEnd(uint32_t word) const override;
virtual void UnpackHeader(uint32_t* word) override;
virtual void UnpackEnd(uint32_t* word) override;
virtual void UnpackDatum(uint32_t* word) override;
static constexpr uint32_t s_typeMask = 0x07000000;
static constexpr uint32_t s_typeHeader = 0x02000000;
static constexpr uint32_t s_typeBody = 0x00000000;
static constexpr uint32_t s_typeEnd = 0x04000000;
static constexpr uint32_t s_geoAddressShift = 27;
static constexpr uint32_t s_geoAddressMask = 0xf8000000;
static constexpr uint32_t s_headerCountShift = 8;
static constexpr uint32_t s_headerCountMask = 0x00003f00;
static constexpr uint32_t s_dataChannelShift = 16;
static constexpr uint32_t s_dataChannelMask = 0x001f0000;
static constexpr uint32_t s_dataMask = 0x00000fff;
static constexpr uint32_t s_dataStatusMask = 0x00003000;
static constexpr uint32_t s_dataOverflow = 0x00001000;
static constexpr uint32_t s_dataUnderflow = 0x00002000;
};
}
#endif

View File

@ -0,0 +1,62 @@
#include "MesyTecUnpacker.h"
#include "Specter/Utils/Functions.h"
namespace Specter {
MesyTecUnpacker::MesyTecUnpacker() :
Unpacker()
{
}
MesyTecUnpacker::~MesyTecUnpacker() {}
void MesyTecUnpacker::UnpackHeader(uint32_t* word)
{
if(!IsHeader(*word))
{
SPEC_WARN("In MesyQDCUnpacker::UnpackHeader() found non-header word!");
m_moduleID = s_illegalModuleID;
m_bodyWordCount = 0;
}
m_moduleID = (*word & s_idMask) >> s_idShift;
m_bodyWordCount = (*word & s_headerCountMask) - 1; //For MesyTec, count includes the end word
}
void MesyTecUnpacker::UnpackDatum(uint32_t* word)
{
if(!IsBody(*word))
{
SPEC_WARN("In MesyQDCUnpacker::UnpackDatum() found non-body word!");
return;
}
SpecData datum;
uint32_t channel = (*word & s_dataChannelMask) >> s_dataChannelShift;
datum.id = Utilities::GetBoardChannelUUID(m_moduleID, channel);
datum.longEnergy = (*word & s_dataMask);
}
void MesyTecUnpacker::UnpackEnd(uint32_t* word)
{
if(!IsEnd(*word))
{
SPEC_WARN("In MesyQDCUnpacker::UnpackEnd() found non-end word!");
}
}
bool MesyTecUnpacker::IsHeader(uint32_t word) const
{
return ((word & s_typeMask) == s_typeHeader);
}
bool MesyTecUnpacker::IsBody(uint32_t word) const
{
return ((word & s_typeMask) == s_typeBody);
}
bool MesyTecUnpacker::IsEnd(uint32_t word) const
{
return ((word & s_typeMask) == s_typeEnd);
}
}

View File

@ -0,0 +1,41 @@
#ifndef MESY_TEC_UNPACKER_H
#define MESY_TEC_UNPACKER_H
#include "Unpacker.h"
namespace Specter {
class MesyTecUnpacker : public Unpacker
{
public:
MesyTecUnpacker();
virtual ~MesyTecUnpacker();
virtual bool IsHeader(uint32_t word) const override;
private:
virtual bool IsBody(uint32_t word) const override;
virtual bool IsEnd(uint32_t word) const override;
virtual void UnpackHeader(uint32_t* word) override;
virtual void UnpackEnd(uint32_t* word) override;
virtual void UnpackDatum(uint32_t* word) override;
static constexpr uint32_t s_typeMask = 0xc000000;
static constexpr uint32_t s_typeHeader = 0x40000000;
static constexpr uint32_t s_typeBody = 0x00000000;
static constexpr uint32_t s_typeEnd = 0xc0000000;
static constexpr uint32_t s_idShift = 16;
static constexpr uint32_t s_idMask = 0x00ff0000;
static constexpr uint32_t s_headerCountMask = 0x00000fff;
static constexpr uint32_t s_dataChannelShift = 16;
static constexpr uint32_t s_dataChannelMask = 0x001f0000;
static constexpr uint32_t s_dataMask = 0x0000ffff;
};
}
#endif

View File

@ -0,0 +1,82 @@
#ifndef UNPACKER_H
#define UNPACKER_H
#include "Specter/Physics/SpecData.h"
namespace Specter {
struct UnpackerResult
{
uint32_t* finalPosition = nullptr;
std::vector<SpecData> data;
};
class Unpacker
{
public:
using Ref = std::shared_ptr<Unpacker>;
Unpacker() :
m_bodyWordCount(0), m_moduleID(s_illegalModuleID)
{
}
virtual ~Unpacker() {}
const UnpackerResult& Unpack(uint32_t* begin, uint32_t* end)
{
m_parsedEvent = UnpackerResult();
uint32_t* iter = begin;
UnpackHeader(iter);
++iter;
uint32_t* bodyEnd = iter + m_bodyWordCount;
if(bodyEnd > end || m_moduleID == s_illegalModuleID)
{
SPEC_WARN("In Unpacker::Unpack() header unpack error (number of words: {0}, moduleID: {1}), data not parsed!", m_bodyWordCount, m_moduleID);
}
else
{
iter = UnpackBody(iter, bodyEnd);
UnpackEnd(iter);
++iter;
}
m_parsedEvent.finalPosition = iter;
return m_parsedEvent;
}
virtual bool IsHeader(uint32_t word) const = 0;
protected:
virtual bool IsBody(uint32_t word) const = 0;
virtual bool IsEnd(uint32_t word) const = 0;
virtual void UnpackHeader(uint32_t* word) = 0;
virtual void UnpackEnd(uint32_t* word) = 0;
uint32_t* UnpackBody(uint32_t* bodyBegin, uint32_t* bodyEnd)
{
uint32_t* iter = bodyBegin;
while(iter != bodyEnd)
{
UnpackDatum(iter);
iter++;
}
return iter;
}
virtual void UnpackDatum(uint32_t* word) = 0;
UnpackerResult m_parsedEvent;
uint64_t m_bodyWordCount;
uint32_t m_moduleID;
static constexpr uint32_t s_illegalModuleID = 999;
};
}
#endif

View File

@ -0,0 +1,128 @@
#ifndef SPECTER_THREAD_SAFE_QUEUE_H
#define SPECTER_THREAD_SAFE_QUEUE_H
#include <thread>
#include <mutex>
#include <atomic>
#include <queue>
#include <condition_variable>
namespace Specter {
template<typename T>
class ThreadSafeQueue
{
public:
ThreadSafeQueue() = default;
ThreadSafeQueue(const ThreadSafeQueue&) = delete; //no copy
~ThreadSafeQueue() { Clear(); }
void PushBack(const T& data)
{
std::scoped_lock<std::mutex> guard(m_queueMutex);
m_queue.push_back(data);
std::scoped_lock<std::mutex> condGuard(m_conditionMutex);
m_conditional.notify_one();
}
void PushFront(const T& data)
{
std::scoped_lock<std::mutex> guard(m_queueMutex);
m_queue.push_front(data);
std::scoped_lock<std::mutex> conditionGuard(m_conditionMutex);
m_conditional.notify_one();
}
void PopBack()
{
std::scoped_lock<std::mutex> guard(m_queueMutex);
m_queue.pop_back();
}
void PopFront()
{
std::scoped_lock<std::mutex> guard(m_queueMutex);
m_queue.pop_front();
}
const T& Front()
{
std::scoped_lock<std::mutex> guard(m_queueMutex);
return m_queue.front();
}
const T& Back()
{
std::scoped_lock<std::mutex> guard(m_queueMutex);
return m_queue.back();
}
std::size_t Size()
{
std::scoped_lock<std::mutex> guard(m_queueMutex);
return m_queue.size();
}
bool IsEmpty()
{
std::scoped_lock<std::mutex> guard(m_queueMutex);
return m_queue.empty();
}
void Clear()
{
std::scoped_lock<std::mutex> guard(m_queueMutex);
m_queue.clear();
}
//For iterator loops, need begin()/end() idiom
typename std::deque<T>::iterator begin()
{
std::scoped_lock<std::mutex> guard(m_queueMutex);
return m_queue.begin();
}
typename std::deque<T>::iterator end()
{
std::scoped_lock<std::mutex> guard(m_queueMutex);
return m_queue.end();
}
void Wait()
{
while (IsEmpty() && !m_isForceWakeup)
{
std::unique_lock<std::mutex> guard(m_conditionMutex);
m_conditional.wait(guard);
}
}
void ForceWakeup()
{
m_isForceWakeup = true;
std::unique_lock<std::mutex> guard(m_conditionMutex);
m_conditional.notify_one();
}
void ResetWakeup()
{
m_isForceWakeup = false;
}
private:
std::mutex m_queueMutex;
std::deque<T> m_queue;
std::mutex m_conditionMutex;
std::condition_variable m_conditional;
std::atomic<bool> m_isForceWakeup = false;
};
}
#endif