mirror of
https://github.com/gwm17/DaqGrimoire.git
synced 2024-11-26 20:28:51 -05:00
Adding the code
This commit is contained in:
parent
ae9c724d21
commit
6f647bf370
50
include/DYListData.h
Normal file
50
include/DYListData.h
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
#ifndef DY_LIST_DATA_H
|
||||||
|
#define DY_LIST_DATA_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
namespace DaqGrimoire {
|
||||||
|
|
||||||
|
namespace Data
|
||||||
|
{
|
||||||
|
static constexpr std::size_t Size = 24;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DYListData
|
||||||
|
{
|
||||||
|
uint16_t board;
|
||||||
|
uint16_t channel;
|
||||||
|
uint64_t timestamp;
|
||||||
|
uint32_t energy;
|
||||||
|
uint32_t energyShort;
|
||||||
|
uint32_t flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace Utils
|
||||||
|
{
|
||||||
|
void GetDataEventFromBuffer(char* bufferIter, DYListData& dataEvent)
|
||||||
|
{
|
||||||
|
dataEvent.board = *((uint16_t*)bufferIter);
|
||||||
|
bufferIter += 2;
|
||||||
|
|
||||||
|
dataEvent.channel = *((uint16_t*)bufferIter);
|
||||||
|
bufferIter += 2;
|
||||||
|
|
||||||
|
dataEvent.timestamp = *((uint64_t*)bufferIter);
|
||||||
|
bufferIter += 8;
|
||||||
|
|
||||||
|
dataEvent.energy = *((uint32_t*)bufferIter);
|
||||||
|
bufferIter += 4;
|
||||||
|
|
||||||
|
dataEvent.energyShort = *((uint32_t*)bufferIter);
|
||||||
|
bufferIter += 4;
|
||||||
|
|
||||||
|
dataEvent.flags = *((uint32_t*)bufferIter);
|
||||||
|
bufferIter += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
10
include/DaqGrimoire.h
Normal file
10
include/DaqGrimoire.h
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#ifndef DAQ_GRIMOIRE_H
|
||||||
|
#define DAQ_GRIMOIRE_H
|
||||||
|
|
||||||
|
#include "FileIO/DYFileReader.h"
|
||||||
|
|
||||||
|
#ifdef DG_HAS_ASIO
|
||||||
|
#include "NetIO/DYClient.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
123
include/FileIO/DYFileReader.h
Normal file
123
include/FileIO/DYFileReader.h
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
#ifndef DY_FILE_READER_H
|
||||||
|
#define DY_FILE_READER_H
|
||||||
|
|
||||||
|
#include "../DYListData.h"
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <memory>
|
||||||
|
#include <fstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace DaqGrimoire {
|
||||||
|
|
||||||
|
class DYFileReader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DYFileReader() :
|
||||||
|
m_fileHandle(nullptr), m_bufferSizeEvents(200000), m_isEOF(false), m_fileSizeBytes(0), m_fileSizeEvents(0), m_bufferIter(nullptr), m_bufferEnd(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DYFileReader(std::size_t bufferSize) :
|
||||||
|
m_fileHandle(nullptr), m_bufferSizeEvents(bufferSize), m_isEOF(false), m_fileSizeBytes(0), m_fileSizeEvents(0), m_bufferIter(nullptr), m_bufferEnd(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DYFileReader(const std::filesystem::path& filepath, std::size_t bufferSize = 200000) :
|
||||||
|
m_fileHandle(nullptr), m_bufferSizeEvents(bufferSize), m_isEOF(false), m_fileSizeBytes(0), m_fileSizeEvents(0), m_bufferIter(nullptr), m_bufferEnd(nullptr)
|
||||||
|
{
|
||||||
|
Open(filepath);
|
||||||
|
}
|
||||||
|
|
||||||
|
~DYFileReader()
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Open(const std::filesystem::path& filepath)
|
||||||
|
{
|
||||||
|
m_filepath = filepath;
|
||||||
|
m_fileHandle->open(filepath, std::ios::binary | std::ios::in);
|
||||||
|
|
||||||
|
m_fileHandle->seekg(0, std::ios_base::end);
|
||||||
|
m_fileSizeBytes = m_fileHandle->tellg();
|
||||||
|
|
||||||
|
//Replace this
|
||||||
|
if (m_fileSizeBytes == 0 || m_fileSizeBytes < Data::Size)
|
||||||
|
{
|
||||||
|
m_isEOF = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (m_fileSizeBytes % Data::Size != 0)
|
||||||
|
{
|
||||||
|
m_isEOF = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_fileSizeEvents = m_fileSizeBytes / Data::Size;
|
||||||
|
m_rawBuffer.resize(m_bufferSizeEvents * Data::Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Close()
|
||||||
|
{
|
||||||
|
if (IsOpen())
|
||||||
|
m_fileHandle->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetNextEvent(DYListData& dataEvent)
|
||||||
|
{
|
||||||
|
if (!IsOpen() || IsEOF())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (m_bufferIter == m_bufferEnd)
|
||||||
|
{
|
||||||
|
FillBuffer();
|
||||||
|
if (IsEOF())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Utils::GetDataEventFromBuffer(m_bufferIter, dataEvent);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const bool IsOpen() const { return m_fileHandle == nullptr ? false : m_fileHandle->is_open(); }
|
||||||
|
const bool IsEOF() const { return m_isEOF; }
|
||||||
|
const std::size_t GetFileSizeBytes() const { return m_fileSizeBytes; }
|
||||||
|
const std::size_t GetFileSizeEvents() const { return m_fileSizeEvents; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void FillBuffer()
|
||||||
|
{
|
||||||
|
if (m_fileHandle->eof())
|
||||||
|
{
|
||||||
|
m_isEOF = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_fileHandle->read(m_rawBuffer.data(), m_rawBuffer.size());
|
||||||
|
|
||||||
|
m_bufferIter = m_rawBuffer.data();
|
||||||
|
m_bufferEnd = m_bufferIter + m_fileHandle->gcount(); //one past the last datum
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
std::filesystem::path m_filepath;
|
||||||
|
std::shared_ptr<std::ifstream> m_fileHandle;
|
||||||
|
|
||||||
|
std::vector<char> m_rawBuffer;
|
||||||
|
std::size_t m_bufferSizeEvents; //in units of data events
|
||||||
|
|
||||||
|
std::size_t m_fileSizeBytes; //in bytes
|
||||||
|
std::size_t m_fileSizeEvents; //in data events
|
||||||
|
|
||||||
|
bool m_isEOF;
|
||||||
|
|
||||||
|
char* m_bufferIter;
|
||||||
|
char* m_bufferEnd;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
129
include/NetIO/DYClient.h
Normal file
129
include/NetIO/DYClient.h
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
#ifndef DY_CLIENT_H
|
||||||
|
#define DY_CLIENT_H
|
||||||
|
|
||||||
|
#include "DYMessage.h"
|
||||||
|
#include "ThreadSafeQueue.h"
|
||||||
|
|
||||||
|
#include "asio.hpp"
|
||||||
|
|
||||||
|
namespace DaqGrimoire {
|
||||||
|
|
||||||
|
class DYClient
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DYClient(const std::string& address, const std::string& port) :
|
||||||
|
m_socket(m_context)
|
||||||
|
{
|
||||||
|
Connect(address, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
~DYClient()
|
||||||
|
{
|
||||||
|
Disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GetNextEvent(DYListData& dataEvent)
|
||||||
|
{
|
||||||
|
if (m_dataQueue.IsEmpty())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
dataEvent = m_dataQueue.Front();
|
||||||
|
m_dataQueue.PopFront();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Connect(const std::string& address, const std::string& port)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
asio::ip::tcp::resolver resolver(m_context);
|
||||||
|
auto end_points = resolver.resolve(address, port);
|
||||||
|
asio::async_connect(m_socket, end_points,
|
||||||
|
[this](std::error_code ec, asio::ip::tcp::endpoint endpoint)
|
||||||
|
{
|
||||||
|
if (!ec)
|
||||||
|
{
|
||||||
|
ReadHeader();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
m_asioThread = std::thread([this]() { m_context.run() });
|
||||||
|
}
|
||||||
|
catch (asio::system_error& e)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Disconnect()
|
||||||
|
{
|
||||||
|
if (IsConnected())
|
||||||
|
{
|
||||||
|
asio::post(m_context, [this]() { m_socket.close(); })
|
||||||
|
}
|
||||||
|
|
||||||
|
m_context.stop();
|
||||||
|
if (m_asioThread.joinable())
|
||||||
|
m_asioThread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsConnected() { return m_socket.is_open(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
|
||||||
|
void 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 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)
|
||||||
|
{
|
||||||
|
char* dataPtr = m_tempMessage.body.data();
|
||||||
|
char* endPtr = m_tempMessage.body.data() + m_tempMessage.body.size();
|
||||||
|
DYListData tempData;
|
||||||
|
while (dataPtr != endPtr)
|
||||||
|
{
|
||||||
|
Utils::GetDataEventFromBuffer(dataPtr, tempData);
|
||||||
|
m_dataQueue.PushBack(tempData);
|
||||||
|
}
|
||||||
|
|
||||||
|
ReadHeader();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
asio::io_context m_context;
|
||||||
|
asio::ip::tcp::socket m_socket;
|
||||||
|
|
||||||
|
std::thread m_asioThread;
|
||||||
|
|
||||||
|
DYMessage m_tempMessage;
|
||||||
|
|
||||||
|
ThreadSafeQueue<DYListData> m_dataQueue;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
19
include/NetIO/DYMessage.h
Normal file
19
include/NetIO/DYMessage.h
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
#ifndef DY_MESSAGE_H
|
||||||
|
#define DY_MESSAGE_H
|
||||||
|
|
||||||
|
#include "../DYListData.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace DaqGrimoire {
|
||||||
|
|
||||||
|
struct DYMessage
|
||||||
|
{
|
||||||
|
DYMessage() = default;
|
||||||
|
|
||||||
|
uint64_t size;
|
||||||
|
std::vector<char> body;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
128
include/NetIO/ThreadSafeQueue.h
Normal file
128
include/NetIO/ThreadSafeQueue.h
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
#ifndef THREAD_SAFE_QUEUE_H
|
||||||
|
#define THREAD_SAFE_QUEUE_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <deque>
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
namespace DaqGrimoire {
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
std::deque<T>::iterator begin()
|
||||||
|
{
|
||||||
|
std::scoped_lock<std::mutex> guard(m_queueMutex);
|
||||||
|
return m_queue.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
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