108 lines
3.5 KiB
C
108 lines
3.5 KiB
C
|
|
#ifndef SCAN_DATA_CACHE_H
|
||
|
|
#define SCAN_DATA_CACHE_H
|
||
|
|
|
||
|
|
#include <atomic>
|
||
|
|
#include <condition_variable>
|
||
|
|
#include <cstdint>
|
||
|
|
#include <deque>
|
||
|
|
#include <functional>
|
||
|
|
#include <map>
|
||
|
|
#include <mutex>
|
||
|
|
#include <thread>
|
||
|
|
#include <utility>
|
||
|
|
#include <vector>
|
||
|
|
|
||
|
|
#include "VZNL_Types.h"
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Owns all laser lines produced by a scan. SDK callbacks only copy a line
|
||
|
|
* and try to enqueue it; they never wait for the consumer or the disk.
|
||
|
|
*/
|
||
|
|
class ScanDataCache
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
using ScanId = std::uint64_t;
|
||
|
|
using Data = std::vector<std::pair<EVzResultDataType, SVzLaserLineData>>;
|
||
|
|
|
||
|
|
ScanDataCache();
|
||
|
|
~ScanDataCache();
|
||
|
|
|
||
|
|
ScanDataCache(const ScanDataCache&) = delete;
|
||
|
|
ScanDataCache& operator=(const ScanDataCache&) = delete;
|
||
|
|
|
||
|
|
void BeginScan(ScanId scanId);
|
||
|
|
bool TryEnqueue(ScanId scanId, int cameraIndex,
|
||
|
|
EVzResultDataType dataType,
|
||
|
|
const SVzLaserLineData& line);
|
||
|
|
void FinishCamera(ScanId scanId, int cameraIndex);
|
||
|
|
|
||
|
|
// Moves a fully received camera buffer to the caller. Returns false when
|
||
|
|
// the scan is not finished yet or the buffer has no data.
|
||
|
|
bool TryTakeCompleted(ScanId scanId, int cameraIndex, Data& data);
|
||
|
|
void Restore(ScanId scanId, int cameraIndex, Data&& data);
|
||
|
|
|
||
|
|
// Used by debug-file input, which is already a complete scan.
|
||
|
|
void ReplaceCompleted(ScanId scanId, int cameraIndex, Data&& data);
|
||
|
|
void SetLineObserver(std::function<void(ScanId, int, EVzResultDataType,
|
||
|
|
const SVzLaserLineData&)> observer);
|
||
|
|
void SetReadyNotifier(std::function<void(ScanId, int)> notifier);
|
||
|
|
bool CopyData(ScanId scanId, int cameraIndex, Data& data) const;
|
||
|
|
|
||
|
|
bool HasData(ScanId scanId, int cameraIndex) const;
|
||
|
|
bool IsCompleted(ScanId scanId, int cameraIndex) const;
|
||
|
|
bool IsIncomplete(ScanId scanId, int cameraIndex) const;
|
||
|
|
std::size_t Size(ScanId scanId, int cameraIndex) const;
|
||
|
|
void CancelScan(ScanId scanId);
|
||
|
|
void Clear();
|
||
|
|
void Drain();
|
||
|
|
void Stop();
|
||
|
|
|
||
|
|
private:
|
||
|
|
struct QueueItem {
|
||
|
|
ScanId scanId = 0;
|
||
|
|
int cameraIndex = 0;
|
||
|
|
EVzResultDataType dataType{};
|
||
|
|
SVzLaserLineData line{};
|
||
|
|
std::size_t bytes = 0;
|
||
|
|
};
|
||
|
|
|
||
|
|
struct CameraBuffer {
|
||
|
|
Data data;
|
||
|
|
std::size_t pending = 0;
|
||
|
|
bool finishRequested = false;
|
||
|
|
bool completed = false;
|
||
|
|
bool incomplete = false;
|
||
|
|
};
|
||
|
|
|
||
|
|
using CameraKey = std::pair<ScanId, int>;
|
||
|
|
|
||
|
|
void WorkerLoop();
|
||
|
|
static bool CopyLine(EVzResultDataType dataType,
|
||
|
|
const SVzLaserLineData& source,
|
||
|
|
SVzLaserLineData& destination);
|
||
|
|
static void FreeLine(EVzResultDataType dataType, SVzLaserLineData& line);
|
||
|
|
static void FreeData(Data& data);
|
||
|
|
|
||
|
|
mutable std::mutex m_stateMutex;
|
||
|
|
std::map<CameraKey, CameraBuffer> m_buffers;
|
||
|
|
std::function<void(ScanId, int, EVzResultDataType,
|
||
|
|
const SVzLaserLineData&)> m_lineObserver;
|
||
|
|
std::function<void(ScanId, int)> m_readyNotifier;
|
||
|
|
|
||
|
|
// The SDK callback only holds these locks for the queue/state update. It
|
||
|
|
// never waits for the consumer, the algorithm, or disk I/O.
|
||
|
|
std::mutex m_queueMutex;
|
||
|
|
std::condition_variable m_queueCondition;
|
||
|
|
// The scan buffer is the source of truth and must not drop valid lines at
|
||
|
|
// an arbitrary byte threshold. The queue is drained by the worker; actual
|
||
|
|
// memory availability is the only general limit.
|
||
|
|
std::deque<QueueItem> m_queue;
|
||
|
|
std::size_t m_queuedBytes = 0;
|
||
|
|
std::size_t m_inFlight = 0;
|
||
|
|
|
||
|
|
std::atomic<bool> m_running{true};
|
||
|
|
std::thread m_worker;
|
||
|
|
};
|
||
|
|
|
||
|
|
#endif
|