From 49f1e3b19d8efc3b89a98a474aba55c8f7b89e28 Mon Sep 17 00:00:00 2001 From: Grant Date: Sun, 10 Nov 2019 14:25:35 -0800 Subject: [PATCH] Add Stream Reader Thread --- CMakeLists.txt | 1 + StreamManager.cpp | 217 +++++++++++++++++++++++++++++++++++++++++++--- StreamManager.hpp | 38 +++++++- StreamReader.cpp | 60 +++++++++++++ StreamReader.hpp | 28 ++++++ 5 files changed, 329 insertions(+), 15 deletions(-) create mode 100644 StreamReader.cpp create mode 100644 StreamReader.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 21b2f46..5917027 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,7 @@ add_executable( FaultFinder ImageManager.cpp ConfigManager.cpp FaultManager.cpp + StreamReader.cpp ${prog_SRCS} ) diff --git a/StreamManager.cpp b/StreamManager.cpp index be01739..8050621 100644 --- a/StreamManager.cpp +++ b/StreamManager.cpp @@ -1,18 +1,213 @@ -#include -#include -#include - #include "StreamManager.hpp" -#include "ImageManager.hpp" StreamManager::StreamManager(QObject *parent) : QObject(parent) -{ - QTimer *timer = new QTimer(this); - connect(timer, &QTimer::timeout, this, QOverload<>::of(&StreamManager::Process)); - timer->start(1000); +{ + // Listen for New Emissivity Signal + //connect(&config_mgr, &ConfigManager::NewEmissivity, this, &StreamManager::SetEmissivity); + PvResult res; + + res = FindDevice(); + + if (res.IsFailure()) + exit(res.GetCode()); + + res = ConnectToDevice(); + + if (res.IsFailure()) + exit(res.GetCode()); + + res = OpenStream(); + + if (res.IsFailure()) + exit(res.GetCode()); + + ConfigureStream(); + + CreatePipeline(); + + StartStream(); + + ImageThread = new StreamReader(Device, Stream, Pipeline); + + ImageThread->start(QThread::TimeCriticalPriority); } -void StreamManager::Process() +StreamManager::~StreamManager() { - qInfo() << "TICK"; + ImageThread->requestInterruption(); + ImageThread->wait(); + StopStream(); + Disconnect(); +} + +void StreamManager::SetEmissivity(double emissivity) +{ + if (lDeviceParams) + lDeviceParams->SetFloatValue("ObjectEmissivity", emissivity); +} + +PvResult StreamManager::FindDevice() +{ + PvResult lResult = PvResult(); + const PvDeviceInfo *lSelectedDI = NULL; + PvSystem lSystem; + + lSystem.Find(); + + // Detect, select device. + std::vector lDIVector; + for (uint32_t i = 0; i < lSystem.GetInterfaceCount(); i++) + { + const PvInterface *lInterface = dynamic_cast(lSystem.GetInterface(i)); + if (lInterface != NULL) + { + for (uint32_t j = 0; j < lInterface->GetDeviceCount(); j++) + { + const PvDeviceInfo *lDI = dynamic_cast(lInterface->GetDeviceInfo(j)); + if (lDI != NULL) + { + lDIVector.push_back(lDI); + } + } + } + } + + if (lDIVector.size() == 0) + { + qCritical() << "Device not found!"; + lResult.SetCode(PV_NOT_FOUND); + return lResult; + } + + lSelectedDI = lDIVector.front(); + + ConnectionID = lSelectedDI->GetConnectionID(); + + lResult.SetCode(PV_OK); + + return lResult; +} + +PvResult StreamManager::ConnectToDevice() +{ + PvResult lResult; + + // Connect to the GigE Vision or USB3 Vision device + qInfo() << "Connecting to device."; + Device = PvDevice::CreateAndConnect(ConnectionID, &lResult); + if (Device == NULL) + { + qCritical() << "Unable to connect to device."; + } + + return lResult; +} + +PvResult StreamManager::OpenStream() +{ + PvResult lResult; + + // Open stream to the GigE Vision or USB3 Vision device + qInfo() << "Opening stream from device."; + Stream = PvStream::CreateAndOpen(ConnectionID, &lResult); + + if (Stream != NULL) + { + // If this is a GigE Vision device, configure GigE Vision specific streaming parameters + PvDeviceGEV* lDeviceGEV = dynamic_cast(Device); + if ( lDeviceGEV != NULL ) + { + PvStreamGEV *lStreamGEV = static_cast(Stream); + + // Negotiate packet size + lDeviceGEV->NegotiatePacketSize(); + + // Configure device streaming destination + lDeviceGEV->SetStreamDestination( lStreamGEV->GetLocalIPAddress(), lStreamGEV->GetLocalPort() ); + } + } + else + { + qCritical() << "Unable to stream from device."; + } + + return lResult; +} + +void StreamManager::ConfigureStream() +{ + // Get device parameters need to control streaming + lDeviceParams = Device->GetParameters(); + + // Use Temperature Format Instead of Raw Counts + lDeviceParams->SetEnumValue("IRFormat", 1); + + SetEmissivity(0.95); +} + +void StreamManager::CreatePipeline() +{ + // Create the PvPipeline object + Pipeline = new PvPipeline( Stream ); + + if ( Pipeline != NULL ) + { + // Reading payload size from device + uint32_t lSize = Device->GetPayloadSize(); + + // Set the Buffer count and the Buffer size + Pipeline->SetBufferCount( BUFFER_COUNT ); + Pipeline->SetBufferSize( lSize ); + } +} + +void StreamManager::StartStream() +{ + // Map the GenICam AcquisitionStart and AcquisitionStop commands + PvGenCommand *lStart = dynamic_cast(lDeviceParams->Get("AcquisitionStart")); + + qInfo() << "Starting pipeline"; + Pipeline->Start(); + + // Get stream parameters + PvGenParameterArray *lStreamParams = Stream->GetParameters(); + + // Map a few GenICam stream stats counters + PvGenFloat *lFrameRate = dynamic_cast(lStreamParams->Get("AcquisitionRate")); + PvGenFloat *lBandwidth = dynamic_cast(lStreamParams->Get("Bandwidth")); + + // Enable streaming and send the AcquisitionStart command + qInfo() << "Enabling streaming and sending AcquisitionStart command."; + Device->StreamEnable(); + lStart->Execute(); +} + +void StreamManager::StopStream() +{ + // Tell the device to stop sending images. + qInfo() << "Sending AcquisitionStop command to the device"; + PvGenCommand *lStop = dynamic_cast(lDeviceParams->Get("AcquisitionStop")); + lStop->Execute(); + + // Disable streaming on the device + qInfo() << "Disable streaming on the controller.";; + Device->StreamDisable(); + + // Stop the pipeline + qInfo() << "Stop pipeline"; + Pipeline->Stop(); +} + +void StreamManager::Disconnect() +{ + if (Stream != NULL) + { + Stream->Close(); + PvStream::Free(Stream); + } + if (Device != NULL) + { + Device->Disconnect(); + PvDevice::Free(Device); + } } \ No newline at end of file diff --git a/StreamManager.hpp b/StreamManager.hpp index 8b688e1..77ad928 100644 --- a/StreamManager.hpp +++ b/StreamManager.hpp @@ -2,17 +2,47 @@ #define STREAM_MANAGER_H #include +#include + +#include +#include +#include +#include +#include +#include + +#include "StreamReader.hpp" + +#define BUFFER_COUNT (32) class StreamManager : public QObject { - Q_OBJECT; public: - StreamManager(QObject *parent); - void Process(); - + virtual ~StreamManager(); + +public slots: + void SetEmissivity(double emissivity); + +private: + PvResult FindDevice(); + PvResult ConnectToDevice(); + PvResult OpenStream(); + void ConfigureStream(); + void StartStream(); + void StopStream(); + void CreatePipeline(); + void AcquireImages(); + void Disconnect(); + + PvString ConnectionID; + PvDevice *Device = NULL; + PvStream *Stream = NULL; + PvGenParameterArray *lDeviceParams = NULL; + PvPipeline *Pipeline = NULL; + StreamReader *ImageThread; }; #endif \ No newline at end of file diff --git a/StreamReader.cpp b/StreamReader.cpp new file mode 100644 index 0000000..2d7b5dc --- /dev/null +++ b/StreamReader.cpp @@ -0,0 +1,60 @@ +#include "StreamReader.hpp" + +StreamReader::StreamReader(PvDevice *Device, PvStream *Stream, PvPipeline *Pipeline) +{ + this->Device = Device; + this->Stream = Stream; + this->Pipeline = Pipeline; +} + +void StreamReader::run() +{ + while (!isInterruptionRequested()) + { + PvBuffer *lBuffer = NULL; + PvResult lOperationResult; + + // wait for this to unblock before called in event loop + // Retrieve next buffer + PvResult lResult = Stream->RetrieveBuffer(&lBuffer, &lOperationResult, 1000); + if (lResult.IsOK()) + { + if (lOperationResult.IsOK()) + { + PvPayloadType lType; + + // If the buffer contains an image, display width and height. + uint32_t lWidth = 0, lHeight = 0; + lType = lBuffer->GetPayloadType(); + + if (lType == PvPayloadTypeImage) + { + // Get image specific buffer interface. + PvImage *lImage = lBuffer->GetImage(); + + // Read width, height. + lWidth = lImage->GetWidth(); + lHeight = lImage->GetHeight(); + + NewImage(lWidth, lHeight, lImage->GetDataPointer()); + } + else + { + qWarning() << " (buffer does not contain image)"; + } + } + else + { + qInfo() << lOperationResult.GetCodeString().GetAscii() << "\r"; + } + + // Re-queue the buffer in the stream object + Stream->QueueBuffer(lBuffer); + } + else + { + // Retrieve buffer failure + qCritical() << lResult.GetCodeString().GetAscii() << "\r"; + } + } +} \ No newline at end of file diff --git a/StreamReader.hpp b/StreamReader.hpp new file mode 100644 index 0000000..e2981c2 --- /dev/null +++ b/StreamReader.hpp @@ -0,0 +1,28 @@ +#ifndef STREAM_READER_H +#define STREAM_READER_H + +#include +#include +#include +#include +#include + +class StreamReader : public QThread +{ + Q_OBJECT; + + void run(); + +public: + StreamReader(PvDevice *Device, PvStream *Stream, PvPipeline *Pipeline); + +signals: + void NewImage(uint32_t width, uint32_t height, uint8_t *imgPointer); + +private: + PvDevice *Device = NULL; + PvStream *Stream = NULL; + PvPipeline *Pipeline = NULL; +}; + +#endif \ No newline at end of file