mirror of
https://github.com/gwm17/Specter.git
synced 2024-11-26 12:18:51 -05:00
Compare commits
2 Commits
7fca02119e
...
8e9fcffa65
Author | SHA1 | Date | |
---|---|---|---|
8e9fcffa65 | |||
Gordon McCann | 72190d93a3 |
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
else if (m_chosenType == DataSource::SourceType::CharonOnline)
|
||||||
|
{
|
||||||
|
ImGui::InputText("Hostname", &m_chosenLocation);
|
||||||
|
ImGui::InputText("Port", &m_chosenPort);
|
||||||
}
|
}
|
||||||
ImGui::InputInt("Coinc. Window (ps)", &m_chosenWindow);
|
|
||||||
|
|
||||||
|
|
||||||
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);
|
||||||
{
|
Application::Get().OnEvent(event);
|
||||||
PhysicsStartEvent event(m_chosenLocation, m_chosenType, m_chosenWindow, m_chosenPort, false, 0U);
|
|
||||||
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();
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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.
|
|
||||||
m_datum.longEnergy = m_hit.energy;
|
|
||||||
m_datum.shortEnergy = m_hit.energyShort;
|
|
||||||
m_datum.calEnergy = m_hit.energyCalibrated;
|
|
||||||
m_datum.timestamp = m_hit.timestamp;
|
|
||||||
m_datum.id = Utilities::GetBoardChannelUUID(m_hit.board, m_hit.channel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Convert data from CoMPASS format to universal Specter format.
|
||||||
|
m_datum.longEnergy = m_hit.energy;
|
||||||
|
m_datum.shortEnergy = m_hit.energyShort;
|
||||||
|
m_datum.calEnergy = m_hit.energyCalibrated;
|
||||||
|
m_datum.timestamp = m_hit.timestamp;
|
||||||
|
m_datum.id = Utilities::GetBoardChannelUUID(m_hit.board, m_hit.channel);
|
||||||
|
|
||||||
return m_datum;
|
if(m_eventBuilder.AddDatum(m_datum))
|
||||||
|
{
|
||||||
|
m_isEventReady = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
|
m_datum.longEnergy = m_dyHit.energy;
|
||||||
|
m_datum.shortEnergy = m_dyHit.energyShort;
|
||||||
|
m_datum.timestamp = m_dyHit.timestamp;
|
||||||
|
m_datum.id = Utilities::GetBoardChannelUUID(m_dyHit.board, m_dyHit.channel);
|
||||||
|
if(m_eventBuilder.AddDatum(m_datum))
|
||||||
{
|
{
|
||||||
//Convert data from Daqromancy format to universal Specter format.
|
m_isEventReady = true;
|
||||||
m_datum.longEnergy = m_dyHit.energy;
|
|
||||||
m_datum.shortEnergy = m_dyHit.energyShort;
|
|
||||||
m_datum.timestamp = m_dyHit.timestamp;
|
|
||||||
m_datum.id = Utilities::GetBoardChannelUUID(m_dyHit.board, m_dyHit.channel);
|
|
||||||
}
|
}
|
||||||
return m_datum;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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();
|
||||||
|
|
|
@ -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))
|
||||||
|
m_isEventReady = true;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
m_datum = SpecData();
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_datum;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,19 +11,21 @@
|
||||||
#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::None : return nullptr;
|
case DataSource::SourceType::CharonOnline: return new CharonOnlineSource(location, port);
|
||||||
|
case DataSource::SourceType::None: return nullptr;
|
||||||
}
|
}
|
||||||
SPEC_WARN("Invalid DataSourceType at CreateDataSource!");
|
SPEC_WARN("Invalid DataSourceType at CreateDataSource!");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -34,10 +36,11 @@ namespace Specter {
|
||||||
switch(type)
|
switch(type)
|
||||||
{
|
{
|
||||||
case DataSource::SourceType::None: return "None";
|
case DataSource::SourceType::None: return "None";
|
||||||
case DataSource::SourceType::CompassOnline : return "CompassOnline";
|
case DataSource::SourceType::CompassOnline: return "CompassOnline";
|
||||||
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";
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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,43 +136,37 @@ 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();
|
||||||
//Pass data from source to event builder. True from AddDatum indicates events are ready
|
if(m_source->IsEventReady())
|
||||||
if (m_eventBuilder.AddDatum(datum))
|
|
||||||
{
|
|
||||||
events = m_eventBuilder.GetReadyEvents();
|
|
||||||
for (auto& event : events)
|
|
||||||
{
|
{
|
||||||
for (auto& stage : m_physStack)
|
events = m_source->GetEvents();
|
||||||
stage->AnalyzePhysicsEvent(event);
|
|
||||||
|
|
||||||
//Now that the analysis stack has filled all our NavParameters with data, update the histogram counts
|
|
||||||
m_manager->UpdateHistograms();
|
|
||||||
//Invalidate all parameters to get ready for next event
|
|
||||||
m_manager->InvalidateParameters();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto& event : events)
|
||||||
|
{
|
||||||
|
for (auto& stage : m_physStack)
|
||||||
|
stage->AnalyzePhysicsEvent(event);
|
||||||
|
|
||||||
|
//Now that the analysis stack has filled all our NavParameters with data, update the histogram counts
|
||||||
|
m_manager->UpdateHistograms();
|
||||||
|
//Invalidate all parameters to get ready for next event
|
||||||
|
m_manager->InvalidateParameters();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!events.empty())
|
||||||
|
events.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
96
Specter/src/Specter/Physics/nscldaq/CharonClient.cpp
Normal file
96
Specter/src/Specter/Physics/nscldaq/CharonClient.cpp
Normal 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();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
43
Specter/src/Specter/Physics/nscldaq/CharonClient.h
Normal file
43
Specter/src/Specter/Physics/nscldaq/CharonClient.h
Normal 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
|
67
Specter/src/Specter/Physics/nscldaq/CharonOnlineSource.cpp
Normal file
67
Specter/src/Specter/Physics/nscldaq/CharonOnlineSource.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
35
Specter/src/Specter/Physics/nscldaq/CharonOnlineSource.h
Normal file
35
Specter/src/Specter/Physics/nscldaq/CharonOnlineSource.h
Normal 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
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
46
Specter/src/Specter/Physics/nscldaq/Unpackers/CaenUnpacker.h
Normal file
46
Specter/src/Specter/Physics/nscldaq/Unpackers/CaenUnpacker.h
Normal 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
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
82
Specter/src/Specter/Physics/nscldaq/Unpackers/Unpacker.h
Normal file
82
Specter/src/Specter/Physics/nscldaq/Unpackers/Unpacker.h
Normal 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
|
128
Specter/src/Specter/Utils/ThreadSafeQueue.h
Normal file
128
Specter/src/Specter/Utils/ThreadSafeQueue.h
Normal 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
|
Loading…
Reference in New Issue
Block a user