diff --git a/.gitmodules b/.gitmodules index ef7f893..d293815 100644 --- a/.gitmodules +++ b/.gitmodules @@ -24,3 +24,6 @@ [submodule "Specter/vendor/yaml-cpp"] path = Specter/vendor/yaml-cpp url = https://github.com/jbeder/yaml-cpp.git +[submodule "Specter/vendor/DaqGrimoire"] + path = Specter/vendor/DaqGrimoire + url = https://github.com/gwm17/DaqGrimoire.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 0001f24..3dbfc76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.16) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) if(NOT CMAKE_BUILD_TYPE STREQUAL "Release") set(CMAKE_BUILD_TYPE "Debug") diff --git a/Specter/CMakeLists.txt b/Specter/CMakeLists.txt index 00e5a0d..a8d5585 100644 --- a/Specter/CMakeLists.txt +++ b/Specter/CMakeLists.txt @@ -3,4 +3,7 @@ add_subdirectory(vendor/glfw) add_subdirectory(vendor/imgui) add_subdirectory(vendor/yaml-cpp) +set(GRIMOIRE_ASIO_INCLUDE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/vendor/asio/asio/include) +add_subdirectory(vendor/DaqGrimoire) + add_subdirectory(src) diff --git a/Specter/src/CMakeLists.txt b/Specter/src/CMakeLists.txt index ffcc64e..3af82ef 100644 --- a/Specter/src/CMakeLists.txt +++ b/Specter/src/CMakeLists.txt @@ -99,6 +99,10 @@ target_sources(Specter PRIVATE Platform/OpenGL/OpenGLRendererAPI.h Platform/OpenGL/OpenGLWindow.cpp Platform/OpenGL/OpenGLWindow.h + Specter/Physics/Daqromancy/DYFileSource.h + Specter/Physics/Daqromancy/DYFileSource.cpp + Specter/Physics/Daqromancy/DYOnlineSource.h + Specter/Physics/Daqromancy/DYOnlineSource.cpp ) #ImPlot sources @@ -114,7 +118,7 @@ target_sources(Specter PRIVATE ) #Link our accompanying dependencies -target_link_libraries(Specter PRIVATE imgui glfw glad yaml-cpp) +target_link_libraries(Specter PRIVATE imgui glfw glad yaml-cpp DaqGrimoire) #Link OS graphics implementations set(THREADS_PREFER_PTHREAD_FLAG On) diff --git a/Specter/src/Specter/Physics/Daqromancy/DYFileSource.cpp b/Specter/src/Specter/Physics/Daqromancy/DYFileSource.cpp new file mode 100644 index 0000000..8fefdf1 --- /dev/null +++ b/Specter/src/Specter/Physics/Daqromancy/DYFileSource.cpp @@ -0,0 +1,115 @@ +#include "DYFileSource.h" + +namespace Specter { + + DYFileSource::DYFileSource(const std::string& directory, int channels_per_board) : + DataSource(), m_directory(directory), m_channelsPerBoard(channels_per_board) + { + CollectFiles(); + } + + DYFileSource::~DYFileSource() + { + } + + void DYFileSource::CollectFiles() + { + SPEC_PROFILE_FUNCTION(); + int nfiles = 0; + for (auto& item : std::filesystem::directory_iterator(m_directory)) + { + if (item.path().extension() == s_extension) + nfiles++; + } + + m_files.clear(); + m_files.reserve(nfiles); + for (auto& item : std::filesystem::directory_iterator(m_directory)) + { + if (item.path().extension() == s_extension) + { + m_files.emplace_back(item.path().string()); + } + } + + long total_hits = 0; + for (auto& file : m_files) + { + + if (!file.IsOpen()) + { + SPEC_ERROR("Unable to open a DYFile file {0}", file.GetFilePath()); + m_validFlag = false; + return; + } + + total_hits += file.GetFileSizeEvents(); + } + + if (m_files.size() == 0) + { + SPEC_WARN("Unable to find any files with extension {0} in directory {1}. CompassRun killed.", s_extension, m_directory); + m_validFlag = false; + } + else + { + SPEC_INFO("Succesfully opened {0} files with {1} total hits", nfiles, total_hits); + m_validFlag = true; + } + } + + bool DYFileSource::GetNextHit() + { + SPEC_PROFILE_FUNCTION(); + DaqGrimoire::DYFileReader* earliestFile = nullptr; + + for (std::size_t i = m_startIndex; i < m_files.size(); i++) + { + if (m_files[i].IsHitUsed()) + m_files[i].ReadNextEvent(); + + if (m_files[i].IsEOF()) + { + if (i == m_startIndex) + m_startIndex++; + continue; + } + else if (i == m_startIndex || m_files[i].GetCurrentEvent().timestamp < earliestFile->GetCurrentEvent().timestamp) + { + earliestFile = &(m_files[i]); + } + } + + if (earliestFile == nullptr) + return false; + + m_dyHit = earliestFile->GetCurrentEvent(); + earliestFile->SetHitUsed(); + return true; + } + + const SpecData& DYFileSource::GetData() + { + if (!IsValid()) + { + SPEC_ERROR("Trying to access DYFileSource data when invalid, bug detected!"); + m_datum = SpecData(); + return m_datum; + } + + if (!GetNextHit()) + { + 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 = m_dyHit.board * m_channelsPerBoard + m_dyHit.channel; + } + return m_datum; + } +} \ No newline at end of file diff --git a/Specter/src/Specter/Physics/Daqromancy/DYFileSource.h b/Specter/src/Specter/Physics/Daqromancy/DYFileSource.h new file mode 100644 index 0000000..c7987ca --- /dev/null +++ b/Specter/src/Specter/Physics/Daqromancy/DYFileSource.h @@ -0,0 +1,34 @@ +#ifndef DY_FILE_SOURCE_H +#define DY_FILE_SOURCE_H + +#include "DaqGrimoire.h" +#include "Specter/Physics/DataSource.h" +#include + +namespace Specter { + + class DYFileSource : public DataSource + { + public: + DYFileSource(const std::string& directory, int channels_per_board = 16); + virtual ~DYFileSource(); + + virtual const SpecData& GetData() override; + + private: + void CollectFiles(); + bool GetNextHit(); + + std::filesystem::path m_directory; + static constexpr std::string_view s_extension = ".dybin"; + int m_channelsPerBoard; + + std::vector m_files; + DaqGrimoire::DYListData m_dyHit; + std::size_t m_startIndex; + + uint64_t m_totalDataHits; + }; +} + +#endif \ No newline at end of file diff --git a/Specter/src/Specter/Physics/Daqromancy/DYOnlineSource.cpp b/Specter/src/Specter/Physics/Daqromancy/DYOnlineSource.cpp new file mode 100644 index 0000000..2747761 --- /dev/null +++ b/Specter/src/Specter/Physics/Daqromancy/DYOnlineSource.cpp @@ -0,0 +1,39 @@ +#include "DYOnlineSource.h" + +namespace Specter { + + DYOnlineSource::DYOnlineSource(const std::string& hostname, const std::string& port, int channelsPerBoard) : + DataSource(), m_clientConnection(hostname, port), m_channelsPerBoard(channelsPerBoard) + { + m_validFlag = m_clientConnection.IsConnected(); + } + + DYOnlineSource::~DYOnlineSource() + { + } + + const SpecData& DYOnlineSource::GetData() + { + if (!m_clientConnection.IsConnected()) + { + m_validFlag = false; + m_datum = SpecData(); + return m_datum; + } + + if (m_clientConnection.GetNextEvent(m_dyHit)) + { + //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 = m_dyHit.board * m_channelsPerBoard + m_dyHit.channel; + } + else + { + m_datum = SpecData(); + } + + return m_datum; + } +} \ No newline at end of file diff --git a/Specter/src/Specter/Physics/Daqromancy/DYOnlineSource.h b/Specter/src/Specter/Physics/Daqromancy/DYOnlineSource.h new file mode 100644 index 0000000..104db03 --- /dev/null +++ b/Specter/src/Specter/Physics/Daqromancy/DYOnlineSource.h @@ -0,0 +1,24 @@ +#ifndef DY_ONLINE_SOURCE_H +#define DY_ONLINE_SOURCE_H + +#include "Specter/Physics/DataSource.h" +#include "NetIO/DYClient.h" + +namespace Specter { + + class DYOnlineSource : public DataSource + { + public: + DYOnlineSource(const std::string& hostname, const std::string& port, int channelsPerBoard = 16); + ~DYOnlineSource(); + + virtual const SpecData& GetData() override; + + private: + DaqGrimoire::DYClient m_clientConnection; + DaqGrimoire::DYListData m_dyHit; + int m_channelsPerBoard; + }; +} + +#endif \ No newline at end of file diff --git a/Specter/src/Specter/Physics/DataSource.cpp b/Specter/src/Specter/Physics/DataSource.cpp index 4466710..3336b4e 100644 --- a/Specter/src/Specter/Physics/DataSource.cpp +++ b/Specter/src/Specter/Physics/DataSource.cpp @@ -9,6 +9,8 @@ #include "DataSource.h" #include "Caen/CompassRun.h" #include "Caen/CompassOnlineSource.h" +#include "Daqromancy/DYFileSource.h" +#include "Daqromancy/DYOnlineSource.h" namespace Specter { @@ -19,6 +21,8 @@ namespace Specter { { case DataSource::SourceType::CompassOffline : return new CompassRun(location, channels_per_board); case DataSource::SourceType::CompassOnline : return new CompassOnlineSource(location, port, header, channels_per_board); + case DataSource::SourceType::DaqromancyOffline: return new DYFileSource(location, channels_per_board); + case DataSource::SourceType::DaqromancyOnline: return new DYOnlineSource(location, port, channels_per_board); case DataSource::SourceType::None : return nullptr; } SPEC_WARN("Invalid DataSourceType at CreateDataSource!"); @@ -32,6 +36,8 @@ namespace Specter { case DataSource::SourceType::None: return "None"; case DataSource::SourceType::CompassOnline : return "CompassOnline"; case DataSource::SourceType::CompassOffline : return "CompassOffline"; + case DataSource::SourceType::DaqromancyOffline: return "DaqromancyOffline"; + case DataSource::SourceType::DaqromancyOnline: return "DaqromancyOnline"; } return "None"; diff --git a/Specter/src/Specter/Physics/DataSource.h b/Specter/src/Specter/Physics/DataSource.h index db77669..23e134d 100644 --- a/Specter/src/Specter/Physics/DataSource.h +++ b/Specter/src/Specter/Physics/DataSource.h @@ -21,7 +21,9 @@ namespace Specter { { None, CompassOnline, - CompassOffline + CompassOffline, + DaqromancyOnline, + DaqromancyOffline }; DataSource() : diff --git a/Specter/src/Specter/Physics/SpecData.h b/Specter/src/Specter/Physics/SpecData.h index 93c8384..1760d95 100644 --- a/Specter/src/Specter/Physics/SpecData.h +++ b/Specter/src/Specter/Physics/SpecData.h @@ -17,11 +17,11 @@ namespace Specter { struct SpecData { - uint32_t longEnergy; - uint32_t shortEnergy; - uint64_t calEnergy; - uint64_t timestamp; - uint32_t id; + uint32_t longEnergy = 0; + uint32_t shortEnergy = 0; + uint64_t calEnergy = 0; + uint64_t timestamp = 0; + uint32_t id = 0; }; using SpecEvent = std::vector; diff --git a/Specter/vendor/DaqGrimoire b/Specter/vendor/DaqGrimoire new file mode 160000 index 0000000..dedd1e0 --- /dev/null +++ b/Specter/vendor/DaqGrimoire @@ -0,0 +1 @@ +Subproject commit dedd1e0e953423a50ec8a35f4cb3161218aac642