From 4cd2150ff96beda9626dd4c3afe7ef44cccd48e7 Mon Sep 17 00:00:00 2001 From: "melnykov.artem" Date: Thu, 18 Aug 2022 14:05:32 -0500 Subject: [PATCH 01/14] Started adding DataStreamer device --- MMDevice/MMDevice.cpp | 1 + MMDevice/MMDevice.h | 50 ++++++++++++++++++++++++++++++++++++ MMDevice/MMDeviceConstants.h | 3 ++- 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/MMDevice/MMDevice.cpp b/MMDevice/MMDevice.cpp index 36c82ef97..4423dae0e 100644 --- a/MMDevice/MMDevice.cpp +++ b/MMDevice/MMDevice.cpp @@ -46,6 +46,7 @@ const DeviceType SignalIO::Type = SignalIODevice; const DeviceType Magnifier::Type = MagnifierDevice; const DeviceType SLM::Type = SLMDevice; const DeviceType Galvo::Type = GalvoDevice; +const DeviceType DataStreamer::Type = DataStreamerDevice; const DeviceType Hub::Type = HubDevice; } // namespace MM diff --git a/MMDevice/MMDevice.h b/MMDevice/MMDevice.h index cd070d6ff..3990433d3 100644 --- a/MMDevice/MMDevice.h +++ b/MMDevice/MMDevice.h @@ -1176,6 +1176,56 @@ namespace MM { virtual int GetChannel(char* channelName) = 0; }; + /** + * DataStreamer API + */ + class DataStreamer : public Device + { + public: + DataStreamer() {} + virtual ~DataStreamer() {} + + // Device API + virtual DeviceType GetType() const { return Type; } + static const DeviceType Type; + + // DataStreamer API + + // Calls that are specific to each DataStreamer device + // and should be implemented in the device adapter + /** + * Get the size (in bytes) of the data buffer available for download from the hardware + */ + virtual int GetBufferSize(unsigned& dataBufferSiize) = 0; + /** + * Receive data buffer from the hardware and place it at memory location + * specified by pDataBuffer + */ + virtual int GetBuffer(unsigned pDataBuffer) = 0; + /** + * Process the data buffer available at pDataBuffer and place + * resulting multidimensional array at pProcessedArray + */ + virtual int ProcessBuffer(unsigned pDataBuffer, unsigned pProcessedArray) = 0; + /** + * Get dimensionality of the array obtained as a result of processing data + */ + virtual int GetProcessedArrayDimension(unsigned& numberOfDimensions) = 0; + /** + * Get the shape of the array (how long the dimensions are) + */ + virtual int GetProcessedArrayShape(unsigned& shape) = 0; + + // Calls that are implemented at the DeviceBase level and + // remain the same for any DataStreamer device + virtual int SetStreamLength(unsigned numberOfBuffers, double timeUs) = 0; + virtual int GetStreamLength(unsigned& numberOfBuffers, double& timeUs) = 0; + virtual int StartStream() = 0; + virtual int StopStream() = 0; + virtual int PauseStream() = 0; + virtual int IsStreaming(unsigned& isStreaming) = 0; + }; + /** * HUB device. Used for complex uber-device functionality in microscope stands * and managing auto-configuration (discovery) of other devices diff --git a/MMDevice/MMDeviceConstants.h b/MMDevice/MMDeviceConstants.h index 058572b91..09f49366d 100644 --- a/MMDevice/MMDeviceConstants.h +++ b/MMDevice/MMDeviceConstants.h @@ -216,7 +216,8 @@ namespace MM { MagnifierDevice, SLMDevice, HubDevice, - GalvoDevice + GalvoDevice, + DataStreamerDevice }; enum PropertyType { From 5afe9911ee62964c8f505e44d8fe3937d92b4987 Mon Sep 17 00:00:00 2001 From: "melnykov.artem" Date: Tue, 25 Oct 2022 14:16:29 -0500 Subject: [PATCH 02/14] Rebasing onto main: replaced boost with std --- DeviceAdapters/DemoCamera/DemoCamera.cpp | 6 + DeviceAdapters/DemoCamera/DemoCamera.h | 59 ++++ MMCore/CircularBlockCollection.cpp | 76 +++++ MMCore/CircularBlockCollection.h | 56 ++++ MMCore/CoreUtils.h | 1 + MMCore/Devices/DataStreamerInstance.cpp | 34 +++ MMCore/Devices/DataStreamerInstance.h | 47 ++++ MMCore/Devices/DeviceInstances.h | 1 + .../LoadableModules/LoadedDeviceAdapter.cpp | 2 + MMCore/MMCore.cpp | 91 ++++++ MMCore/MMCore.h | 13 + MMCore/MMCore.vcxproj | 4 + MMCore/MMCore.vcxproj.filters | 14 +- MMDevice/DeviceBase.h | 265 ++++++++++++++++++ MMDevice/MMDevice.h | 18 +- 15 files changed, 673 insertions(+), 14 deletions(-) create mode 100644 MMCore/CircularBlockCollection.cpp create mode 100644 MMCore/CircularBlockCollection.h create mode 100644 MMCore/Devices/DataStreamerInstance.cpp create mode 100644 MMCore/Devices/DataStreamerInstance.h diff --git a/DeviceAdapters/DemoCamera/DemoCamera.cpp b/DeviceAdapters/DemoCamera/DemoCamera.cpp index 0a9fb3fdf..140508d3e 100644 --- a/DeviceAdapters/DemoCamera/DemoCamera.cpp +++ b/DeviceAdapters/DemoCamera/DemoCamera.cpp @@ -89,6 +89,7 @@ MODULE_API void InitializeModuleData() RegisterDevice(g_DA2DeviceName, MM::SignalIODevice, "Demo DA-2"); RegisterDevice(g_MagnifierDeviceName, MM::MagnifierDevice, "Demo Optovar"); RegisterDevice(g_GalvoDeviceName, MM::GalvoDevice, "Demo Galvo"); + RegisterDevice(g_DataStreamerDeviceName, MM::DataStreamerDevice, "Demo DataStreamer"); RegisterDevice("TransposeProcessor", MM::ImageProcessorDevice, "TransposeProcessor"); RegisterDevice("ImageFlipX", MM::ImageProcessorDevice, "ImageFlipX"); RegisterDevice("ImageFlipY", MM::ImageProcessorDevice, "ImageFlipY"); @@ -167,6 +168,11 @@ MODULE_API MM::Device* CreateDevice(const char* deviceName) // create Galvo return new DemoGalvo(); } + else if (strcmp(deviceName, g_DataStreamerDeviceName) == 0) + { + // create DataStreamer + return new DemoDataStreamer(); + } else if(strcmp(deviceName, "TransposeProcessor") == 0) { diff --git a/DeviceAdapters/DemoCamera/DemoCamera.h b/DeviceAdapters/DemoCamera/DemoCamera.h index acd3df13a..29b2a6f19 100644 --- a/DeviceAdapters/DemoCamera/DemoCamera.h +++ b/DeviceAdapters/DemoCamera/DemoCamera.h @@ -51,6 +51,8 @@ const char* NoHubError = "Parent Hub not defined."; +const char* g_DataStreamerDeviceName = "DSimulatedDataStreamer"; + // Defines which segments in a seven-segment display are lit up for each of // the numbers 0-9. Segments are: // @@ -1194,6 +1196,63 @@ class DemoGalvo : public CGalvoBase, ImgManipulator double vMaxY_; }; +////////////////////////////////////////////////////////////////////////////// +// DemoShutter class +// Simulation of shutter device +////////////////////////////////////////////////////////////////////////////// +class DemoDataStreamer : public CDataStreamerBase +{ +public: + DemoDataStreamer() + { + // parent ID display + CreateHubIDProperty(); + } + ~DemoDataStreamer() {} + + int Initialize() { + initialized_ = true; + return DEVICE_OK; + } + int Shutdown() { initialized_ = false; return DEVICE_OK; } + + void GetName(char* pszName) const { + CDeviceUtils::CopyLimitedString(pszName, g_DataStreamerDeviceName); + } + bool Busy() { + return false; + } + + + int GetBufferSize(unsigned& dataBufferSize) { dataBufferSize = 5; LogMessage("HRYUK!!!-GetBufferSize", false); return DEVICE_OK; } + + std::unique_ptr GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize) { + + LogMessage("HRYUK!!!-GetBuffer", false); + + // allocate a new data array and put data into it + std::unique_ptr data(new char[expectedDataBufferSize]); + //data.operator[](0) = 69; + //data.operator[](1) = 79; + //data.operator[](2) = 89; + //data.operator[](3) = 99; + //data.operator[](4) = 109; + + actualDataBufferSize = 5; + + return data; + } + + int ProcessBuffer(std::string str) { +// int ProcessBuffer(std::unique_ptr &pDataBuffer) { + LogMessage(str.c_str(), false); + return DEVICE_OK; + } + +private: + bool initialized_; + MM::MMTime changedTime_; +}; #endif //_DEMOCAMERA_H_ diff --git a/MMCore/CircularBlockCollection.cpp b/MMCore/CircularBlockCollection.cpp new file mode 100644 index 000000000..d62945a22 --- /dev/null +++ b/MMCore/CircularBlockCollection.cpp @@ -0,0 +1,76 @@ +/////////////////////////////////////////////////////////////////////////////// +// FILE: CircularBlockCollection.cpp +// PROJECT: Micro-Manager +// SUBSYSTEM: MMCore +//----------------------------------------------------------------------------- +// DESCRIPTION: Implementation of circular buffer that also stores sizes +// of contained data blocks +// +// COPYRIGHT: Artem Melnykov, 2022 +// +// LICENSE: This file is distributed under the "Lesser GPL" (LGPL) license. +// License text is included with the source distribution. +// +// This file is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES. +// +// AUTHOR: Artem Melnykov, melnykov.artem@gmail.com, 2022 +// + +#include "CircularBlockCollection.h" + + +CircularBlockCollection::CircularBlockCollection(unsigned int maxNumberOfBlocks, bool stopOnOverflow) : + maxNumberOfBlocks_(0), + stopOnOverflow_(true), + overflowStatus_(false) +{ + boost::circular_buffer cb_(maxNumberOfBlocks); + maxNumberOfBlocks_ = maxNumberOfBlocks; + stopOnOverflow_ = stopOnOverflow; +} + +CircularBlockCollection::~CircularBlockCollection() +{ +} + +void CircularBlockCollection::Add(BLOCK dataBlock) +{ + MMThreadGuard g(this->executeLock_); + if (cb_.capacity() - cb_.size() == 0) { + overflowStatus_ = true; + if (stopOnOverflow_) return; + cb_.empty(); + } + cb_.push_front(dataBlock); +} + +BLOCK CircularBlockCollection::Remove() +{ + MMThreadGuard g(this->executeLock_); + if (cb_.size() == 0) { + return BLOCK(); + } + else { + BLOCK dataBlock = BLOCK(cb_.at(0)); + cb_.pop_back(); + return dataBlock; + } +} + +void CircularBlockCollection::ResetOverflowStatus() +{ + MMThreadGuard g(this->executeLock_); + overflowStatus_ = false; +} + +bool CircularBlockCollection::GetOverflowStatus() +{ + MMThreadGuard g(this->executeLock_); + return overflowStatus_; +} \ No newline at end of file diff --git a/MMCore/CircularBlockCollection.h b/MMCore/CircularBlockCollection.h new file mode 100644 index 000000000..26e201517 --- /dev/null +++ b/MMCore/CircularBlockCollection.h @@ -0,0 +1,56 @@ +/////////////////////////////////////////////////////////////////////////////// +// FILE: CircularBlockCollection.h +// PROJECT: Micro-Manager +// SUBSYSTEM: MMCore +//----------------------------------------------------------------------------- +// DESCRIPTION: Implementation of circular buffer that also stores sizes +// of contained data blocks +// +// COPYRIGHT: Artem Melnykov, 2022 +// +// LICENSE: This file is distributed under the "Lesser GPL" (LGPL) license. +// License text is included with the source distribution. +// +// This file is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES. +// +// AUTHOR: Artem Melnykov, melnykov.artem@gmail.com, 2022 +// + +#pragma once + +#include +#include + +#include "../MMDevice/DeviceThreads.h" + +typedef struct { + boost::shared_ptr data; + unsigned int dataSize; +} BLOCK; + + +class CircularBlockCollection +{ +public: + CircularBlockCollection(unsigned int maxNumberOfBlocks, bool stopOnOverflow); + ~CircularBlockCollection(); + + bool GetOverflowStatus(); + void ResetOverflowStatus(); + + void Add(BLOCK dataBlock); + BLOCK Remove(); + +private: + boost::circular_buffer cb_; + MMThreadLock executeLock_; + unsigned long maxNumberOfBlocks_; + bool stopOnOverflow_; + bool overflowStatus_; +}; diff --git a/MMCore/CoreUtils.h b/MMCore/CoreUtils.h index d8b6718e5..6a592c423 100644 --- a/MMCore/CoreUtils.h +++ b/MMCore/CoreUtils.h @@ -72,6 +72,7 @@ inline std::string ToString(const MM::DeviceType d) case MM::SLMDevice: return "SLM"; case MM::HubDevice: return "Hub"; case MM::GalvoDevice: return "Galvo"; + case MM::DataStreamerDevice: return "DataStreamer"; } return "Invalid"; } diff --git a/MMCore/Devices/DataStreamerInstance.cpp b/MMCore/Devices/DataStreamerInstance.cpp new file mode 100644 index 000000000..66674582e --- /dev/null +++ b/MMCore/Devices/DataStreamerInstance.cpp @@ -0,0 +1,34 @@ +// PROJECT: Micro-Manager +// SUBSYSTEM: MMCore +// +// DESCRIPTION: Galvo device instance wrapper +// +// COPYRIGHT: University of California, San Francisco, 2014, +// All Rights reserved +// +// LICENSE: This file is distributed under the "Lesser GPL" (LGPL) license. +// License text is included with the source distribution. +// +// This file is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES. +// +// AUTHOR: Mark Tsuchida + +#include "DataStreamerInstance.h" + + +int DataStreamerInstance::GetBufferSize(unsigned& dataBufferSiize) { return GetImpl()->GetBufferSize(dataBufferSiize); } +std::unique_ptr DataStreamerInstance::GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize) { return GetImpl()->GetBuffer(expectedDataBufferSize,actualDataBufferSize); } +//int DataStreamerInstance::ProcessBuffer(std::unique_ptr& pDataBuffer) { return GetImpl()->ProcessBuffer(pDataBuffer); } +int DataStreamerInstance::ProcessBuffer(std::string str) { return GetImpl()->ProcessBuffer(str); } +int DataStreamerInstance::SetStreamParameters(bool stopOnOverflow, unsigned numberOfBuffers, double durationUs, double updatePeriodUs) { return GetImpl()->SetStreamParameters(stopOnOverflow, numberOfBuffers, durationUs, updatePeriodUs); } +int DataStreamerInstance::GetStreamParameters(bool& stopOnOverflow, unsigned& numberOfBuffers, double& durationUs, double& updatePeriodUs) { return GetImpl()->GetStreamParameters(stopOnOverflow,numberOfBuffers,durationUs,updatePeriodUs); } +int DataStreamerInstance::StartStream() { return GetImpl()->StartStream(); } +int DataStreamerInstance::StopStream() { return GetImpl()->StopStream(); } +int DataStreamerInstance::IsStreaming(unsigned& isStreaming) { return GetImpl()->IsStreaming(isStreaming); } + diff --git a/MMCore/Devices/DataStreamerInstance.h b/MMCore/Devices/DataStreamerInstance.h new file mode 100644 index 000000000..594bfcb15 --- /dev/null +++ b/MMCore/Devices/DataStreamerInstance.h @@ -0,0 +1,47 @@ +// PROJECT: Micro-Manager +// SUBSYSTEM: MMCore +// +// COPYRIGHT: University of California, San Francisco, 2014, +// All Rights reserved +// +// LICENSE: This file is distributed under the "Lesser GPL" (LGPL) license. +// License text is included with the source distribution. +// +// This file is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +// +// IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES. +// +// AUTHOR: Mark Tsuchida + +#pragma once + +#include "DeviceInstanceBase.h" + + +class DataStreamerInstance : public DeviceInstanceBase +{ +public: + DataStreamerInstance(CMMCore* core, + boost::shared_ptr adapter, + const std::string& name, + MM::Device* pDevice, + DeleteDeviceFunction deleteFunction, + const std::string& label, + mm::logging::Logger deviceLogger, + mm::logging::Logger coreLogger) : + DeviceInstanceBase(core, adapter, name, pDevice, deleteFunction, label, deviceLogger, coreLogger) + {} + + int GetBufferSize(unsigned& dataBufferSiize); + std::unique_ptr GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize); + int ProcessBuffer(std::string str); + int SetStreamParameters(bool stopOnOverflow, unsigned numberOfBuffers, double durationUs, double updatePeriodUs); + int GetStreamParameters(bool& stopOnOverflow, unsigned& numberOfBuffers, double& durationUs, double& updatePeriodUs); + int StartStream(); + int StopStream(); + int IsStreaming(unsigned& isStreaming); +}; diff --git a/MMCore/Devices/DeviceInstances.h b/MMCore/Devices/DeviceInstances.h index 8dfacf4d7..70d7e894d 100644 --- a/MMCore/Devices/DeviceInstances.h +++ b/MMCore/Devices/DeviceInstances.h @@ -32,4 +32,5 @@ #include "MagnifierInstance.h" #include "SLMInstance.h" #include "GalvoInstance.h" +#include "DataStreamerInstance.h" #include "HubInstance.h" diff --git a/MMCore/LoadableModules/LoadedDeviceAdapter.cpp b/MMCore/LoadableModules/LoadedDeviceAdapter.cpp index caf2a3404..389fd207c 100644 --- a/MMCore/LoadableModules/LoadedDeviceAdapter.cpp +++ b/MMCore/LoadableModules/LoadedDeviceAdapter.cpp @@ -183,6 +183,8 @@ LoadedDeviceAdapter::LoadDevice(CMMCore* core, const std::string& name, return std::make_shared(core, shared_this, name, pDevice, deleter, label, deviceLogger, coreLogger); case MM::GalvoDevice: return std::make_shared(core, shared_this, name, pDevice, deleter, label, deviceLogger, coreLogger); + case MM::DataStreamerDevice: + return std::make_shared(core, shared_this, name, pDevice, deleter, label, deviceLogger, coreLogger); case MM::HubDevice: return std::make_shared(core, shared_this, name, pDevice, deleter, label, deviceLogger, coreLogger); default: diff --git a/MMCore/MMCore.cpp b/MMCore/MMCore.cpp index eb55d5391..0336b289f 100644 --- a/MMCore/MMCore.cpp +++ b/MMCore/MMCore.cpp @@ -6411,6 +6411,97 @@ string CMMCore::getGalvoChannel(const char* deviceLabel) throw (CMMError) /* SYSTEM STATE */ +/** +* Start acquisition with the specified data streamer. +*/ +void CMMCore::startStream(const char* dataStreamerLabel) throw (CMMError) +{ + boost::shared_ptr pDataStreamer = + deviceManager_->GetDeviceOfType(dataStreamerLabel); + if (pDataStreamer) + { + mm::DeviceModuleLockGuard guard(pDataStreamer); + int ret = pDataStreamer->StartStream(); + if (ret != DEVICE_OK) + { + logError("CMMCore::startStream()", getDeviceErrorText(ret, pDataStreamer).c_str()); + throw CMMError(getDeviceErrorText(ret, pDataStreamer).c_str(), MMERR_DEVICE_GENERIC); + } + } +} + +/** +* Stop acquisition with the specified data streamer. +*/ +void CMMCore::stopStream(const char* dataStreamerLabel) throw (CMMError) +{ + boost::shared_ptr pDataStreamer = + deviceManager_->GetDeviceOfType(dataStreamerLabel); + if (pDataStreamer) + { + mm::DeviceModuleLockGuard guard(pDataStreamer); + int ret = pDataStreamer->StopStream(); + if (ret != DEVICE_OK) + { + logError("CMMCore::startStream()", getDeviceErrorText(ret, pDataStreamer).c_str()); + throw CMMError(getDeviceErrorText(ret, pDataStreamer).c_str(), MMERR_DEVICE_GENERIC); + } + } +} + +/** + * Sets data streamer parameters + * @param label the data streamer device label + * @param stopOnOverflow stop streaming if circular streaming buffer overflows + * @param numberOfBlocks number of data blocks to collect + * @param durationUs collection duration in microseconds + * @param updatePeriodUs update period in microseconds + */ +void CMMCore::setStreamParameters(const char* dataStreamerLabel, bool stopOnOverflow, + unsigned numberOfBlocks, double durationUs, double updatePeriodUs) +{ + boost::shared_ptr pDataStreamer = + deviceManager_->GetDeviceOfType(dataStreamerLabel); + + LOG_DEBUG(coreLogger_) << "Setting stream parameters of " << dataStreamerLabel << + " to stopOnOverflow=" << stopOnOverflow << ", " << + "numberOfBlocks=" << numberOfBlocks << ", " << + "durationUs=" << durationUs << ", " << + "updatePeriodUs=" << updatePeriodUs; + + mm::DeviceModuleLockGuard guard(pDataStreamer); + int ret = pDataStreamer->SetStreamParameters(stopOnOverflow, numberOfBlocks, durationUs, updatePeriodUs); + if (ret != DEVICE_OK) + { + logError(pDataStreamer->GetName().c_str(), getDeviceErrorText(ret, pDataStreamer).c_str()); + throw CMMError(getDeviceErrorText(ret, pDataStreamer).c_str(), MMERR_DEVICE_GENERIC); + } +} + +/** + * Obtains current parameters of the data streamer. + * @param label the data streamer device label + * @param stopOnOverflow a return parameter indicating if streaming should stop when acquisition buffer overflow takes place + * @param numberOfBlocks a return parameter that gives the number of blocks to be acquired + * @param durationUs a return parameter that gives duration of the stream + * @param updatePeriodUs a return parameter that gives the update rate of the stream + */ +void CMMCore::getStreamParameters(const char* label, bool& stopOnOverflow, + unsigned& numberOfBlocks, double& durationUs, double& updatePeriodUs) throw (CMMError) +{ + boost::shared_ptr pDataStreamer = + deviceManager_->GetDeviceOfType(label); + + mm::DeviceModuleLockGuard guard(pDataStreamer); + int ret = pDataStreamer->GetStreamParameters(stopOnOverflow, numberOfBlocks, durationUs, updatePeriodUs); + if (ret != DEVICE_OK) + { + logError(pDataStreamer->GetName().c_str(), getDeviceErrorText(ret, pDataStreamer).c_str()); + throw CMMError(getDeviceErrorText(ret, pDataStreamer).c_str(), MMERR_DEVICE_GENERIC); + } +} + + /** * Saves the current system state to a text file of the MM specific format. * The file records only read-write properties. diff --git a/MMCore/MMCore.h b/MMCore/MMCore.h index 71addcb64..bf0e512bc 100644 --- a/MMCore/MMCore.h +++ b/MMCore/MMCore.h @@ -609,6 +609,19 @@ class CMMCore std::string getGalvoChannel(const char* galvoLabel) throw (CMMError); ///@} + /** \name DataStreamer control. + * + * Control of data streaming devices. + */ + ///@{ + void startStream(const char* dataStreamerLabel) throw (CMMError); + void stopStream(const char* dataStreamerLabel) throw (CMMError); + void setStreamParameters(const char* dataStreamerLabel, bool stopOnOverflow, + unsigned numberOfBlocks, double durationUs, double updatePeriodUs) throw (CMMError); + void getStreamParameters(const char* label, bool& stopOnOverflow, + unsigned& numberOfBlocks, double& durationUs, double& updatePeriodUs) throw (CMMError); + ///@} + /** \name Device discovery. */ ///@{ bool supportsDeviceDetection(char* deviceLabel); diff --git a/MMCore/MMCore.vcxproj b/MMCore/MMCore.vcxproj index 0b2428216..804587313 100644 --- a/MMCore/MMCore.vcxproj +++ b/MMCore/MMCore.vcxproj @@ -79,6 +79,7 @@ + @@ -86,6 +87,7 @@ + @@ -117,6 +119,7 @@ + @@ -126,6 +129,7 @@ + diff --git a/MMCore/MMCore.vcxproj.filters b/MMCore/MMCore.vcxproj.filters index a01ede1fd..eefb7af96 100644 --- a/MMCore/MMCore.vcxproj.filters +++ b/MMCore/MMCore.vcxproj.filters @@ -141,6 +141,12 @@ Source Files + + Source Files + + + Source Files\Devices + @@ -305,5 +311,11 @@ Header Files + + Header Files + + + Header Files\Devices + - + \ No newline at end of file diff --git a/MMDevice/DeviceBase.h b/MMDevice/DeviceBase.h index 4321f5945..8290b44aa 100644 --- a/MMDevice/DeviceBase.h +++ b/MMDevice/DeviceBase.h @@ -34,6 +34,8 @@ #include "ModuleInterface.h" #include "DeviceThreads.h" +#include + #include #include @@ -2161,6 +2163,269 @@ class CGalvoBase : public CDeviceBase double GetYMinimum() { return 0.0;}; }; +typedef struct { + std::unique_ptr data; + unsigned int expectedSize; + unsigned int actualSize; +} data_block; + +class CircularBlockCollection { +public: + CircularBlockCollection(unsigned int maxNumberOfBlocks, bool stopOnOverflow) : + maxNumberOfBlocks_(0), + stopOnOverflow_(true), + overflowStatus_(false) + { + maxNumberOfBlocks_ = maxNumberOfBlocks; + cb_.set_capacity(maxNumberOfBlocks_); + cb_.empty(); + //boost::circular_buffer> cb_(maxNumberOfBlocks_); + stopOnOverflow_ = stopOnOverflow; + } + + ~CircularBlockCollection() {} + + void Add(std::unique_ptr &pDataBlock) + { + MMThreadGuard g(this->executeLock_); + if ((cb_.capacity() - cb_.size()) == 0) { + overflowStatus_ = true; + if (stopOnOverflow_) return; + cb_.empty(); + } + cb_.push_front(std::move(pDataBlock)); + } + + int GetCapacity() { + return cb_.capacity(); + } + + int GetSize() { + return cb_.size(); + } + + std::unique_ptr Remove() + { + MMThreadGuard g(this->executeLock_); + if (cb_.size() == 0) { + return 0; + } + else { + //std::unique_ptr dataBlock = std::move(cb_.at(0)); + //cb_.pop_back(); + return std::move(cb_.at(0)); + } + } + + void ResetOverflowStatus() + { + MMThreadGuard g(this->executeLock_); + overflowStatus_ = false; + } + + bool GetOverflowStatus() + { + MMThreadGuard g(this->executeLock_); + return overflowStatus_; + } +private: + boost::circular_buffer> cb_; + MMThreadLock executeLock_; + unsigned long maxNumberOfBlocks_; + bool stopOnOverflow_; + bool overflowStatus_; +}; + + +/** +* Base class for creating DataStreamer devices. +*/ +template +class CDataStreamerBase : public CDeviceBase +{ + friend class CircularBlockCollection; +public: + CDataStreamerBase() : numberOfBlocks_(1), durationUs_(1e6), updatePeriodUs_(1e5), + stopOnOverflow_(true), stopFlag_(false), + cbcData_(0), thdAcq_(0) + { + cbcData_ = new CircularBlockCollection(numberOfBlocks_, stopOnOverflow_); + thdAcq_ = new AcquisitionThread(this); + } + + virtual ~CDataStreamerBase() + { + if (thdAcq_->IsRunning()) { + thdAcq_->Stop(); + thdAcq_->wait(); + } + delete thdAcq_; + delete cbcData_; + } + + virtual int GetBufferSize(unsigned& dataBufferSiize) = 0; + virtual std::unique_ptr GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize) = 0; + //virtual int ProcessBuffer(std::unique_ptr &pDataBuffer) = 0; + virtual int ProcessBuffer(std::string str) = 0; + + virtual int SetStreamParameters(bool stopOnOverflow, unsigned numberOfBlocks, double durationUs, double updatePeriodUs) + { + if (thdAcq_->IsRunning()) { + return DEVICE_CAMERA_BUSY_ACQUIRING; + } + stopOnOverflow_ = stopOnOverflow, + numberOfBlocks_ = numberOfBlocks; + durationUs_ = durationUs; + updatePeriodUs_ = updatePeriodUs; + delete cbcData_; + cbcData_ = new CircularBlockCollection(numberOfBlocks_, stopOnOverflow_); + return DEVICE_OK; + } + + virtual int GetStreamParameters(bool& stopOnOverflow, unsigned& numberOfBlocks, double& durationUs, double& updatePeriodUs) + { + stopOnOverflow = stopOnOverflow_, + numberOfBlocks = numberOfBlocks_; + durationUs = durationUs_; + updatePeriodUs = updatePeriodUs_; + return DEVICE_OK; + } + + virtual int StartStream() + { + if (thdAcq_->IsRunning()) { + return DEVICE_CAMERA_BUSY_ACQUIRING; + } + thdAcq_->Start(); + return DEVICE_OK; + } + + virtual int StopStream() { + if (thdAcq_->IsRunning()) { + thdAcq_->Stop(); + thdAcq_->wait(); + } + return DEVICE_OK; + } + + virtual int IsStreaming(unsigned& isStreaming) { return isStreaming_; } + + //* GetDataCBC() { return this->cbcData_; } + + class AcquisitionThread : public MMDeviceThreadBase + { + friend class CDataStreamerBase; + friend class CircularBlockCollection; + public: + AcquisitionThread(CDataStreamerBase* p) : pDataStreamerBase_(0), isRunning_(false),stopFlag_(false) + { + pDataStreamerBase_ = p; + } + ~AcquisitionThread() {} + + void Start() { + this->SetIsRunning(true); + this->activate(); + } + + void Stop() { + if (this->GetIsRunning()) { + this->SetStopFlag(true); + } + } + + bool IsRunning() { + return this->GetIsRunning(); + } + + private: + CDataStreamerBase* pDataStreamerBase_; + bool isRunning_; + bool stopFlag_; + MMThreadLock stopLock_; + MMThreadLock isRunningLock_; + + // Provide description here + int svc(void) + { + int ret = 0; + unsigned int expectedDataSize, actualDataSize; + unsigned int blockCounter=0; + CircularBlockCollection* cbc = pDataStreamerBase_->cbcData_; + MM::MMTime startTime = pDataStreamerBase_->GetCurrentMMTime(); + MM::MMTime timeSinceStart = pDataStreamerBase_->GetCurrentMMTime() - startTime; + // check all stopping conditions + while (!(this->GetStopFlag() || //read externally set stop flag + blockCounter >= pDataStreamerBase_->numberOfBlocks_ || // stop if desired number of blocks have been collected + (cbc->GetOverflowStatus() && pDataStreamerBase_->stopOnOverflow_) || // buffer overflow + timeSinceStart > pDataStreamerBase_->durationUs_) ) { // timeout + Sleep(pDataStreamerBase_->updatePeriodUs_/1000); + timeSinceStart = pDataStreamerBase_->GetCurrentMMTime() - startTime; + ret = pDataStreamerBase_->GetBufferSize(expectedDataSize); + if (expectedDataSize != 0) { + std::unique_ptr newBlock(new data_block); + newBlock->data = pDataStreamerBase_->GetBuffer(expectedDataSize, actualDataSize); + newBlock->expectedSize = expectedDataSize; + newBlock->actualSize = actualDataSize; + cbc->Add(newBlock); + blockCounter++; + } + } + + std::stringstream ss; + ss << "Terminating acuisition thread for the following reason:"; + if (this->GetStopFlag()) { + ss << " user selection"; + } + else if (cbc->GetOverflowStatus() && pDataStreamerBase_->stopOnOverflow_) { + ss << " acquisition buffer overflow"; + } + else if (blockCounter >= pDataStreamerBase_->numberOfBlocks_) { + ss << "desired number of blocks (" << blockCounter << ") have been collected"; + } + else if (timeSinceStart > pDataStreamerBase_->durationUs_) { + ss << " acquisition time exceeded the set limit (" << pDataStreamerBase_->durationUs_ << " microseconds)"; + } + pDataStreamerBase_->LogMessage(ss.str(), true); + + this->SetIsRunning(false); + stopFlag_ = false; + return DEVICE_OK; + } + + void SetStopFlag(bool stop) { + MMThreadGuard g(this->stopLock_); + stopFlag_ = stop; + } + + bool GetStopFlag() { + MMThreadGuard g(this->stopLock_); + return stopFlag_; + } + + void SetIsRunning(bool isRunning) { + MMThreadGuard g(this->isRunningLock_); + isRunning_ = isRunning; + } + + bool GetIsRunning() { + MMThreadGuard g(this->isRunningLock_); + return isRunning_; + } + + }; + +private: + unsigned numberOfBlocks_; + double durationUs_; + double updatePeriodUs_; + bool stopOnOverflow_; + bool isStreaming_; + bool stopFlag_; + CircularBlockCollection* cbcData_; + AcquisitionThread* thdAcq_; +}; + /** * Base class for creating special HUB devices for managing device libraries. */ diff --git a/MMDevice/MMDevice.h b/MMDevice/MMDevice.h index 3990433d3..18eb7d9f0 100644 --- a/MMDevice/MMDevice.h +++ b/MMDevice/MMDevice.h @@ -1201,28 +1201,20 @@ namespace MM { * Receive data buffer from the hardware and place it at memory location * specified by pDataBuffer */ - virtual int GetBuffer(unsigned pDataBuffer) = 0; + virtual std::unique_ptr GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize) = 0; /** * Process the data buffer available at pDataBuffer and place * resulting multidimensional array at pProcessedArray */ - virtual int ProcessBuffer(unsigned pDataBuffer, unsigned pProcessedArray) = 0; - /** - * Get dimensionality of the array obtained as a result of processing data - */ - virtual int GetProcessedArrayDimension(unsigned& numberOfDimensions) = 0; - /** - * Get the shape of the array (how long the dimensions are) - */ - virtual int GetProcessedArrayShape(unsigned& shape) = 0; + //virtual int ProcessBuffer(std::unique_ptr& pDataBuffer) = 0; + virtual int ProcessBuffer(std::string str) = 0; // Calls that are implemented at the DeviceBase level and // remain the same for any DataStreamer device - virtual int SetStreamLength(unsigned numberOfBuffers, double timeUs) = 0; - virtual int GetStreamLength(unsigned& numberOfBuffers, double& timeUs) = 0; + virtual int SetStreamParameters(bool stopOnOverflow, unsigned numberOfBuffers, double durationUs, double updatePeriodUs) = 0; + virtual int GetStreamParameters(bool& stopOnOverflow, unsigned& numberOfBuffers, double& durationUs, double& updatePeriodUs) = 0; virtual int StartStream() = 0; virtual int StopStream() = 0; - virtual int PauseStream() = 0; virtual int IsStreaming(unsigned& isStreaming) = 0; }; From b620a8155d55fb5920a8a93a3d549939a6f71f1a Mon Sep 17 00:00:00 2001 From: "melnykov.artem" Date: Fri, 28 Oct 2022 14:56:03 -0500 Subject: [PATCH 03/14] Added processing thread --- DeviceAdapters/DemoCamera/DemoCamera.h | 19 +++-- MMCore/Devices/DataStreamerInstance.cpp | 3 +- MMCore/Devices/DataStreamerInstance.h | 2 +- MMDevice/DeviceBase.h | 98 +++++++++++++++++++++---- MMDevice/MMDevice.h | 3 +- 5 files changed, 98 insertions(+), 27 deletions(-) diff --git a/DeviceAdapters/DemoCamera/DemoCamera.h b/DeviceAdapters/DemoCamera/DemoCamera.h index 29b2a6f19..a57ac3d81 100644 --- a/DeviceAdapters/DemoCamera/DemoCamera.h +++ b/DeviceAdapters/DemoCamera/DemoCamera.h @@ -49,6 +49,8 @@ #define ERR_STAGE_MOVING 106 #define HUB_NOT_AVAILABLE 107 +int tempValue = 9; + const char* NoHubError = "Parent Hub not defined."; const char* g_DataStreamerDeviceName = "DSimulatedDataStreamer"; @@ -1232,20 +1234,21 @@ class DemoDataStreamer : public CDataStreamerBase // allocate a new data array and put data into it std::unique_ptr data(new char[expectedDataBufferSize]); - //data.operator[](0) = 69; - //data.operator[](1) = 79; - //data.operator[](2) = 89; - //data.operator[](3) = 99; - //data.operator[](4) = 109; + tempValue += 3; + data.operator[](0) = tempValue; + data.operator[](1) = tempValue+1; + data.operator[](2) = tempValue+2; + data.operator[](3) = tempValue+3; + data.operator[](4) = tempValue+4; actualDataBufferSize = 5; return data; } - int ProcessBuffer(std::string str) { -// int ProcessBuffer(std::unique_ptr &pDataBuffer) { - LogMessage(str.c_str(), false); + int ProcessBuffer(std::unique_ptr &pDataBuffer) { + LogMessage("HRYUK!!!-ProcessBuffer", false); + LogMessage(std::to_string(pDataBuffer.operator[](0)),true); return DEVICE_OK; } diff --git a/MMCore/Devices/DataStreamerInstance.cpp b/MMCore/Devices/DataStreamerInstance.cpp index 66674582e..803489ba6 100644 --- a/MMCore/Devices/DataStreamerInstance.cpp +++ b/MMCore/Devices/DataStreamerInstance.cpp @@ -24,8 +24,7 @@ int DataStreamerInstance::GetBufferSize(unsigned& dataBufferSiize) { return GetImpl()->GetBufferSize(dataBufferSiize); } std::unique_ptr DataStreamerInstance::GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize) { return GetImpl()->GetBuffer(expectedDataBufferSize,actualDataBufferSize); } -//int DataStreamerInstance::ProcessBuffer(std::unique_ptr& pDataBuffer) { return GetImpl()->ProcessBuffer(pDataBuffer); } -int DataStreamerInstance::ProcessBuffer(std::string str) { return GetImpl()->ProcessBuffer(str); } +int DataStreamerInstance::ProcessBuffer(std::unique_ptr& pDataBuffer) { return GetImpl()->ProcessBuffer(pDataBuffer); } int DataStreamerInstance::SetStreamParameters(bool stopOnOverflow, unsigned numberOfBuffers, double durationUs, double updatePeriodUs) { return GetImpl()->SetStreamParameters(stopOnOverflow, numberOfBuffers, durationUs, updatePeriodUs); } int DataStreamerInstance::GetStreamParameters(bool& stopOnOverflow, unsigned& numberOfBuffers, double& durationUs, double& updatePeriodUs) { return GetImpl()->GetStreamParameters(stopOnOverflow,numberOfBuffers,durationUs,updatePeriodUs); } int DataStreamerInstance::StartStream() { return GetImpl()->StartStream(); } diff --git a/MMCore/Devices/DataStreamerInstance.h b/MMCore/Devices/DataStreamerInstance.h index 594bfcb15..d10f4a796 100644 --- a/MMCore/Devices/DataStreamerInstance.h +++ b/MMCore/Devices/DataStreamerInstance.h @@ -38,7 +38,7 @@ class DataStreamerInstance : public DeviceInstanceBase int GetBufferSize(unsigned& dataBufferSiize); std::unique_ptr GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize); - int ProcessBuffer(std::string str); + int ProcessBuffer(std::unique_ptr& pDataBuffer); int SetStreamParameters(bool stopOnOverflow, unsigned numberOfBuffers, double durationUs, double updatePeriodUs); int GetStreamParameters(bool& stopOnOverflow, unsigned& numberOfBuffers, double& durationUs, double& updatePeriodUs); int StartStream(); diff --git a/MMDevice/DeviceBase.h b/MMDevice/DeviceBase.h index 8290b44aa..cc82e816b 100644 --- a/MMDevice/DeviceBase.h +++ b/MMDevice/DeviceBase.h @@ -2193,7 +2193,7 @@ class CircularBlockCollection { if (stopOnOverflow_) return; cb_.empty(); } - cb_.push_front(std::move(pDataBlock)); + cb_.push_back(std::move(pDataBlock)); } int GetCapacity() { @@ -2211,9 +2211,9 @@ class CircularBlockCollection { return 0; } else { - //std::unique_ptr dataBlock = std::move(cb_.at(0)); - //cb_.pop_back(); - return std::move(cb_.at(0)); + std::unique_ptr dataBlock = std::move(cb_.at(0)); + cb_.pop_front(); + return dataBlock; } } @@ -2245,12 +2245,13 @@ class CDataStreamerBase : public CDeviceBase { friend class CircularBlockCollection; public: - CDataStreamerBase() : numberOfBlocks_(1), durationUs_(1e6), updatePeriodUs_(1e5), - stopOnOverflow_(true), stopFlag_(false), - cbcData_(0), thdAcq_(0) + CDataStreamerBase() : numberOfBlocks_(1), durationUs_(1e6), updatePeriodUs_(1e5), + stopOnOverflow_(true), stopFlag_(false), + cbcData_(0), thdAcq_(0) { cbcData_ = new CircularBlockCollection(numberOfBlocks_, stopOnOverflow_); thdAcq_ = new AcquisitionThread(this); + thdProc_ = new ProcessingThread(this); } virtual ~CDataStreamerBase() @@ -2259,14 +2260,17 @@ class CDataStreamerBase : public CDeviceBase thdAcq_->Stop(); thdAcq_->wait(); } + if (thdProc_->IsRunning()) { + thdProc_->wait(); + } delete thdAcq_; + delete thdProc_; delete cbcData_; } virtual int GetBufferSize(unsigned& dataBufferSiize) = 0; virtual std::unique_ptr GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize) = 0; - //virtual int ProcessBuffer(std::unique_ptr &pDataBuffer) = 0; - virtual int ProcessBuffer(std::string str) = 0; + virtual int ProcessBuffer(std::unique_ptr& pDataBuffer) = 0; virtual int SetStreamParameters(bool stopOnOverflow, unsigned numberOfBlocks, double durationUs, double updatePeriodUs) { @@ -2274,7 +2278,7 @@ class CDataStreamerBase : public CDeviceBase return DEVICE_CAMERA_BUSY_ACQUIRING; } stopOnOverflow_ = stopOnOverflow, - numberOfBlocks_ = numberOfBlocks; + numberOfBlocks_ = numberOfBlocks; durationUs_ = durationUs; updatePeriodUs_ = updatePeriodUs; delete cbcData_; @@ -2285,7 +2289,7 @@ class CDataStreamerBase : public CDeviceBase virtual int GetStreamParameters(bool& stopOnOverflow, unsigned& numberOfBlocks, double& durationUs, double& updatePeriodUs) { stopOnOverflow = stopOnOverflow_, - numberOfBlocks = numberOfBlocks_; + numberOfBlocks = numberOfBlocks_; durationUs = durationUs_; updatePeriodUs = updatePeriodUs_; return DEVICE_OK; @@ -2293,10 +2297,11 @@ class CDataStreamerBase : public CDeviceBase virtual int StartStream() { - if (thdAcq_->IsRunning()) { + if (thdAcq_->IsRunning() || thdProc_->IsRunning()) { return DEVICE_CAMERA_BUSY_ACQUIRING; } thdAcq_->Start(); + thdProc_->Start(); return DEVICE_OK; } @@ -2305,13 +2310,14 @@ class CDataStreamerBase : public CDeviceBase thdAcq_->Stop(); thdAcq_->wait(); } + if (thdProc_->IsRunning()) { + thdProc_->wait(); + } return DEVICE_OK; } virtual int IsStreaming(unsigned& isStreaming) { return isStreaming_; } - //* GetDataCBC() { return this->cbcData_; } - class AcquisitionThread : public MMDeviceThreadBase { friend class CDataStreamerBase; @@ -2415,6 +2421,69 @@ class CDataStreamerBase : public CDeviceBase }; + class ProcessingThread : public MMDeviceThreadBase + { + friend class CDataStreamerBase; + friend class CircularBlockCollection; + friend class AcquisitionThread; + public: + ProcessingThread(CDataStreamerBase* p) : pDataStreamerBase_(0), isRunning_(false) + { + pDataStreamerBase_ = p; + } + ~ProcessingThread() {} + + void Start() { + this->SetIsRunning(true); + this->activate(); + } + + bool IsRunning() { + return this->GetIsRunning(); + } + + private: + CDataStreamerBase* pDataStreamerBase_; + AcquisitionThread* acq_; + bool isRunning_; + MMThreadLock isRunningLock_; + + // Provide description here + int svc(void) + { + int ret = 0; + CircularBlockCollection* cbc = pDataStreamerBase_->cbcData_; + AcquisitionThread* acq = pDataStreamerBase_->thdAcq_; + // give the device time to acquire data + Sleep(pDataStreamerBase_->updatePeriodUs_ / 1000); + // run while the acquisition thread is active or + // there is unprocessed data in the circular acquisition buffer + while (acq->GetIsRunning() || cbc->GetSize() != 0) { + Sleep(pDataStreamerBase_->updatePeriodUs_ / 1000); + if (cbc->GetSize() != 0) { + std::unique_ptr newBlock = cbc->Remove(); + ret = pDataStreamerBase_->ProcessBuffer(std::move(newBlock->data)); + } + } + + pDataStreamerBase_->LogMessage("Terminating processing thread.", true); + + this->SetIsRunning(false); + return DEVICE_OK; + } + + void SetIsRunning(bool isRunning) { + MMThreadGuard g(this->isRunningLock_); + isRunning_ = isRunning; + } + + bool GetIsRunning() { + MMThreadGuard g(this->isRunningLock_); + return isRunning_; + } + + }; + private: unsigned numberOfBlocks_; double durationUs_; @@ -2424,6 +2493,7 @@ class CDataStreamerBase : public CDeviceBase bool stopFlag_; CircularBlockCollection* cbcData_; AcquisitionThread* thdAcq_; + ProcessingThread* thdProc_; }; /** diff --git a/MMDevice/MMDevice.h b/MMDevice/MMDevice.h index 18eb7d9f0..a71a5edc4 100644 --- a/MMDevice/MMDevice.h +++ b/MMDevice/MMDevice.h @@ -1206,8 +1206,7 @@ namespace MM { * Process the data buffer available at pDataBuffer and place * resulting multidimensional array at pProcessedArray */ - //virtual int ProcessBuffer(std::unique_ptr& pDataBuffer) = 0; - virtual int ProcessBuffer(std::string str) = 0; + virtual int ProcessBuffer(std::unique_ptr& pDataBuffer) = 0; // Calls that are implemented at the DeviceBase level and // remain the same for any DataStreamer device From 064198545154980af5df21ec3c25ad65ab361e46 Mon Sep 17 00:00:00 2001 From: "melnykov.artem" Date: Sun, 30 Oct 2022 17:21:34 -0500 Subject: [PATCH 04/14] Implemented setting circular buffer capacity --- DeviceAdapters/DemoCamera/DemoCamera.h | 2 +- MMCore/Devices/DataStreamerInstance.cpp | 2 ++ MMCore/Devices/DataStreamerInstance.h | 4 ++- MMCore/MMCore.cpp | 41 +++++++++++++++++++++++++ MMCore/MMCore.h | 2 ++ MMDevice/DeviceBase.h | 29 ++++++++++++----- MMDevice/MMDevice.h | 2 ++ 7 files changed, 73 insertions(+), 9 deletions(-) diff --git a/DeviceAdapters/DemoCamera/DemoCamera.h b/DeviceAdapters/DemoCamera/DemoCamera.h index a57ac3d81..2bd75bcd9 100644 --- a/DeviceAdapters/DemoCamera/DemoCamera.h +++ b/DeviceAdapters/DemoCamera/DemoCamera.h @@ -1226,7 +1226,7 @@ class DemoDataStreamer : public CDataStreamerBase } - int GetBufferSize(unsigned& dataBufferSize) { dataBufferSize = 5; LogMessage("HRYUK!!!-GetBufferSize", false); return DEVICE_OK; } + int GetBufferSize(unsigned& dataBufferSize) { dataBufferSize = 100*1024*1024; LogMessage("HRYUK!!!-GetBufferSize", false); return DEVICE_OK; } std::unique_ptr GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize) { diff --git a/MMCore/Devices/DataStreamerInstance.cpp b/MMCore/Devices/DataStreamerInstance.cpp index 803489ba6..46631de8a 100644 --- a/MMCore/Devices/DataStreamerInstance.cpp +++ b/MMCore/Devices/DataStreamerInstance.cpp @@ -30,4 +30,6 @@ int DataStreamerInstance::GetStreamParameters(bool& stopOnOverflow, unsigned& nu int DataStreamerInstance::StartStream() { return GetImpl()->StartStream(); } int DataStreamerInstance::StopStream() { return GetImpl()->StopStream(); } int DataStreamerInstance::IsStreaming(unsigned& isStreaming) { return GetImpl()->IsStreaming(isStreaming); } +int DataStreamerInstance::SetCircularAcquisitionBufferCapacity(unsigned capacity) { return GetImpl()->SetCircularAcquisitionBufferCapacity(capacity); } +int DataStreamerInstance::GetCircularAcquisitionBufferCapacity(unsigned& capacity) { return GetImpl()->GetCircularAcquisitionBufferCapacity(capacity); } diff --git a/MMCore/Devices/DataStreamerInstance.h b/MMCore/Devices/DataStreamerInstance.h index d10f4a796..da2d975f9 100644 --- a/MMCore/Devices/DataStreamerInstance.h +++ b/MMCore/Devices/DataStreamerInstance.h @@ -43,5 +43,7 @@ class DataStreamerInstance : public DeviceInstanceBase int GetStreamParameters(bool& stopOnOverflow, unsigned& numberOfBuffers, double& durationUs, double& updatePeriodUs); int StartStream(); int StopStream(); - int IsStreaming(unsigned& isStreaming); + int IsStreaming(unsigned& isStreaming); + int SetCircularAcquisitionBufferCapacity(unsigned capacity); + int GetCircularAcquisitionBufferCapacity(unsigned& capacity); }; diff --git a/MMCore/MMCore.cpp b/MMCore/MMCore.cpp index 0336b289f..0367082a7 100644 --- a/MMCore/MMCore.cpp +++ b/MMCore/MMCore.cpp @@ -6501,6 +6501,47 @@ void CMMCore::getStreamParameters(const char* label, bool& stopOnOverflow, } } +/** + * Sets circular acquisition buffer capacity + * @param label the data streamer device label + * @param capacity number of data blocks in the circular buffer + */ +void CMMCore::setCircularAcquisitionBufferCapacity(const char* dataStreamerLabel, unsigned capacity) +{ + boost::shared_ptr pDataStreamer = + deviceManager_->GetDeviceOfType(dataStreamerLabel); + + LOG_DEBUG(coreLogger_) << "Setting circular acquisition buffer capacity to" << capacity; + + mm::DeviceModuleLockGuard guard(pDataStreamer); + int ret = pDataStreamer->SetCircularAcquisitionBufferCapacity(capacity); + if (ret != DEVICE_OK) + { + logError(pDataStreamer->GetName().c_str(), getDeviceErrorText(ret, pDataStreamer).c_str()); + throw CMMError(getDeviceErrorText(ret, pDataStreamer).c_str(), MMERR_DEVICE_GENERIC); + } +} + +/** + * Returns circular acquisition buffer capacity + * @param label the data streamer device label + */ +long CMMCore::getCircularAcquisitionBufferCapacity(const char* dataStreamerLabel) +{ + boost::shared_ptr pDataStreamer = + deviceManager_->GetDeviceOfType(dataStreamerLabel); + + mm::DeviceModuleLockGuard guard(pDataStreamer); + long capacity; + int ret = pDataStreamer->GetCircularAcquisitionBufferCapacity((unsigned&)capacity); + if (ret <= 0) + { + logError(pDataStreamer->GetName().c_str(), getDeviceErrorText(ret, pDataStreamer).c_str()); + throw CMMError(getDeviceErrorText(ret, pDataStreamer).c_str(), MMERR_DEVICE_GENERIC); + } + return capacity; +} + /** * Saves the current system state to a text file of the MM specific format. diff --git a/MMCore/MMCore.h b/MMCore/MMCore.h index bf0e512bc..6ba939bd1 100644 --- a/MMCore/MMCore.h +++ b/MMCore/MMCore.h @@ -620,6 +620,8 @@ class CMMCore unsigned numberOfBlocks, double durationUs, double updatePeriodUs) throw (CMMError); void getStreamParameters(const char* label, bool& stopOnOverflow, unsigned& numberOfBlocks, double& durationUs, double& updatePeriodUs) throw (CMMError); + void setCircularAcquisitionBufferCapacity(const char* dataStreamerLabel, unsigned capacity) throw (CMMError); + long getCircularAcquisitionBufferCapacity(const char* dataStreamerLabel) throw (CMMError); ///@} /** \name Device discovery. */ diff --git a/MMDevice/DeviceBase.h b/MMDevice/DeviceBase.h index cc82e816b..54ee7524a 100644 --- a/MMDevice/DeviceBase.h +++ b/MMDevice/DeviceBase.h @@ -2247,9 +2247,9 @@ class CDataStreamerBase : public CDeviceBase public: CDataStreamerBase() : numberOfBlocks_(1), durationUs_(1e6), updatePeriodUs_(1e5), stopOnOverflow_(true), stopFlag_(false), - cbcData_(0), thdAcq_(0) + cbcData_(0), cbcCapacity_(10), thdAcq_(0), thdProc_(0) { - cbcData_ = new CircularBlockCollection(numberOfBlocks_, stopOnOverflow_); + cbcData_ = new CircularBlockCollection(cbcCapacity_, stopOnOverflow_); thdAcq_ = new AcquisitionThread(this); thdProc_ = new ProcessingThread(this); } @@ -2277,19 +2277,19 @@ class CDataStreamerBase : public CDeviceBase if (thdAcq_->IsRunning()) { return DEVICE_CAMERA_BUSY_ACQUIRING; } - stopOnOverflow_ = stopOnOverflow, - numberOfBlocks_ = numberOfBlocks; + stopOnOverflow_ = stopOnOverflow; + numberOfBlocks_ = numberOfBlocks; durationUs_ = durationUs; updatePeriodUs_ = updatePeriodUs; delete cbcData_; - cbcData_ = new CircularBlockCollection(numberOfBlocks_, stopOnOverflow_); + cbcData_ = new CircularBlockCollection(cbcCapacity_, stopOnOverflow_); return DEVICE_OK; } virtual int GetStreamParameters(bool& stopOnOverflow, unsigned& numberOfBlocks, double& durationUs, double& updatePeriodUs) { - stopOnOverflow = stopOnOverflow_, - numberOfBlocks = numberOfBlocks_; + stopOnOverflow = stopOnOverflow_; + numberOfBlocks = numberOfBlocks_; durationUs = durationUs_; updatePeriodUs = updatePeriodUs_; return DEVICE_OK; @@ -2316,6 +2316,20 @@ class CDataStreamerBase : public CDeviceBase return DEVICE_OK; } + virtual int SetCircularAcquisitionBufferCapacity(unsigned capacity) { + if (thdAcq_->IsRunning() || thdProc_->IsRunning()) { + return DEVICE_CAMERA_BUSY_ACQUIRING; + } + cbcCapacity_ = capacity; + delete cbcData_; + cbcData_ = new CircularBlockCollection(cbcCapacity_, stopOnOverflow_); + return DEVICE_OK; + } + + virtual int GetCircularAcquisitionBufferCapacity(unsigned& capacity) { + return cbcCapacity_; + } + virtual int IsStreaming(unsigned& isStreaming) { return isStreaming_; } class AcquisitionThread : public MMDeviceThreadBase @@ -2492,6 +2506,7 @@ class CDataStreamerBase : public CDeviceBase bool isStreaming_; bool stopFlag_; CircularBlockCollection* cbcData_; + unsigned cbcCapacity_; AcquisitionThread* thdAcq_; ProcessingThread* thdProc_; }; diff --git a/MMDevice/MMDevice.h b/MMDevice/MMDevice.h index a71a5edc4..a7a117c3b 100644 --- a/MMDevice/MMDevice.h +++ b/MMDevice/MMDevice.h @@ -1215,6 +1215,8 @@ namespace MM { virtual int StartStream() = 0; virtual int StopStream() = 0; virtual int IsStreaming(unsigned& isStreaming) = 0; + virtual int SetCircularAcquisitionBufferCapacity(unsigned capacity) = 0; + virtual int GetCircularAcquisitionBufferCapacity(unsigned& capacity) = 0; }; /** From 0917430f91f8ae13bd7d5fb3efabadcca721332c Mon Sep 17 00:00:00 2001 From: "melnykov.artem" Date: Tue, 1 Nov 2022 18:50:30 -0500 Subject: [PATCH 05/14] Added dataSize to ProcessBuffer call and finished adding simulated DataStreamer --- DeviceAdapters/DemoCamera/DemoCamera.h | 64 +++++++++++++++++-------- MMCore/Devices/DataStreamerInstance.cpp | 2 +- MMCore/Devices/DataStreamerInstance.h | 2 +- MMDevice/DeviceBase.h | 4 +- MMDevice/MMDevice.h | 2 +- 5 files changed, 49 insertions(+), 25 deletions(-) diff --git a/DeviceAdapters/DemoCamera/DemoCamera.h b/DeviceAdapters/DemoCamera/DemoCamera.h index 2bd75bcd9..c0f4d09bd 100644 --- a/DeviceAdapters/DemoCamera/DemoCamera.h +++ b/DeviceAdapters/DemoCamera/DemoCamera.h @@ -38,6 +38,7 @@ #include #include #include +#include ////////////////////////////////////////////////////////////////////////////// // Error codes @@ -49,8 +50,6 @@ #define ERR_STAGE_MOVING 106 #define HUB_NOT_AVAILABLE 107 -int tempValue = 9; - const char* NoHubError = "Parent Hub not defined."; const char* g_DataStreamerDeviceName = "DSimulatedDataStreamer"; @@ -1205,7 +1204,8 @@ class DemoGalvo : public CGalvoBase, ImgManipulator class DemoDataStreamer : public CDataStreamerBase { public: - DemoDataStreamer() + DemoDataStreamer() : + mockDataSize_(1024*1024) { // parent ID display CreateHubIDProperty(); @@ -1213,10 +1213,21 @@ class DemoDataStreamer : public CDataStreamerBase ~DemoDataStreamer() {} int Initialize() { + // initialize mock data + mockData_ = new char[mockDataSize_]; + char val = 0; + for (int ii = 0; ii < mockDataSize_; ii++) { mockData_[ii] = val; val++; } + + writeFile_.open("C:\\temp\\mybinaryfile.txt", std::ios::out | std::ios::binary); + initialized_ = true; return DEVICE_OK; } - int Shutdown() { initialized_ = false; return DEVICE_OK; } + int Shutdown() { + writeFile_.close(); + initialized_ = false; + return DEVICE_OK; + } void GetName(char* pszName) const { CDeviceUtils::CopyLimitedString(pszName, g_DataStreamerDeviceName); @@ -1226,34 +1237,47 @@ class DemoDataStreamer : public CDataStreamerBase } - int GetBufferSize(unsigned& dataBufferSize) { dataBufferSize = 100*1024*1024; LogMessage("HRYUK!!!-GetBufferSize", false); return DEVICE_OK; } + int GetBufferSize(unsigned& dataBufferSize) { + LogMessage("Demo DataStreamer: calling GetBufferSize", true); + dataBufferSize = mockDataSize_; + return DEVICE_OK; + } std::unique_ptr GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize) { - LogMessage("HRYUK!!!-GetBuffer", false); - - // allocate a new data array and put data into it - std::unique_ptr data(new char[expectedDataBufferSize]); - tempValue += 3; - data.operator[](0) = tempValue; - data.operator[](1) = tempValue+1; - data.operator[](2) = tempValue+2; - data.operator[](3) = tempValue+3; - data.operator[](4) = tempValue+4; - - actualDataBufferSize = 5; + LogMessage("Demo DataStreamer: calling GetBuffer", true); + + if (expectedDataBufferSize <= mockDataSize_) { + actualDataBufferSize = expectedDataBufferSize; + } + else { + actualDataBufferSize = mockDataSize_; + } + // allocate a new data array and put data in it + std::unique_ptr data(new char[actualDataBufferSize]); + memcpy(data.get(), mockData_, actualDataBufferSize); return data; } - int ProcessBuffer(std::unique_ptr &pDataBuffer) { - LogMessage("HRYUK!!!-ProcessBuffer", false); - LogMessage(std::to_string(pDataBuffer.operator[](0)),true); + int ProcessBuffer(std::unique_ptr &pDataBuffer, unsigned dataSize) { + + LogMessage("Demo DataStreamer: calling ProcessBuffer", true); + + if (!writeFile_) { + LogMessage("Demo DataStreamer: unable to wite into a file during ProcessBuffer call", false); + return 0; + } + writeFile_.write(pDataBuffer.get(), dataSize); + return DEVICE_OK; } private: bool initialized_; + unsigned mockDataSize_; + char* mockData_; + std::ofstream writeFile_; MM::MMTime changedTime_; }; diff --git a/MMCore/Devices/DataStreamerInstance.cpp b/MMCore/Devices/DataStreamerInstance.cpp index 46631de8a..a6df38c4a 100644 --- a/MMCore/Devices/DataStreamerInstance.cpp +++ b/MMCore/Devices/DataStreamerInstance.cpp @@ -24,7 +24,7 @@ int DataStreamerInstance::GetBufferSize(unsigned& dataBufferSiize) { return GetImpl()->GetBufferSize(dataBufferSiize); } std::unique_ptr DataStreamerInstance::GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize) { return GetImpl()->GetBuffer(expectedDataBufferSize,actualDataBufferSize); } -int DataStreamerInstance::ProcessBuffer(std::unique_ptr& pDataBuffer) { return GetImpl()->ProcessBuffer(pDataBuffer); } +int DataStreamerInstance::ProcessBuffer(std::unique_ptr& pDataBuffer, unsigned dataSize) { return GetImpl()->ProcessBuffer(pDataBuffer, dataSize); } int DataStreamerInstance::SetStreamParameters(bool stopOnOverflow, unsigned numberOfBuffers, double durationUs, double updatePeriodUs) { return GetImpl()->SetStreamParameters(stopOnOverflow, numberOfBuffers, durationUs, updatePeriodUs); } int DataStreamerInstance::GetStreamParameters(bool& stopOnOverflow, unsigned& numberOfBuffers, double& durationUs, double& updatePeriodUs) { return GetImpl()->GetStreamParameters(stopOnOverflow,numberOfBuffers,durationUs,updatePeriodUs); } int DataStreamerInstance::StartStream() { return GetImpl()->StartStream(); } diff --git a/MMCore/Devices/DataStreamerInstance.h b/MMCore/Devices/DataStreamerInstance.h index da2d975f9..6996904cb 100644 --- a/MMCore/Devices/DataStreamerInstance.h +++ b/MMCore/Devices/DataStreamerInstance.h @@ -38,7 +38,7 @@ class DataStreamerInstance : public DeviceInstanceBase int GetBufferSize(unsigned& dataBufferSiize); std::unique_ptr GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize); - int ProcessBuffer(std::unique_ptr& pDataBuffer); + int ProcessBuffer(std::unique_ptr& pDataBuffer, unsigned dataSize); int SetStreamParameters(bool stopOnOverflow, unsigned numberOfBuffers, double durationUs, double updatePeriodUs); int GetStreamParameters(bool& stopOnOverflow, unsigned& numberOfBuffers, double& durationUs, double& updatePeriodUs); int StartStream(); diff --git a/MMDevice/DeviceBase.h b/MMDevice/DeviceBase.h index 54ee7524a..1c12624bb 100644 --- a/MMDevice/DeviceBase.h +++ b/MMDevice/DeviceBase.h @@ -2270,7 +2270,7 @@ class CDataStreamerBase : public CDeviceBase virtual int GetBufferSize(unsigned& dataBufferSiize) = 0; virtual std::unique_ptr GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize) = 0; - virtual int ProcessBuffer(std::unique_ptr& pDataBuffer) = 0; + virtual int ProcessBuffer(std::unique_ptr& pDataBuffer, unsigned dataSize) = 0; virtual int SetStreamParameters(bool stopOnOverflow, unsigned numberOfBlocks, double durationUs, double updatePeriodUs) { @@ -2476,7 +2476,7 @@ class CDataStreamerBase : public CDeviceBase Sleep(pDataStreamerBase_->updatePeriodUs_ / 1000); if (cbc->GetSize() != 0) { std::unique_ptr newBlock = cbc->Remove(); - ret = pDataStreamerBase_->ProcessBuffer(std::move(newBlock->data)); + ret = pDataStreamerBase_->ProcessBuffer(std::move(newBlock->data),newBlock->actualSize); } } diff --git a/MMDevice/MMDevice.h b/MMDevice/MMDevice.h index a7a117c3b..f2674d4d2 100644 --- a/MMDevice/MMDevice.h +++ b/MMDevice/MMDevice.h @@ -1206,7 +1206,7 @@ namespace MM { * Process the data buffer available at pDataBuffer and place * resulting multidimensional array at pProcessedArray */ - virtual int ProcessBuffer(std::unique_ptr& pDataBuffer) = 0; + virtual int ProcessBuffer(std::unique_ptr& pDataBuffer, unsigned dataSize) = 0; // Calls that are implemented at the DeviceBase level and // remain the same for any DataStreamer device From 122f63d42f35a54517fa928956990cce98e68d0a Mon Sep 17 00:00:00 2001 From: "melnykov.artem" Date: Sat, 5 Nov 2022 09:57:13 -0500 Subject: [PATCH 06/14] Removed unused CircularBlockCollection files (a remnant of early development) --- MMCore/CircularBlockCollection.cpp | 76 ------------------------------ MMCore/CircularBlockCollection.h | 56 ---------------------- MMCore/MMCore.vcxproj | 2 - MMCore/MMCore.vcxproj.filters | 6 --- 4 files changed, 140 deletions(-) delete mode 100644 MMCore/CircularBlockCollection.cpp delete mode 100644 MMCore/CircularBlockCollection.h diff --git a/MMCore/CircularBlockCollection.cpp b/MMCore/CircularBlockCollection.cpp deleted file mode 100644 index d62945a22..000000000 --- a/MMCore/CircularBlockCollection.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// FILE: CircularBlockCollection.cpp -// PROJECT: Micro-Manager -// SUBSYSTEM: MMCore -//----------------------------------------------------------------------------- -// DESCRIPTION: Implementation of circular buffer that also stores sizes -// of contained data blocks -// -// COPYRIGHT: Artem Melnykov, 2022 -// -// LICENSE: This file is distributed under the "Lesser GPL" (LGPL) license. -// License text is included with the source distribution. -// -// This file is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty -// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// -// IN NO EVENT SHALL THE COPYRIGHT OWNER OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES. -// -// AUTHOR: Artem Melnykov, melnykov.artem@gmail.com, 2022 -// - -#include "CircularBlockCollection.h" - - -CircularBlockCollection::CircularBlockCollection(unsigned int maxNumberOfBlocks, bool stopOnOverflow) : - maxNumberOfBlocks_(0), - stopOnOverflow_(true), - overflowStatus_(false) -{ - boost::circular_buffer cb_(maxNumberOfBlocks); - maxNumberOfBlocks_ = maxNumberOfBlocks; - stopOnOverflow_ = stopOnOverflow; -} - -CircularBlockCollection::~CircularBlockCollection() -{ -} - -void CircularBlockCollection::Add(BLOCK dataBlock) -{ - MMThreadGuard g(this->executeLock_); - if (cb_.capacity() - cb_.size() == 0) { - overflowStatus_ = true; - if (stopOnOverflow_) return; - cb_.empty(); - } - cb_.push_front(dataBlock); -} - -BLOCK CircularBlockCollection::Remove() -{ - MMThreadGuard g(this->executeLock_); - if (cb_.size() == 0) { - return BLOCK(); - } - else { - BLOCK dataBlock = BLOCK(cb_.at(0)); - cb_.pop_back(); - return dataBlock; - } -} - -void CircularBlockCollection::ResetOverflowStatus() -{ - MMThreadGuard g(this->executeLock_); - overflowStatus_ = false; -} - -bool CircularBlockCollection::GetOverflowStatus() -{ - MMThreadGuard g(this->executeLock_); - return overflowStatus_; -} \ No newline at end of file diff --git a/MMCore/CircularBlockCollection.h b/MMCore/CircularBlockCollection.h deleted file mode 100644 index 26e201517..000000000 --- a/MMCore/CircularBlockCollection.h +++ /dev/null @@ -1,56 +0,0 @@ -/////////////////////////////////////////////////////////////////////////////// -// FILE: CircularBlockCollection.h -// PROJECT: Micro-Manager -// SUBSYSTEM: MMCore -//----------------------------------------------------------------------------- -// DESCRIPTION: Implementation of circular buffer that also stores sizes -// of contained data blocks -// -// COPYRIGHT: Artem Melnykov, 2022 -// -// LICENSE: This file is distributed under the "Lesser GPL" (LGPL) license. -// License text is included with the source distribution. -// -// This file is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty -// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// -// IN NO EVENT SHALL THE COPYRIGHT OWNER OR -// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES. -// -// AUTHOR: Artem Melnykov, melnykov.artem@gmail.com, 2022 -// - -#pragma once - -#include -#include - -#include "../MMDevice/DeviceThreads.h" - -typedef struct { - boost::shared_ptr data; - unsigned int dataSize; -} BLOCK; - - -class CircularBlockCollection -{ -public: - CircularBlockCollection(unsigned int maxNumberOfBlocks, bool stopOnOverflow); - ~CircularBlockCollection(); - - bool GetOverflowStatus(); - void ResetOverflowStatus(); - - void Add(BLOCK dataBlock); - BLOCK Remove(); - -private: - boost::circular_buffer cb_; - MMThreadLock executeLock_; - unsigned long maxNumberOfBlocks_; - bool stopOnOverflow_; - bool overflowStatus_; -}; diff --git a/MMCore/MMCore.vcxproj b/MMCore/MMCore.vcxproj index 804587313..c5369b973 100644 --- a/MMCore/MMCore.vcxproj +++ b/MMCore/MMCore.vcxproj @@ -79,7 +79,6 @@ - @@ -119,7 +118,6 @@ - diff --git a/MMCore/MMCore.vcxproj.filters b/MMCore/MMCore.vcxproj.filters index eefb7af96..65f1987a8 100644 --- a/MMCore/MMCore.vcxproj.filters +++ b/MMCore/MMCore.vcxproj.filters @@ -141,9 +141,6 @@ Source Files - - Source Files - Source Files\Devices @@ -311,9 +308,6 @@ Header Files - - Header Files - Header Files\Devices From 4e63c34a97ee9407736d7f5107f9328a7c71fd4e Mon Sep 17 00:00:00 2001 From: "melnykov.artem" Date: Sat, 5 Nov 2022 16:21:44 -0500 Subject: [PATCH 07/14] Brought this branch up to date with main --- MMCore/Devices/DataStreamerInstance.h | 2 +- MMCore/MMCore.cpp | 12 ++++++------ MMDevice/DeviceBase.h | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/MMCore/Devices/DataStreamerInstance.h b/MMCore/Devices/DataStreamerInstance.h index 6996904cb..b0db26f21 100644 --- a/MMCore/Devices/DataStreamerInstance.h +++ b/MMCore/Devices/DataStreamerInstance.h @@ -26,7 +26,7 @@ class DataStreamerInstance : public DeviceInstanceBase { public: DataStreamerInstance(CMMCore* core, - boost::shared_ptr adapter, + std::shared_ptr adapter, const std::string& name, MM::Device* pDevice, DeleteDeviceFunction deleteFunction, diff --git a/MMCore/MMCore.cpp b/MMCore/MMCore.cpp index 0367082a7..941e13fe2 100644 --- a/MMCore/MMCore.cpp +++ b/MMCore/MMCore.cpp @@ -6416,7 +6416,7 @@ string CMMCore::getGalvoChannel(const char* deviceLabel) throw (CMMError) */ void CMMCore::startStream(const char* dataStreamerLabel) throw (CMMError) { - boost::shared_ptr pDataStreamer = + std::shared_ptr pDataStreamer = deviceManager_->GetDeviceOfType(dataStreamerLabel); if (pDataStreamer) { @@ -6435,7 +6435,7 @@ void CMMCore::startStream(const char* dataStreamerLabel) throw (CMMError) */ void CMMCore::stopStream(const char* dataStreamerLabel) throw (CMMError) { - boost::shared_ptr pDataStreamer = + std::shared_ptr pDataStreamer = deviceManager_->GetDeviceOfType(dataStreamerLabel); if (pDataStreamer) { @@ -6460,7 +6460,7 @@ void CMMCore::stopStream(const char* dataStreamerLabel) throw (CMMError) void CMMCore::setStreamParameters(const char* dataStreamerLabel, bool stopOnOverflow, unsigned numberOfBlocks, double durationUs, double updatePeriodUs) { - boost::shared_ptr pDataStreamer = + std::shared_ptr pDataStreamer = deviceManager_->GetDeviceOfType(dataStreamerLabel); LOG_DEBUG(coreLogger_) << "Setting stream parameters of " << dataStreamerLabel << @@ -6489,7 +6489,7 @@ void CMMCore::setStreamParameters(const char* dataStreamerLabel, bool stopOnOver void CMMCore::getStreamParameters(const char* label, bool& stopOnOverflow, unsigned& numberOfBlocks, double& durationUs, double& updatePeriodUs) throw (CMMError) { - boost::shared_ptr pDataStreamer = + std::shared_ptr pDataStreamer = deviceManager_->GetDeviceOfType(label); mm::DeviceModuleLockGuard guard(pDataStreamer); @@ -6508,7 +6508,7 @@ void CMMCore::getStreamParameters(const char* label, bool& stopOnOverflow, */ void CMMCore::setCircularAcquisitionBufferCapacity(const char* dataStreamerLabel, unsigned capacity) { - boost::shared_ptr pDataStreamer = + std::shared_ptr pDataStreamer = deviceManager_->GetDeviceOfType(dataStreamerLabel); LOG_DEBUG(coreLogger_) << "Setting circular acquisition buffer capacity to" << capacity; @@ -6528,7 +6528,7 @@ void CMMCore::setCircularAcquisitionBufferCapacity(const char* dataStreamerLabel */ long CMMCore::getCircularAcquisitionBufferCapacity(const char* dataStreamerLabel) { - boost::shared_ptr pDataStreamer = + std::shared_ptr pDataStreamer = deviceManager_->GetDeviceOfType(dataStreamerLabel); mm::DeviceModuleLockGuard guard(pDataStreamer); diff --git a/MMDevice/DeviceBase.h b/MMDevice/DeviceBase.h index 1c12624bb..244a08326 100644 --- a/MMDevice/DeviceBase.h +++ b/MMDevice/DeviceBase.h @@ -2378,7 +2378,7 @@ class CDataStreamerBase : public CDeviceBase while (!(this->GetStopFlag() || //read externally set stop flag blockCounter >= pDataStreamerBase_->numberOfBlocks_ || // stop if desired number of blocks have been collected (cbc->GetOverflowStatus() && pDataStreamerBase_->stopOnOverflow_) || // buffer overflow - timeSinceStart > pDataStreamerBase_->durationUs_) ) { // timeout + timeSinceStart > MM::MMTime(pDataStreamerBase_->durationUs_)) ) { // timeout Sleep(pDataStreamerBase_->updatePeriodUs_/1000); timeSinceStart = pDataStreamerBase_->GetCurrentMMTime() - startTime; ret = pDataStreamerBase_->GetBufferSize(expectedDataSize); @@ -2403,7 +2403,7 @@ class CDataStreamerBase : public CDeviceBase else if (blockCounter >= pDataStreamerBase_->numberOfBlocks_) { ss << "desired number of blocks (" << blockCounter << ") have been collected"; } - else if (timeSinceStart > pDataStreamerBase_->durationUs_) { + else if (timeSinceStart > MM::MMTime(pDataStreamerBase_->durationUs_)) { ss << " acquisition time exceeded the set limit (" << pDataStreamerBase_->durationUs_ << " microseconds)"; } pDataStreamerBase_->LogMessage(ss.str(), true); From 473f4f123e73af74d7e3fd315e04b9e2b96043ef Mon Sep 17 00:00:00 2001 From: "melnykov.artem" Date: Tue, 15 Nov 2022 21:28:24 -0600 Subject: [PATCH 08/14] Fixed getStreamParameters --- MMCore/MMCore.cpp | 10 ++++++---- MMCore/MMCore.h | 4 ++-- MMCoreJ_wrap/MMCoreJ.i | 4 ++++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/MMCore/MMCore.cpp b/MMCore/MMCore.cpp index 941e13fe2..f95f0bf29 100644 --- a/MMCore/MMCore.cpp +++ b/MMCore/MMCore.cpp @@ -6458,7 +6458,7 @@ void CMMCore::stopStream(const char* dataStreamerLabel) throw (CMMError) * @param updatePeriodUs update period in microseconds */ void CMMCore::setStreamParameters(const char* dataStreamerLabel, bool stopOnOverflow, - unsigned numberOfBlocks, double durationUs, double updatePeriodUs) + int numberOfBlocks, double durationUs, double updatePeriodUs) { std::shared_ptr pDataStreamer = deviceManager_->GetDeviceOfType(dataStreamerLabel); @@ -6470,7 +6470,7 @@ void CMMCore::setStreamParameters(const char* dataStreamerLabel, bool stopOnOver "updatePeriodUs=" << updatePeriodUs; mm::DeviceModuleLockGuard guard(pDataStreamer); - int ret = pDataStreamer->SetStreamParameters(stopOnOverflow, numberOfBlocks, durationUs, updatePeriodUs); + int ret = pDataStreamer->SetStreamParameters(stopOnOverflow, (unsigned)numberOfBlocks, durationUs, updatePeriodUs); if (ret != DEVICE_OK) { logError(pDataStreamer->GetName().c_str(), getDeviceErrorText(ret, pDataStreamer).c_str()); @@ -6487,18 +6487,20 @@ void CMMCore::setStreamParameters(const char* dataStreamerLabel, bool stopOnOver * @param updatePeriodUs a return parameter that gives the update rate of the stream */ void CMMCore::getStreamParameters(const char* label, bool& stopOnOverflow, - unsigned& numberOfBlocks, double& durationUs, double& updatePeriodUs) throw (CMMError) + int& numberOfBlocks, double& durationUs, double& updatePeriodUs) throw (CMMError) { std::shared_ptr pDataStreamer = deviceManager_->GetDeviceOfType(label); mm::DeviceModuleLockGuard guard(pDataStreamer); - int ret = pDataStreamer->GetStreamParameters(stopOnOverflow, numberOfBlocks, durationUs, updatePeriodUs); + unsigned int p2; + int ret = pDataStreamer->GetStreamParameters(stopOnOverflow, p2, durationUs, updatePeriodUs); if (ret != DEVICE_OK) { logError(pDataStreamer->GetName().c_str(), getDeviceErrorText(ret, pDataStreamer).c_str()); throw CMMError(getDeviceErrorText(ret, pDataStreamer).c_str(), MMERR_DEVICE_GENERIC); } + numberOfBlocks = (int)p2; } /** diff --git a/MMCore/MMCore.h b/MMCore/MMCore.h index 6ba939bd1..52fdc76b7 100644 --- a/MMCore/MMCore.h +++ b/MMCore/MMCore.h @@ -617,9 +617,9 @@ class CMMCore void startStream(const char* dataStreamerLabel) throw (CMMError); void stopStream(const char* dataStreamerLabel) throw (CMMError); void setStreamParameters(const char* dataStreamerLabel, bool stopOnOverflow, - unsigned numberOfBlocks, double durationUs, double updatePeriodUs) throw (CMMError); + int numberOfBlocks, double durationUs, double updatePeriodUs) throw (CMMError); void getStreamParameters(const char* label, bool& stopOnOverflow, - unsigned& numberOfBlocks, double& durationUs, double& updatePeriodUs) throw (CMMError); + int& numberOfBlocks, double& durationUs, double& updatePeriodUs) throw (CMMError); void setCircularAcquisitionBufferCapacity(const char* dataStreamerLabel, unsigned capacity) throw (CMMError); long getCircularAcquisitionBufferCapacity(const char* dataStreamerLabel) throw (CMMError); ///@} diff --git a/MMCoreJ_wrap/MMCoreJ.i b/MMCoreJ_wrap/MMCoreJ.i index 84a71459b..4fb20b0b9 100644 --- a/MMCoreJ_wrap/MMCoreJ.i +++ b/MMCoreJ_wrap/MMCoreJ.i @@ -287,6 +287,10 @@ %apply int &OUTPUT { int &y }; %apply int &OUTPUT { int &xSize }; %apply int &OUTPUT { int &ySize }; +%apply bool &OUTPUT { bool &stopOnOverflow }; +%apply int &OUTPUT { int &numberOfBlocks }; +%apply double &OUTPUT { double &durationUs }; +%apply double &OUTPUT { double &updatePeriodUs }; // Java typemap From 4e3e9cdf121827e3c3f21c6a2901958db2c27b31 Mon Sep 17 00:00:00 2001 From: "melnykov.artem" Date: Wed, 14 Dec 2022 21:39:42 -0600 Subject: [PATCH 09/14] Cleaned up DataStremer and brought up to date with main MM branch --- DeviceAdapters/DemoCamera/DemoCamera.h | 9 +- MMCore/Devices/DataStreamerInstance.cpp | 11 +- MMCore/Devices/DataStreamerInstance.h | 11 +- MMCore/MMCore.cpp | 114 +++++++--------- MMCore/MMCore.h | 6 +- MMDevice/DeviceBase.h | 168 ++++++++++++++---------- MMDevice/MMDevice.h | 21 +-- MMDevice/MMDeviceConstants.h | 1 + 8 files changed, 180 insertions(+), 161 deletions(-) diff --git a/DeviceAdapters/DemoCamera/DemoCamera.h b/DeviceAdapters/DemoCamera/DemoCamera.h index c0f4d09bd..bfdddad6d 100644 --- a/DeviceAdapters/DemoCamera/DemoCamera.h +++ b/DeviceAdapters/DemoCamera/DemoCamera.h @@ -1205,7 +1205,8 @@ class DemoDataStreamer : public CDataStreamerBase { public: DemoDataStreamer() : - mockDataSize_(1024*1024) + mockDataSize_(1024*1024), + initialized_(false) { // parent ID display CreateHubIDProperty(); @@ -1216,7 +1217,7 @@ class DemoDataStreamer : public CDataStreamerBase // initialize mock data mockData_ = new char[mockDataSize_]; char val = 0; - for (int ii = 0; ii < mockDataSize_; ii++) { mockData_[ii] = val; val++; } + for (unsigned ii = 0; ii < mockDataSize_; ii++) { mockData_[ii] = val; val++; } writeFile_.open("C:\\temp\\mybinaryfile.txt", std::ios::out | std::ios::binary); @@ -1256,11 +1257,12 @@ class DemoDataStreamer : public CDataStreamerBase // allocate a new data array and put data in it std::unique_ptr data(new char[actualDataBufferSize]); memcpy(data.get(), mockData_, actualDataBufferSize); + LogMessage("Demo DataStreamer: finished GetBuffer", true); return data; } - int ProcessBuffer(std::unique_ptr &pDataBuffer, unsigned dataSize) { + int ProcessBuffer(std::unique_ptr& pDataBuffer, unsigned dataSize) { LogMessage("Demo DataStreamer: calling ProcessBuffer", true); @@ -1269,6 +1271,7 @@ class DemoDataStreamer : public CDataStreamerBase return 0; } writeFile_.write(pDataBuffer.get(), dataSize); + LogMessage("Demo DataStreamer: finished ProcessBuffer", true); return DEVICE_OK; } diff --git a/MMCore/Devices/DataStreamerInstance.cpp b/MMCore/Devices/DataStreamerInstance.cpp index a6df38c4a..73791b658 100644 --- a/MMCore/Devices/DataStreamerInstance.cpp +++ b/MMCore/Devices/DataStreamerInstance.cpp @@ -25,11 +25,12 @@ int DataStreamerInstance::GetBufferSize(unsigned& dataBufferSiize) { return GetImpl()->GetBufferSize(dataBufferSiize); } std::unique_ptr DataStreamerInstance::GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize) { return GetImpl()->GetBuffer(expectedDataBufferSize,actualDataBufferSize); } int DataStreamerInstance::ProcessBuffer(std::unique_ptr& pDataBuffer, unsigned dataSize) { return GetImpl()->ProcessBuffer(pDataBuffer, dataSize); } -int DataStreamerInstance::SetStreamParameters(bool stopOnOverflow, unsigned numberOfBuffers, double durationUs, double updatePeriodUs) { return GetImpl()->SetStreamParameters(stopOnOverflow, numberOfBuffers, durationUs, updatePeriodUs); } -int DataStreamerInstance::GetStreamParameters(bool& stopOnOverflow, unsigned& numberOfBuffers, double& durationUs, double& updatePeriodUs) { return GetImpl()->GetStreamParameters(stopOnOverflow,numberOfBuffers,durationUs,updatePeriodUs); } int DataStreamerInstance::StartStream() { return GetImpl()->StartStream(); } int DataStreamerInstance::StopStream() { return GetImpl()->StopStream(); } -int DataStreamerInstance::IsStreaming(unsigned& isStreaming) { return GetImpl()->IsStreaming(isStreaming); } -int DataStreamerInstance::SetCircularAcquisitionBufferCapacity(unsigned capacity) { return GetImpl()->SetCircularAcquisitionBufferCapacity(capacity); } -int DataStreamerInstance::GetCircularAcquisitionBufferCapacity(unsigned& capacity) { return GetImpl()->GetCircularAcquisitionBufferCapacity(capacity); } +int DataStreamerInstance::ResetStream() { return GetImpl()->ResetStream(); } +bool DataStreamerInstance::IsStreaming() { return GetImpl()->IsStreaming(); } +int DataStreamerInstance::SetStreamParameters(bool stopOnOverflow, int numberOfBuffers, double durationUs, double updatePeriodUs) { return GetImpl()->SetStreamParameters(stopOnOverflow, numberOfBuffers, durationUs, updatePeriodUs); } +int DataStreamerInstance::GetStreamParameters(bool& stopOnOverflow, int& numberOfBuffers, double& durationUs, double& updatePeriodUs) { return GetImpl()->GetStreamParameters(stopOnOverflow,numberOfBuffers,durationUs,updatePeriodUs); } +int DataStreamerInstance::SetCircularAcquisitionBufferCapacity(int capacity) { return GetImpl()->SetCircularAcquisitionBufferCapacity(capacity); } +int DataStreamerInstance::GetCircularAcquisitionBufferCapacity() { return GetImpl()->GetCircularAcquisitionBufferCapacity(); } diff --git a/MMCore/Devices/DataStreamerInstance.h b/MMCore/Devices/DataStreamerInstance.h index b0db26f21..873b543b7 100644 --- a/MMCore/Devices/DataStreamerInstance.h +++ b/MMCore/Devices/DataStreamerInstance.h @@ -39,11 +39,12 @@ class DataStreamerInstance : public DeviceInstanceBase int GetBufferSize(unsigned& dataBufferSiize); std::unique_ptr GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize); int ProcessBuffer(std::unique_ptr& pDataBuffer, unsigned dataSize); - int SetStreamParameters(bool stopOnOverflow, unsigned numberOfBuffers, double durationUs, double updatePeriodUs); - int GetStreamParameters(bool& stopOnOverflow, unsigned& numberOfBuffers, double& durationUs, double& updatePeriodUs); int StartStream(); int StopStream(); - int IsStreaming(unsigned& isStreaming); - int SetCircularAcquisitionBufferCapacity(unsigned capacity); - int GetCircularAcquisitionBufferCapacity(unsigned& capacity); + int ResetStream(); + bool IsStreaming(); + int SetStreamParameters(bool stopOnOverflow, int numberOfBuffers, double durationUs, double updatePeriodUs); + int GetStreamParameters(bool& stopOnOverflow, int& numberOfBuffers, double& durationUs, double& updatePeriodUs); + int SetCircularAcquisitionBufferCapacity(int capacity); + int GetCircularAcquisitionBufferCapacity(); }; diff --git a/MMCore/MMCore.cpp b/MMCore/MMCore.cpp index f95f0bf29..b3830f5e3 100644 --- a/MMCore/MMCore.cpp +++ b/MMCore/MMCore.cpp @@ -6416,18 +6416,11 @@ string CMMCore::getGalvoChannel(const char* deviceLabel) throw (CMMError) */ void CMMCore::startStream(const char* dataStreamerLabel) throw (CMMError) { - std::shared_ptr pDataStreamer = - deviceManager_->GetDeviceOfType(dataStreamerLabel); - if (pDataStreamer) - { - mm::DeviceModuleLockGuard guard(pDataStreamer); - int ret = pDataStreamer->StartStream(); - if (ret != DEVICE_OK) - { - logError("CMMCore::startStream()", getDeviceErrorText(ret, pDataStreamer).c_str()); - throw CMMError(getDeviceErrorText(ret, pDataStreamer).c_str(), MMERR_DEVICE_GENERIC); - } - } + std::shared_ptr pDataStreamer = deviceManager_->GetDeviceOfType(dataStreamerLabel); + LOG_DEBUG(coreLogger_) << "Starting streaming of " << dataStreamerLabel; + mm::DeviceModuleLockGuard guard(pDataStreamer); + int ret = pDataStreamer->StartStream(); + if (ret != DEVICE_OK) throw CMMError(getDeviceErrorText(ret, pDataStreamer).c_str(), MMERR_DEVICE_GENERIC); } /** @@ -6435,18 +6428,35 @@ void CMMCore::startStream(const char* dataStreamerLabel) throw (CMMError) */ void CMMCore::stopStream(const char* dataStreamerLabel) throw (CMMError) { - std::shared_ptr pDataStreamer = - deviceManager_->GetDeviceOfType(dataStreamerLabel); - if (pDataStreamer) - { - mm::DeviceModuleLockGuard guard(pDataStreamer); - int ret = pDataStreamer->StopStream(); - if (ret != DEVICE_OK) - { - logError("CMMCore::startStream()", getDeviceErrorText(ret, pDataStreamer).c_str()); - throw CMMError(getDeviceErrorText(ret, pDataStreamer).c_str(), MMERR_DEVICE_GENERIC); - } - } + std::shared_ptr pDataStreamer = deviceManager_->GetDeviceOfType(dataStreamerLabel); + LOG_DEBUG(coreLogger_) << "Stopping streaming of " << dataStreamerLabel; + mm::DeviceModuleLockGuard guard(pDataStreamer); + int ret = pDataStreamer->StopStream(); + if (ret != DEVICE_OK) throw CMMError(getDeviceErrorText(ret, pDataStreamer).c_str(), MMERR_DEVICE_GENERIC); +} + +/** +* Reset acquisition with the specified data streamer. +*/ +void CMMCore::resetStream(const char* dataStreamerLabel) throw (CMMError) +{ + std::shared_ptr pDataStreamer = deviceManager_->GetDeviceOfType(dataStreamerLabel); + LOG_DEBUG(coreLogger_) << "Reseting streaming of " << dataStreamerLabel; + mm::DeviceModuleLockGuard guard(pDataStreamer); + int ret = pDataStreamer->ResetStream(); + if (ret != DEVICE_OK) throw CMMError(getDeviceErrorText(ret, pDataStreamer).c_str(), MMERR_DEVICE_GENERIC); +} + +/** +* Get streaming status of the specified data streamer. +*/ +bool CMMCore::isStreaming(const char* dataStreamerLabel) throw (CMMError) +{ + std::shared_ptr pDataStreamer = deviceManager_->GetDeviceOfType(dataStreamerLabel); + LOG_DEBUG(coreLogger_) << "Checking streaming status of " << dataStreamerLabel; + mm::DeviceModuleLockGuard guard(pDataStreamer); + int ret = pDataStreamer->IsStreaming(); + return ret; } /** @@ -6460,8 +6470,7 @@ void CMMCore::stopStream(const char* dataStreamerLabel) throw (CMMError) void CMMCore::setStreamParameters(const char* dataStreamerLabel, bool stopOnOverflow, int numberOfBlocks, double durationUs, double updatePeriodUs) { - std::shared_ptr pDataStreamer = - deviceManager_->GetDeviceOfType(dataStreamerLabel); + std::shared_ptr pDataStreamer = deviceManager_->GetDeviceOfType(dataStreamerLabel); LOG_DEBUG(coreLogger_) << "Setting stream parameters of " << dataStreamerLabel << " to stopOnOverflow=" << stopOnOverflow << ", " << @@ -6471,11 +6480,7 @@ void CMMCore::setStreamParameters(const char* dataStreamerLabel, bool stopOnOver mm::DeviceModuleLockGuard guard(pDataStreamer); int ret = pDataStreamer->SetStreamParameters(stopOnOverflow, (unsigned)numberOfBlocks, durationUs, updatePeriodUs); - if (ret != DEVICE_OK) - { - logError(pDataStreamer->GetName().c_str(), getDeviceErrorText(ret, pDataStreamer).c_str()); - throw CMMError(getDeviceErrorText(ret, pDataStreamer).c_str(), MMERR_DEVICE_GENERIC); - } + if (ret != DEVICE_OK) throw CMMError(getDeviceErrorText(ret, pDataStreamer).c_str(), MMERR_DEVICE_GENERIC); } /** @@ -6486,21 +6491,14 @@ void CMMCore::setStreamParameters(const char* dataStreamerLabel, bool stopOnOver * @param durationUs a return parameter that gives duration of the stream * @param updatePeriodUs a return parameter that gives the update rate of the stream */ -void CMMCore::getStreamParameters(const char* label, bool& stopOnOverflow, +void CMMCore::getStreamParameters(const char* dataStreamerLabel, bool& stopOnOverflow, int& numberOfBlocks, double& durationUs, double& updatePeriodUs) throw (CMMError) { - std::shared_ptr pDataStreamer = - deviceManager_->GetDeviceOfType(label); - + std::shared_ptr pDataStreamer = deviceManager_->GetDeviceOfType(dataStreamerLabel); + LOG_DEBUG(coreLogger_) << "Getting stream parameters of " << dataStreamerLabel; mm::DeviceModuleLockGuard guard(pDataStreamer); - unsigned int p2; - int ret = pDataStreamer->GetStreamParameters(stopOnOverflow, p2, durationUs, updatePeriodUs); - if (ret != DEVICE_OK) - { - logError(pDataStreamer->GetName().c_str(), getDeviceErrorText(ret, pDataStreamer).c_str()); - throw CMMError(getDeviceErrorText(ret, pDataStreamer).c_str(), MMERR_DEVICE_GENERIC); - } - numberOfBlocks = (int)p2; + int ret = pDataStreamer->GetStreamParameters(stopOnOverflow, numberOfBlocks, durationUs, updatePeriodUs); + if (ret != DEVICE_OK) throw CMMError(getDeviceErrorText(ret, pDataStreamer).c_str(), MMERR_DEVICE_GENERIC); } /** @@ -6508,20 +6506,13 @@ void CMMCore::getStreamParameters(const char* label, bool& stopOnOverflow, * @param label the data streamer device label * @param capacity number of data blocks in the circular buffer */ -void CMMCore::setCircularAcquisitionBufferCapacity(const char* dataStreamerLabel, unsigned capacity) +void CMMCore::setCircularAcquisitionBufferCapacity(const char* dataStreamerLabel, int capacity) { - std::shared_ptr pDataStreamer = - deviceManager_->GetDeviceOfType(dataStreamerLabel); - - LOG_DEBUG(coreLogger_) << "Setting circular acquisition buffer capacity to" << capacity; - + std::shared_ptr pDataStreamer = deviceManager_->GetDeviceOfType(dataStreamerLabel); + LOG_DEBUG(coreLogger_) << "Setting circular acquisition buffer capacity of " << dataStreamerLabel << " to " << capacity; mm::DeviceModuleLockGuard guard(pDataStreamer); int ret = pDataStreamer->SetCircularAcquisitionBufferCapacity(capacity); - if (ret != DEVICE_OK) - { - logError(pDataStreamer->GetName().c_str(), getDeviceErrorText(ret, pDataStreamer).c_str()); - throw CMMError(getDeviceErrorText(ret, pDataStreamer).c_str(), MMERR_DEVICE_GENERIC); - } + if (ret != DEVICE_OK) throw CMMError(getDeviceErrorText(ret, pDataStreamer).c_str(), MMERR_DEVICE_GENERIC); } /** @@ -6530,18 +6521,11 @@ void CMMCore::setCircularAcquisitionBufferCapacity(const char* dataStreamerLabel */ long CMMCore::getCircularAcquisitionBufferCapacity(const char* dataStreamerLabel) { - std::shared_ptr pDataStreamer = - deviceManager_->GetDeviceOfType(dataStreamerLabel); - + std::shared_ptr pDataStreamer = deviceManager_->GetDeviceOfType(dataStreamerLabel); + LOG_DEBUG(coreLogger_) << "Getting circular acquisition buffer capacity of " << dataStreamerLabel; mm::DeviceModuleLockGuard guard(pDataStreamer); - long capacity; - int ret = pDataStreamer->GetCircularAcquisitionBufferCapacity((unsigned&)capacity); - if (ret <= 0) - { - logError(pDataStreamer->GetName().c_str(), getDeviceErrorText(ret, pDataStreamer).c_str()); - throw CMMError(getDeviceErrorText(ret, pDataStreamer).c_str(), MMERR_DEVICE_GENERIC); - } - return capacity; + int ret = pDataStreamer->GetCircularAcquisitionBufferCapacity(); + return ret; } diff --git a/MMCore/MMCore.h b/MMCore/MMCore.h index 52fdc76b7..eeed506d0 100644 --- a/MMCore/MMCore.h +++ b/MMCore/MMCore.h @@ -616,11 +616,13 @@ class CMMCore ///@{ void startStream(const char* dataStreamerLabel) throw (CMMError); void stopStream(const char* dataStreamerLabel) throw (CMMError); + void resetStream(const char* dataStreamerLabel) throw (CMMError); + bool isStreaming(const char* dataStreamerLabel) throw (CMMError); void setStreamParameters(const char* dataStreamerLabel, bool stopOnOverflow, int numberOfBlocks, double durationUs, double updatePeriodUs) throw (CMMError); - void getStreamParameters(const char* label, bool& stopOnOverflow, + void getStreamParameters(const char* dataStreamerLabel, bool& stopOnOverflow, int& numberOfBlocks, double& durationUs, double& updatePeriodUs) throw (CMMError); - void setCircularAcquisitionBufferCapacity(const char* dataStreamerLabel, unsigned capacity) throw (CMMError); + void setCircularAcquisitionBufferCapacity(const char* dataStreamerLabel, int capacity) throw (CMMError); long getCircularAcquisitionBufferCapacity(const char* dataStreamerLabel) throw (CMMError); ///@} diff --git a/MMDevice/DeviceBase.h b/MMDevice/DeviceBase.h index 244a08326..47e5fb58a 100644 --- a/MMDevice/DeviceBase.h +++ b/MMDevice/DeviceBase.h @@ -2167,60 +2167,61 @@ typedef struct { std::unique_ptr data; unsigned int expectedSize; unsigned int actualSize; -} data_block; +} acquired_block; -class CircularBlockCollection { +/** +* Helper class for storing data blocks acquired by DataStreamer devices +*/ +class AcquiredBlockCollection { public: - CircularBlockCollection(unsigned int maxNumberOfBlocks, bool stopOnOverflow) : - maxNumberOfBlocks_(0), - stopOnOverflow_(true), + AcquiredBlockCollection(unsigned int maxNumberOfBlocks, bool stopOnOverflow) : overflowStatus_(false) { maxNumberOfBlocks_ = maxNumberOfBlocks; cb_.set_capacity(maxNumberOfBlocks_); - cb_.empty(); - //boost::circular_buffer> cb_(maxNumberOfBlocks_); stopOnOverflow_ = stopOnOverflow; } - ~CircularBlockCollection() {} + ~AcquiredBlockCollection() {} - void Add(std::unique_ptr &pDataBlock) + void Add(std::unique_ptr &pDataBlock) { MMThreadGuard g(this->executeLock_); if ((cb_.capacity() - cb_.size()) == 0) { overflowStatus_ = true; if (stopOnOverflow_) return; - cb_.empty(); } cb_.push_back(std::move(pDataBlock)); } int GetCapacity() { - return cb_.capacity(); + MMThreadGuard g(this->executeLock_); + return (int)cb_.capacity(); } int GetSize() { - return cb_.size(); + MMThreadGuard g(this->executeLock_); + return (int)cb_.size(); } - std::unique_ptr Remove() + std::unique_ptr Remove() { MMThreadGuard g(this->executeLock_); if (cb_.size() == 0) { return 0; } else { - std::unique_ptr dataBlock = std::move(cb_.at(0)); + std::unique_ptr dataBlock = std::move(cb_.at(0)); cb_.pop_front(); return dataBlock; } } - void ResetOverflowStatus() + void Reset() { MMThreadGuard g(this->executeLock_); overflowStatus_ = false; + cb_.empty(); } bool GetOverflowStatus() @@ -2229,7 +2230,7 @@ class CircularBlockCollection { return overflowStatus_; } private: - boost::circular_buffer> cb_; + boost::circular_buffer> cb_; MMThreadLock executeLock_; unsigned long maxNumberOfBlocks_; bool stopOnOverflow_; @@ -2243,13 +2244,12 @@ class CircularBlockCollection { template class CDataStreamerBase : public CDeviceBase { - friend class CircularBlockCollection; + friend class AcquiredBlockCollection; public: CDataStreamerBase() : numberOfBlocks_(1), durationUs_(1e6), updatePeriodUs_(1e5), - stopOnOverflow_(true), stopFlag_(false), - cbcData_(0), cbcCapacity_(10), thdAcq_(0), thdProc_(0) + stopOnOverflow_(true), stopFlag_(false), acqCollectionCapacity_(10) { - cbcData_ = new CircularBlockCollection(cbcCapacity_, stopOnOverflow_); + acqCollection_ = new AcquiredBlockCollection(acqCollectionCapacity_, stopOnOverflow_); thdAcq_ = new AcquisitionThread(this); thdProc_ = new ProcessingThread(this); } @@ -2265,28 +2265,27 @@ class CDataStreamerBase : public CDeviceBase } delete thdAcq_; delete thdProc_; - delete cbcData_; + delete acqCollection_; } virtual int GetBufferSize(unsigned& dataBufferSiize) = 0; virtual std::unique_ptr GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize) = 0; - virtual int ProcessBuffer(std::unique_ptr& pDataBuffer, unsigned dataSize) = 0; + virtual int ProcessBuffer(std::unique_ptr& pDataBuffer, unsigned actualDataBufferSize) = 0; - virtual int SetStreamParameters(bool stopOnOverflow, unsigned numberOfBlocks, double durationUs, double updatePeriodUs) + virtual int SetStreamParameters(bool stopOnOverflow, int numberOfBlocks, double durationUs, double updatePeriodUs) { - if (thdAcq_->IsRunning()) { - return DEVICE_CAMERA_BUSY_ACQUIRING; - } + if (IsStreaming()) return DEVICE_DATASTREAMER_BUSY_ACQUIRING; + if (numberOfBlocks <= 0 || durationUs < 0 || updatePeriodUs <= 0) return DEVICE_INVALID_INPUT_PARAM; stopOnOverflow_ = stopOnOverflow; numberOfBlocks_ = numberOfBlocks; durationUs_ = durationUs; updatePeriodUs_ = updatePeriodUs; - delete cbcData_; - cbcData_ = new CircularBlockCollection(cbcCapacity_, stopOnOverflow_); + delete acqCollection_; + acqCollection_ = new AcquiredBlockCollection(acqCollectionCapacity_, stopOnOverflow_); return DEVICE_OK; } - virtual int GetStreamParameters(bool& stopOnOverflow, unsigned& numberOfBlocks, double& durationUs, double& updatePeriodUs) + virtual int GetStreamParameters(bool& stopOnOverflow, int& numberOfBlocks, double& durationUs, double& updatePeriodUs) { stopOnOverflow = stopOnOverflow_; numberOfBlocks = numberOfBlocks_; @@ -2297,47 +2296,59 @@ class CDataStreamerBase : public CDeviceBase virtual int StartStream() { - if (thdAcq_->IsRunning() || thdProc_->IsRunning()) { - return DEVICE_CAMERA_BUSY_ACQUIRING; - } + if (IsStreaming()) return DEVICE_DATASTREAMER_BUSY_ACQUIRING; thdAcq_->Start(); thdProc_->Start(); return DEVICE_OK; } virtual int StopStream() { + // a non-blocking implementaion if (thdAcq_->IsRunning()) { thdAcq_->Stop(); - thdAcq_->wait(); + //thdAcq_->wait(); } if (thdProc_->IsRunning()) { - thdProc_->wait(); + //thdProc_->wait(); } return DEVICE_OK; } - virtual int SetCircularAcquisitionBufferCapacity(unsigned capacity) { + virtual int ResetStream() { + if (IsStreaming()) return DEVICE_DATASTREAMER_BUSY_ACQUIRING; + delete acqCollection_; + acqCollection_ = new AcquiredBlockCollection(acqCollectionCapacity_, stopOnOverflow_); + return DEVICE_OK; + } + + virtual bool IsStreaming() { if (thdAcq_->IsRunning() || thdProc_->IsRunning()) { - return DEVICE_CAMERA_BUSY_ACQUIRING; + return true; + } + else { + return false; } - cbcCapacity_ = capacity; - delete cbcData_; - cbcData_ = new CircularBlockCollection(cbcCapacity_, stopOnOverflow_); - return DEVICE_OK; } - virtual int GetCircularAcquisitionBufferCapacity(unsigned& capacity) { - return cbcCapacity_; + virtual int SetCircularAcquisitionBufferCapacity(int capacity) { + if (IsStreaming()) return DEVICE_DATASTREAMER_BUSY_ACQUIRING; + if (capacity <= 0) return DEVICE_INVALID_INPUT_PARAM; + acqCollectionCapacity_ = capacity; + delete acqCollection_; + acqCollection_ = new AcquiredBlockCollection(acqCollectionCapacity_, stopOnOverflow_); + return DEVICE_OK; } - virtual int IsStreaming(unsigned& isStreaming) { return isStreaming_; } + virtual int GetCircularAcquisitionBufferCapacity() { + return acqCollectionCapacity_; + } class AcquisitionThread : public MMDeviceThreadBase { friend class CDataStreamerBase; - friend class CircularBlockCollection; + friend class AcquiredBlockCollection; public: - AcquisitionThread(CDataStreamerBase* p) : pDataStreamerBase_(0), isRunning_(false),stopFlag_(false) + AcquisitionThread(CDataStreamerBase* p) : isRunning_(false),stopFlag_(false) { pDataStreamerBase_ = p; } @@ -2368,50 +2379,61 @@ class CDataStreamerBase : public CDeviceBase // Provide description here int svc(void) { - int ret = 0; + int ret = DEVICE_OK; + std::unique_ptr newBlock(new acquired_block); unsigned int expectedDataSize, actualDataSize; unsigned int blockCounter=0; - CircularBlockCollection* cbc = pDataStreamerBase_->cbcData_; + AcquiredBlockCollection* acqCollection = pDataStreamerBase_->acqCollection_; MM::MMTime startTime = pDataStreamerBase_->GetCurrentMMTime(); MM::MMTime timeSinceStart = pDataStreamerBase_->GetCurrentMMTime() - startTime; // check all stopping conditions while (!(this->GetStopFlag() || //read externally set stop flag blockCounter >= pDataStreamerBase_->numberOfBlocks_ || // stop if desired number of blocks have been collected - (cbc->GetOverflowStatus() && pDataStreamerBase_->stopOnOverflow_) || // buffer overflow - timeSinceStart > MM::MMTime(pDataStreamerBase_->durationUs_)) ) { // timeout - Sleep(pDataStreamerBase_->updatePeriodUs_/1000); + (acqCollection->GetOverflowStatus() && pDataStreamerBase_->stopOnOverflow_) || // buffer overflow + timeSinceStart > MM::MMTime(pDataStreamerBase_->durationUs_)) ) { // collection time elapsed + Sleep((int)(pDataStreamerBase_->updatePeriodUs_/1000)); timeSinceStart = pDataStreamerBase_->GetCurrentMMTime() - startTime; ret = pDataStreamerBase_->GetBufferSize(expectedDataSize); + if (ret != DEVICE_OK) break; if (expectedDataSize != 0) { - std::unique_ptr newBlock(new data_block); newBlock->data = pDataStreamerBase_->GetBuffer(expectedDataSize, actualDataSize); + if (newBlock == 0) break; newBlock->expectedSize = expectedDataSize; newBlock->actualSize = actualDataSize; - cbc->Add(newBlock); + acqCollection->Add(newBlock); blockCounter++; } } std::stringstream ss; - ss << "Terminating acuisition thread for the following reason:"; + ss << "Terminating acuisition thread for the following reason: "; if (this->GetStopFlag()) { ss << " user selection"; } - else if (cbc->GetOverflowStatus() && pDataStreamerBase_->stopOnOverflow_) { - ss << " acquisition buffer overflow"; + else if (acqCollection->GetOverflowStatus() && pDataStreamerBase_->stopOnOverflow_) { + ss << "acquisition buffer overflow"; } else if (blockCounter >= pDataStreamerBase_->numberOfBlocks_) { ss << "desired number of blocks (" << blockCounter << ") have been collected"; } else if (timeSinceStart > MM::MMTime(pDataStreamerBase_->durationUs_)) { - ss << " acquisition time exceeded the set limit (" << pDataStreamerBase_->durationUs_ << " microseconds)"; + ss << "acquisition time exceeded the set limit (" << pDataStreamerBase_->durationUs_ << " microseconds)"; + } + else if (ret != DEVICE_OK) { + ss << "GetBufferSize call returned an error"; + } + else if (newBlock == 0) { + ss << "GetBuffer call returned an error"; + } + else { + ss << "unknown"; } pDataStreamerBase_->LogMessage(ss.str(), true); this->SetIsRunning(false); stopFlag_ = false; return DEVICE_OK; - } + } void SetStopFlag(bool stop) { MMThreadGuard g(this->stopLock_); @@ -2438,10 +2460,10 @@ class CDataStreamerBase : public CDeviceBase class ProcessingThread : public MMDeviceThreadBase { friend class CDataStreamerBase; - friend class CircularBlockCollection; + friend class AcquiredBlockCollection; friend class AcquisitionThread; public: - ProcessingThread(CDataStreamerBase* p) : pDataStreamerBase_(0), isRunning_(false) + ProcessingThread(CDataStreamerBase* p) : isRunning_(false) { pDataStreamerBase_ = p; } @@ -2458,25 +2480,30 @@ class CDataStreamerBase : public CDeviceBase private: CDataStreamerBase* pDataStreamerBase_; - AcquisitionThread* acq_; bool isRunning_; MMThreadLock isRunningLock_; // Provide description here int svc(void) { - int ret = 0; - CircularBlockCollection* cbc = pDataStreamerBase_->cbcData_; - AcquisitionThread* acq = pDataStreamerBase_->thdAcq_; + int ret; + AcquiredBlockCollection* acqCollection = pDataStreamerBase_->acqCollection_; + AcquisitionThread* acqThr = pDataStreamerBase_->thdAcq_; // give the device time to acquire data - Sleep(pDataStreamerBase_->updatePeriodUs_ / 1000); + Sleep((int)(pDataStreamerBase_->updatePeriodUs_ / 1000)); // run while the acquisition thread is active or // there is unprocessed data in the circular acquisition buffer - while (acq->GetIsRunning() || cbc->GetSize() != 0) { - Sleep(pDataStreamerBase_->updatePeriodUs_ / 1000); - if (cbc->GetSize() != 0) { - std::unique_ptr newBlock = cbc->Remove(); + while (acqThr->GetIsRunning() || acqCollection->GetSize() != 0) { + if (acqCollection->GetSize() != 0) { + std::unique_ptr newBlock = acqCollection->Remove(); ret = pDataStreamerBase_->ProcessBuffer(std::move(newBlock->data),newBlock->actualSize); + if (ret != DEVICE_OK) { + pDataStreamerBase_->LogMessage("ProcessBuffer call returned an error.", true); + break; + } + } + else { + Sleep((int)(pDataStreamerBase_->updatePeriodUs_ / 1000)); } } @@ -2503,10 +2530,9 @@ class CDataStreamerBase : public CDeviceBase double durationUs_; double updatePeriodUs_; bool stopOnOverflow_; - bool isStreaming_; bool stopFlag_; - CircularBlockCollection* cbcData_; - unsigned cbcCapacity_; + AcquiredBlockCollection* acqCollection_; + unsigned acqCollectionCapacity_; AcquisitionThread* thdAcq_; ProcessingThread* thdProc_; }; diff --git a/MMDevice/MMDevice.h b/MMDevice/MMDevice.h index f2674d4d2..f988832c7 100644 --- a/MMDevice/MMDevice.h +++ b/MMDevice/MMDevice.h @@ -1194,29 +1194,30 @@ namespace MM { // Calls that are specific to each DataStreamer device // and should be implemented in the device adapter /** - * Get the size (in bytes) of the data buffer available for download from the hardware + * Get the expected size (in bytes) of the data buffer available for download from the hardware */ virtual int GetBufferSize(unsigned& dataBufferSiize) = 0; /** * Receive data buffer from the hardware and place it at memory location - * specified by pDataBuffer + * specified by pDataBuffer; + * update the size of the buffer and pass it as actualDataBufferSize */ virtual std::unique_ptr GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize) = 0; /** - * Process the data buffer available at pDataBuffer and place - * resulting multidimensional array at pProcessedArray + * Process the data buffer available at pDataBuffer */ - virtual int ProcessBuffer(std::unique_ptr& pDataBuffer, unsigned dataSize) = 0; + virtual int ProcessBuffer(std::unique_ptr& pDataBuffer, unsigned actualDataBufferSize) = 0; // Calls that are implemented at the DeviceBase level and // remain the same for any DataStreamer device - virtual int SetStreamParameters(bool stopOnOverflow, unsigned numberOfBuffers, double durationUs, double updatePeriodUs) = 0; - virtual int GetStreamParameters(bool& stopOnOverflow, unsigned& numberOfBuffers, double& durationUs, double& updatePeriodUs) = 0; + virtual int SetStreamParameters(bool stopOnOverflow, int numberOfBuffers, double durationUs, double updatePeriodUs) = 0; + virtual int GetStreamParameters(bool& stopOnOverflow, int& numberOfBuffers, double& durationUs, double& updatePeriodUs) = 0; virtual int StartStream() = 0; virtual int StopStream() = 0; - virtual int IsStreaming(unsigned& isStreaming) = 0; - virtual int SetCircularAcquisitionBufferCapacity(unsigned capacity) = 0; - virtual int GetCircularAcquisitionBufferCapacity(unsigned& capacity) = 0; + virtual int ResetStream() = 0; + virtual bool IsStreaming() = 0; + virtual int SetCircularAcquisitionBufferCapacity(int capacity) = 0; + virtual int GetCircularAcquisitionBufferCapacity() = 0; }; /** diff --git a/MMDevice/MMDeviceConstants.h b/MMDevice/MMDeviceConstants.h index 09f49366d..b7bf2e136 100644 --- a/MMDevice/MMDeviceConstants.h +++ b/MMDevice/MMDeviceConstants.h @@ -78,6 +78,7 @@ #define DEVICE_SEQUENCE_TOO_LARGE 39 #define DEVICE_OUT_OF_MEMORY 40 #define DEVICE_NOT_YET_IMPLEMENTED 41 +#define DEVICE_DATASTREAMER_BUSY_ACQUIRING 42 namespace MM { From 6d0ff54927832dae9c2f2be46ace601200e5a10e Mon Sep 17 00:00:00 2001 From: "melnykov.artem" Date: Fri, 16 Dec 2022 21:03:48 -0600 Subject: [PATCH 10/14] Fixed a couple of bugs, finalized circular acquisition buffer overflow control --- DeviceAdapters/DemoCamera/DemoCamera.h | 3 +- MMCore/Devices/DataStreamerInstance.cpp | 3 +- MMCore/Devices/DataStreamerInstance.h | 3 +- MMCore/MMCore.cpp | 17 +++- MMCore/MMCore.h | 3 +- MMDevice/DeviceBase.h | 116 ++++++++++++++---------- MMDevice/MMDevice.h | 3 +- 7 files changed, 93 insertions(+), 55 deletions(-) diff --git a/DeviceAdapters/DemoCamera/DemoCamera.h b/DeviceAdapters/DemoCamera/DemoCamera.h index bfdddad6d..cf911e0b2 100644 --- a/DeviceAdapters/DemoCamera/DemoCamera.h +++ b/DeviceAdapters/DemoCamera/DemoCamera.h @@ -52,7 +52,7 @@ const char* NoHubError = "Parent Hub not defined."; -const char* g_DataStreamerDeviceName = "DSimulatedDataStreamer"; +const char* g_DataStreamerDeviceName = "DDataStreamer"; // Defines which segments in a seven-segment display are lit up for each of // the numbers 0-9. Segments are: @@ -1271,6 +1271,7 @@ class DemoDataStreamer : public CDataStreamerBase return 0; } writeFile_.write(pDataBuffer.get(), dataSize); + Sleep(2000); LogMessage("Demo DataStreamer: finished ProcessBuffer", true); return DEVICE_OK; diff --git a/MMCore/Devices/DataStreamerInstance.cpp b/MMCore/Devices/DataStreamerInstance.cpp index 73791b658..3e3863af9 100644 --- a/MMCore/Devices/DataStreamerInstance.cpp +++ b/MMCore/Devices/DataStreamerInstance.cpp @@ -27,7 +27,8 @@ std::unique_ptr DataStreamerInstance::GetBuffer(unsigned expectedDataBuf int DataStreamerInstance::ProcessBuffer(std::unique_ptr& pDataBuffer, unsigned dataSize) { return GetImpl()->ProcessBuffer(pDataBuffer, dataSize); } int DataStreamerInstance::StartStream() { return GetImpl()->StartStream(); } int DataStreamerInstance::StopStream() { return GetImpl()->StopStream(); } -int DataStreamerInstance::ResetStream() { return GetImpl()->ResetStream(); } +bool DataStreamerInstance::GetOverflowStatus() { return GetImpl()->GetOverflowStatus(); } +int DataStreamerInstance::ResetOverflowStatus() { return GetImpl()->ResetOverflowStatus(); } bool DataStreamerInstance::IsStreaming() { return GetImpl()->IsStreaming(); } int DataStreamerInstance::SetStreamParameters(bool stopOnOverflow, int numberOfBuffers, double durationUs, double updatePeriodUs) { return GetImpl()->SetStreamParameters(stopOnOverflow, numberOfBuffers, durationUs, updatePeriodUs); } int DataStreamerInstance::GetStreamParameters(bool& stopOnOverflow, int& numberOfBuffers, double& durationUs, double& updatePeriodUs) { return GetImpl()->GetStreamParameters(stopOnOverflow,numberOfBuffers,durationUs,updatePeriodUs); } diff --git a/MMCore/Devices/DataStreamerInstance.h b/MMCore/Devices/DataStreamerInstance.h index 873b543b7..b74775599 100644 --- a/MMCore/Devices/DataStreamerInstance.h +++ b/MMCore/Devices/DataStreamerInstance.h @@ -41,7 +41,8 @@ class DataStreamerInstance : public DeviceInstanceBase int ProcessBuffer(std::unique_ptr& pDataBuffer, unsigned dataSize); int StartStream(); int StopStream(); - int ResetStream(); + bool GetOverflowStatus(); + int ResetOverflowStatus(); bool IsStreaming(); int SetStreamParameters(bool stopOnOverflow, int numberOfBuffers, double durationUs, double updatePeriodUs); int GetStreamParameters(bool& stopOnOverflow, int& numberOfBuffers, double& durationUs, double& updatePeriodUs); diff --git a/MMCore/MMCore.cpp b/MMCore/MMCore.cpp index b3830f5e3..19f3e26f5 100644 --- a/MMCore/MMCore.cpp +++ b/MMCore/MMCore.cpp @@ -6435,15 +6435,26 @@ void CMMCore::stopStream(const char* dataStreamerLabel) throw (CMMError) if (ret != DEVICE_OK) throw CMMError(getDeviceErrorText(ret, pDataStreamer).c_str(), MMERR_DEVICE_GENERIC); } +/** +* Get overflow status of the specified data streamer. +*/ +bool CMMCore::getOverflowStatus(const char* dataStreamerLabel) throw (CMMError) +{ + std::shared_ptr pDataStreamer = deviceManager_->GetDeviceOfType(dataStreamerLabel); + LOG_DEBUG(coreLogger_) << "Getting overflow status of " << dataStreamerLabel; + mm::DeviceModuleLockGuard guard(pDataStreamer); + return pDataStreamer->GetOverflowStatus(); +} + /** * Reset acquisition with the specified data streamer. */ -void CMMCore::resetStream(const char* dataStreamerLabel) throw (CMMError) +void CMMCore::resetOverflowStatus(const char* dataStreamerLabel) throw (CMMError) { std::shared_ptr pDataStreamer = deviceManager_->GetDeviceOfType(dataStreamerLabel); - LOG_DEBUG(coreLogger_) << "Reseting streaming of " << dataStreamerLabel; + LOG_DEBUG(coreLogger_) << "Reseting overflow status of " << dataStreamerLabel; mm::DeviceModuleLockGuard guard(pDataStreamer); - int ret = pDataStreamer->ResetStream(); + int ret = pDataStreamer->ResetOverflowStatus(); if (ret != DEVICE_OK) throw CMMError(getDeviceErrorText(ret, pDataStreamer).c_str(), MMERR_DEVICE_GENERIC); } diff --git a/MMCore/MMCore.h b/MMCore/MMCore.h index eeed506d0..3d313d8c0 100644 --- a/MMCore/MMCore.h +++ b/MMCore/MMCore.h @@ -616,7 +616,8 @@ class CMMCore ///@{ void startStream(const char* dataStreamerLabel) throw (CMMError); void stopStream(const char* dataStreamerLabel) throw (CMMError); - void resetStream(const char* dataStreamerLabel) throw (CMMError); + bool getOverflowStatus(const char* dataStreamerLabel) throw (CMMError); + void resetOverflowStatus(const char* dataStreamerLabel) throw (CMMError); bool isStreaming(const char* dataStreamerLabel) throw (CMMError); void setStreamParameters(const char* dataStreamerLabel, bool stopOnOverflow, int numberOfBlocks, double durationUs, double updatePeriodUs) throw (CMMError); diff --git a/MMDevice/DeviceBase.h b/MMDevice/DeviceBase.h index 47e5fb58a..0b2e94d1e 100644 --- a/MMDevice/DeviceBase.h +++ b/MMDevice/DeviceBase.h @@ -82,6 +82,7 @@ const char* const g_Msg_DEVICE_DUPLICATE_LIBRARY="Duplicate Device Library Name" const char* const g_Msg_DEVICE_PROPERTY_NOT_SEQUENCEABLE="This property is not sequenceable"; const char* const g_Msg_DEVICE_SEQUENCE_TOO_LARGE="Sequence is too large for this device"; const char* const g_Msg_DEVICE_NOT_YET_IMPLEMENTED="This command has not yet been implemented for this device."; +const char* const g_Msg_DEVICE_DATASTREAMER_BUSY_ACQUIRING = "Not allowed while data streamer is running"; inline long nint( double value ) { @@ -949,6 +950,7 @@ class CDeviceBase : public T SetErrorText(DEVICE_PROPERTY_NOT_SEQUENCEABLE, g_Msg_DEVICE_PROPERTY_NOT_SEQUENCEABLE); SetErrorText(DEVICE_SEQUENCE_TOO_LARGE, g_Msg_DEVICE_SEQUENCE_TOO_LARGE); SetErrorText(DEVICE_NOT_YET_IMPLEMENTED, g_Msg_DEVICE_NOT_YET_IMPLEMENTED); + SetErrorText(DEVICE_DATASTREAMER_BUSY_ACQUIRING, g_Msg_DEVICE_DATASTREAMER_BUSY_ACQUIRING); } /** @@ -2217,11 +2219,10 @@ class AcquiredBlockCollection { } } - void Reset() + void SetOverflowStatus(bool status) { MMThreadGuard g(this->executeLock_); - overflowStatus_ = false; - cb_.empty(); + overflowStatus_ = status; } bool GetOverflowStatus() @@ -2275,7 +2276,7 @@ class CDataStreamerBase : public CDeviceBase virtual int SetStreamParameters(bool stopOnOverflow, int numberOfBlocks, double durationUs, double updatePeriodUs) { if (IsStreaming()) return DEVICE_DATASTREAMER_BUSY_ACQUIRING; - if (numberOfBlocks <= 0 || durationUs < 0 || updatePeriodUs <= 0) return DEVICE_INVALID_INPUT_PARAM; + if (numberOfBlocks <= 0 || durationUs <= 0 || updatePeriodUs <= 0) return DEVICE_INVALID_INPUT_PARAM; stopOnOverflow_ = stopOnOverflow; numberOfBlocks_ = numberOfBlocks; durationUs_ = durationUs; @@ -2313,11 +2314,12 @@ class CDataStreamerBase : public CDeviceBase } return DEVICE_OK; } + virtual bool GetOverflowStatus() { + return acqCollection_->GetOverflowStatus(); + } - virtual int ResetStream() { - if (IsStreaming()) return DEVICE_DATASTREAMER_BUSY_ACQUIRING; - delete acqCollection_; - acqCollection_ = new AcquiredBlockCollection(acqCollectionCapacity_, stopOnOverflow_); + virtual int ResetOverflowStatus() { + acqCollection_->SetOverflowStatus(false); return DEVICE_OK; } @@ -2377,35 +2379,47 @@ class CDataStreamerBase : public CDeviceBase MMThreadLock isRunningLock_; // Provide description here - int svc(void) + int svc(void) throw () { - int ret = DEVICE_OK; - std::unique_ptr newBlock(new acquired_block); + int retSize = DEVICE_OK; + int retBuffer = DEVICE_OK; unsigned int expectedDataSize, actualDataSize; - unsigned int blockCounter=0; + unsigned int blockCounter = 0; AcquiredBlockCollection* acqCollection = pDataStreamerBase_->acqCollection_; MM::MMTime startTime = pDataStreamerBase_->GetCurrentMMTime(); MM::MMTime timeSinceStart = pDataStreamerBase_->GetCurrentMMTime() - startTime; - // check all stopping conditions - while (!(this->GetStopFlag() || //read externally set stop flag - blockCounter >= pDataStreamerBase_->numberOfBlocks_ || // stop if desired number of blocks have been collected - (acqCollection->GetOverflowStatus() && pDataStreamerBase_->stopOnOverflow_) || // buffer overflow - timeSinceStart > MM::MMTime(pDataStreamerBase_->durationUs_)) ) { // collection time elapsed - Sleep((int)(pDataStreamerBase_->updatePeriodUs_/1000)); - timeSinceStart = pDataStreamerBase_->GetCurrentMMTime() - startTime; - ret = pDataStreamerBase_->GetBufferSize(expectedDataSize); - if (ret != DEVICE_OK) break; - if (expectedDataSize != 0) { - newBlock->data = pDataStreamerBase_->GetBuffer(expectedDataSize, actualDataSize); - if (newBlock == 0) break; - newBlock->expectedSize = expectedDataSize; - newBlock->actualSize = actualDataSize; - acqCollection->Add(newBlock); - blockCounter++; + std::stringstream ss; + try { + // check all stopping conditions + while (!(this->GetStopFlag() || //read externally set stop flag + blockCounter >= pDataStreamerBase_->numberOfBlocks_ || // stop if desired number of blocks have been collected + (acqCollection->GetOverflowStatus() && pDataStreamerBase_->stopOnOverflow_) || // buffer overflow + timeSinceStart > MM::MMTime(pDataStreamerBase_->durationUs_))) { // collection time elapsed + Sleep((int)(pDataStreamerBase_->updatePeriodUs_ / 1000)); + timeSinceStart = pDataStreamerBase_->GetCurrentMMTime() - startTime; + retSize = pDataStreamerBase_->GetBufferSize(expectedDataSize); + if (retSize != DEVICE_OK) break; + if (expectedDataSize != 0) { + std::unique_ptr newBlock(new acquired_block); + newBlock->data = pDataStreamerBase_->GetBuffer(expectedDataSize, actualDataSize); + if (newBlock->data == 0) { + retBuffer = DEVICE_ERR; + break; + } + newBlock->expectedSize = expectedDataSize; + newBlock->actualSize = actualDataSize; + acqCollection->Add(newBlock); + blockCounter++; + } } } + catch (...) { + pDataStreamerBase_->LogMessage("Unknown acquisition thread exception.", true); + this->SetIsRunning(false); + stopFlag_ = false; + return DEVICE_ERR; + } - std::stringstream ss; ss << "Terminating acuisition thread for the following reason: "; if (this->GetStopFlag()) { ss << " user selection"; @@ -2419,10 +2433,10 @@ class CDataStreamerBase : public CDeviceBase else if (timeSinceStart > MM::MMTime(pDataStreamerBase_->durationUs_)) { ss << "acquisition time exceeded the set limit (" << pDataStreamerBase_->durationUs_ << " microseconds)"; } - else if (ret != DEVICE_OK) { + else if (retSize != DEVICE_OK) { ss << "GetBufferSize call returned an error"; } - else if (newBlock == 0) { + else if (retBuffer != DEVICE_OK) { ss << "GetBuffer call returned an error"; } else { @@ -2484,27 +2498,35 @@ class CDataStreamerBase : public CDeviceBase MMThreadLock isRunningLock_; // Provide description here - int svc(void) + int svc(void) throw () { int ret; - AcquiredBlockCollection* acqCollection = pDataStreamerBase_->acqCollection_; AcquisitionThread* acqThr = pDataStreamerBase_->thdAcq_; - // give the device time to acquire data - Sleep((int)(pDataStreamerBase_->updatePeriodUs_ / 1000)); - // run while the acquisition thread is active or - // there is unprocessed data in the circular acquisition buffer - while (acqThr->GetIsRunning() || acqCollection->GetSize() != 0) { - if (acqCollection->GetSize() != 0) { - std::unique_ptr newBlock = acqCollection->Remove(); - ret = pDataStreamerBase_->ProcessBuffer(std::move(newBlock->data),newBlock->actualSize); - if (ret != DEVICE_OK) { - pDataStreamerBase_->LogMessage("ProcessBuffer call returned an error.", true); - break; + AcquiredBlockCollection* acqCollection = pDataStreamerBase_->acqCollection_; + std::stringstream ss; + try { + // give the device time to acquire data + Sleep((int)(pDataStreamerBase_->updatePeriodUs_ / 1000)); + // run while the acquisition thread is active or + // there is unprocessed data in the circular acquisition buffer + while (acqThr->GetIsRunning() || acqCollection->GetSize() != 0) { + if (acqCollection->GetSize() != 0) { + std::unique_ptr newBlock = acqCollection->Remove(); + ret = pDataStreamerBase_->ProcessBuffer(std::move(newBlock->data), newBlock->actualSize); + if (ret != DEVICE_OK) { + pDataStreamerBase_->LogMessage("ProcessBuffer call returned an error.", true); + break; + } + } + else { + Sleep((int)(pDataStreamerBase_->updatePeriodUs_ / 1000)); } } - else { - Sleep((int)(pDataStreamerBase_->updatePeriodUs_ / 1000)); - } + } + catch (...) { + pDataStreamerBase_->LogMessage("Unknown processing thread exception.", true); + this->SetIsRunning(false); + return DEVICE_ERR; } pDataStreamerBase_->LogMessage("Terminating processing thread.", true); diff --git a/MMDevice/MMDevice.h b/MMDevice/MMDevice.h index f988832c7..26f6a2cbe 100644 --- a/MMDevice/MMDevice.h +++ b/MMDevice/MMDevice.h @@ -1214,7 +1214,8 @@ namespace MM { virtual int GetStreamParameters(bool& stopOnOverflow, int& numberOfBuffers, double& durationUs, double& updatePeriodUs) = 0; virtual int StartStream() = 0; virtual int StopStream() = 0; - virtual int ResetStream() = 0; + virtual bool GetOverflowStatus() = 0; + virtual int ResetOverflowStatus() = 0; virtual bool IsStreaming() = 0; virtual int SetCircularAcquisitionBufferCapacity(int capacity) = 0; virtual int GetCircularAcquisitionBufferCapacity() = 0; From f1da75deb03adcfa0131ce0b5ee7459dc445b851 Mon Sep 17 00:00:00 2001 From: "melnykov.artem" Date: Thu, 22 Dec 2022 22:04:19 -0600 Subject: [PATCH 11/14] Made changes needed for accomodating realistic hardware streaming devices --- DeviceAdapters/DemoCamera/DemoCamera.h | 18 ++- MMCore/Devices/DataStreamerInstance.cpp | 7 +- MMCore/Devices/DataStreamerInstance.h | 7 +- MMCore/MMCore.cpp | 38 +++++- MMCore/MMCore.h | 7 +- MMCoreJ_wrap/MMCoreJ.i | 4 +- MMDevice/DeviceBase.h | 158 +++++++++++++++--------- MMDevice/MMDevice.h | 17 ++- MMDevice/MMDeviceConstants.h | 5 +- 9 files changed, 181 insertions(+), 80 deletions(-) diff --git a/DeviceAdapters/DemoCamera/DemoCamera.h b/DeviceAdapters/DemoCamera/DemoCamera.h index cf911e0b2..f2cbadd3e 100644 --- a/DeviceAdapters/DemoCamera/DemoCamera.h +++ b/DeviceAdapters/DemoCamera/DemoCamera.h @@ -1219,6 +1219,8 @@ class DemoDataStreamer : public CDataStreamerBase char val = 0; for (unsigned ii = 0; ii < mockDataSize_; ii++) { mockData_[ii] = val; val++; } + SetErrorText(69, "My special error text."); + writeFile_.open("C:\\temp\\mybinaryfile.txt", std::ios::out | std::ios::binary); initialized_ = true; @@ -1237,6 +1239,19 @@ class DemoDataStreamer : public CDataStreamerBase return false; } + int StartStream() { + int ret; + LogMessage("Pre-StartStream", true); + ret = this->StartDataStreamerThreads(); + return ret; + } + + int StopStream() { + int ret; + LogMessage("Pre-StoptStream", true); + ret = this->StopDataStreamerThreads(); + return ret; + } int GetBufferSize(unsigned& dataBufferSize) { LogMessage("Demo DataStreamer: calling GetBufferSize", true); @@ -1244,7 +1259,7 @@ class DemoDataStreamer : public CDataStreamerBase return DEVICE_OK; } - std::unique_ptr GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize) { + std::unique_ptr GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize, int& exitStatus) { LogMessage("Demo DataStreamer: calling GetBuffer", true); @@ -1257,6 +1272,7 @@ class DemoDataStreamer : public CDataStreamerBase // allocate a new data array and put data in it std::unique_ptr data(new char[actualDataBufferSize]); memcpy(data.get(), mockData_, actualDataBufferSize); + exitStatus = DEVICE_OK; LogMessage("Demo DataStreamer: finished GetBuffer", true); return data; diff --git a/MMCore/Devices/DataStreamerInstance.cpp b/MMCore/Devices/DataStreamerInstance.cpp index 3e3863af9..58934875c 100644 --- a/MMCore/Devices/DataStreamerInstance.cpp +++ b/MMCore/Devices/DataStreamerInstance.cpp @@ -23,15 +23,16 @@ int DataStreamerInstance::GetBufferSize(unsigned& dataBufferSiize) { return GetImpl()->GetBufferSize(dataBufferSiize); } -std::unique_ptr DataStreamerInstance::GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize) { return GetImpl()->GetBuffer(expectedDataBufferSize,actualDataBufferSize); } +std::unique_ptr DataStreamerInstance::GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize, int& exitStatus) { return GetImpl()->GetBuffer(expectedDataBufferSize,actualDataBufferSize,exitStatus); } int DataStreamerInstance::ProcessBuffer(std::unique_ptr& pDataBuffer, unsigned dataSize) { return GetImpl()->ProcessBuffer(pDataBuffer, dataSize); } int DataStreamerInstance::StartStream() { return GetImpl()->StartStream(); } int DataStreamerInstance::StopStream() { return GetImpl()->StopStream(); } bool DataStreamerInstance::GetOverflowStatus() { return GetImpl()->GetOverflowStatus(); } int DataStreamerInstance::ResetOverflowStatus() { return GetImpl()->ResetOverflowStatus(); } +int DataStreamerInstance::GetStreamExitStatus() { return GetImpl()->GetStreamExitStatus(); } bool DataStreamerInstance::IsStreaming() { return GetImpl()->IsStreaming(); } -int DataStreamerInstance::SetStreamParameters(bool stopOnOverflow, int numberOfBuffers, double durationUs, double updatePeriodUs) { return GetImpl()->SetStreamParameters(stopOnOverflow, numberOfBuffers, durationUs, updatePeriodUs); } -int DataStreamerInstance::GetStreamParameters(bool& stopOnOverflow, int& numberOfBuffers, double& durationUs, double& updatePeriodUs) { return GetImpl()->GetStreamParameters(stopOnOverflow,numberOfBuffers,durationUs,updatePeriodUs); } +int DataStreamerInstance::SetStreamParameters(bool stopOnOverflow, int numberOfBuffers, int durationUs, int updatePeriodUs) { return GetImpl()->SetStreamParameters(stopOnOverflow, numberOfBuffers, durationUs, updatePeriodUs); } +int DataStreamerInstance::GetStreamParameters(bool& stopOnOverflow, int& numberOfBuffers, int& durationUs, int& updatePeriodUs) { return GetImpl()->GetStreamParameters(stopOnOverflow,numberOfBuffers,durationUs,updatePeriodUs); } int DataStreamerInstance::SetCircularAcquisitionBufferCapacity(int capacity) { return GetImpl()->SetCircularAcquisitionBufferCapacity(capacity); } int DataStreamerInstance::GetCircularAcquisitionBufferCapacity() { return GetImpl()->GetCircularAcquisitionBufferCapacity(); } diff --git a/MMCore/Devices/DataStreamerInstance.h b/MMCore/Devices/DataStreamerInstance.h index b74775599..6b756021c 100644 --- a/MMCore/Devices/DataStreamerInstance.h +++ b/MMCore/Devices/DataStreamerInstance.h @@ -37,15 +37,16 @@ class DataStreamerInstance : public DeviceInstanceBase {} int GetBufferSize(unsigned& dataBufferSiize); - std::unique_ptr GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize); + std::unique_ptr GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize, int& exitStatus); int ProcessBuffer(std::unique_ptr& pDataBuffer, unsigned dataSize); int StartStream(); int StopStream(); bool GetOverflowStatus(); int ResetOverflowStatus(); + int GetStreamExitStatus(); bool IsStreaming(); - int SetStreamParameters(bool stopOnOverflow, int numberOfBuffers, double durationUs, double updatePeriodUs); - int GetStreamParameters(bool& stopOnOverflow, int& numberOfBuffers, double& durationUs, double& updatePeriodUs); + int SetStreamParameters(bool stopOnOverflow, int numberOfBuffers, int durationUs, int updatePeriodUs); + int GetStreamParameters(bool& stopOnOverflow, int& numberOfBuffers, int& durationUs, int& updatePeriodUs); int SetCircularAcquisitionBufferCapacity(int capacity); int GetCircularAcquisitionBufferCapacity(); }; diff --git a/MMCore/MMCore.cpp b/MMCore/MMCore.cpp index 19f3e26f5..c7536c75c 100644 --- a/MMCore/MMCore.cpp +++ b/MMCore/MMCore.cpp @@ -6470,6 +6470,18 @@ bool CMMCore::isStreaming(const char* dataStreamerLabel) throw (CMMError) return ret; } +/** +* Get exit status of the stream +*/ +int CMMCore::getStreamExitStatus(const char* dataStreamerLabel) throw (CMMError) +{ + std::shared_ptr pDataStreamer = deviceManager_->GetDeviceOfType(dataStreamerLabel); + LOG_DEBUG(coreLogger_) << "Getting stream exit status of " << dataStreamerLabel; + mm::DeviceModuleLockGuard guard(pDataStreamer); + int ret = pDataStreamer->GetStreamExitStatus(); + return ret; +} + /** * Sets data streamer parameters * @param label the data streamer device label @@ -6479,18 +6491,18 @@ bool CMMCore::isStreaming(const char* dataStreamerLabel) throw (CMMError) * @param updatePeriodUs update period in microseconds */ void CMMCore::setStreamParameters(const char* dataStreamerLabel, bool stopOnOverflow, - int numberOfBlocks, double durationUs, double updatePeriodUs) + int numberOfBlocks, int durationMs, int updatePeriodMs) { std::shared_ptr pDataStreamer = deviceManager_->GetDeviceOfType(dataStreamerLabel); LOG_DEBUG(coreLogger_) << "Setting stream parameters of " << dataStreamerLabel << " to stopOnOverflow=" << stopOnOverflow << ", " << "numberOfBlocks=" << numberOfBlocks << ", " << - "durationUs=" << durationUs << ", " << - "updatePeriodUs=" << updatePeriodUs; + "durationMs=" << durationMs << ", " << + "updatePeriodMs=" << updatePeriodMs; mm::DeviceModuleLockGuard guard(pDataStreamer); - int ret = pDataStreamer->SetStreamParameters(stopOnOverflow, (unsigned)numberOfBlocks, durationUs, updatePeriodUs); + int ret = pDataStreamer->SetStreamParameters(stopOnOverflow, numberOfBlocks, durationMs, updatePeriodMs); if (ret != DEVICE_OK) throw CMMError(getDeviceErrorText(ret, pDataStreamer).c_str(), MMERR_DEVICE_GENERIC); } @@ -6503,12 +6515,12 @@ void CMMCore::setStreamParameters(const char* dataStreamerLabel, bool stopOnOver * @param updatePeriodUs a return parameter that gives the update rate of the stream */ void CMMCore::getStreamParameters(const char* dataStreamerLabel, bool& stopOnOverflow, - int& numberOfBlocks, double& durationUs, double& updatePeriodUs) throw (CMMError) + int& numberOfBlocks, int& durationMs, int& updatePeriodMs) throw (CMMError) { std::shared_ptr pDataStreamer = deviceManager_->GetDeviceOfType(dataStreamerLabel); LOG_DEBUG(coreLogger_) << "Getting stream parameters of " << dataStreamerLabel; mm::DeviceModuleLockGuard guard(pDataStreamer); - int ret = pDataStreamer->GetStreamParameters(stopOnOverflow, numberOfBlocks, durationUs, updatePeriodUs); + int ret = pDataStreamer->GetStreamParameters(stopOnOverflow, numberOfBlocks, durationMs, updatePeriodMs); if (ret != DEVICE_OK) throw CMMError(getDeviceErrorText(ret, pDataStreamer).c_str(), MMERR_DEVICE_GENERIC); } @@ -6539,6 +6551,20 @@ long CMMCore::getCircularAcquisitionBufferCapacity(const char* dataStreamerLabel return ret; } +/** +* Get error code message +*/ +std::string CMMCore::getErrorMessage(const char* deviceLabel, int code) throw (CMMError) +{ + std::shared_ptr pDevice = deviceManager_->GetDevice(deviceLabel); + mm::DeviceModuleLockGuard guard(pDevice); + if (code == DEVICE_OK) { + return string("Device ok."); + } + else { + return pDevice->GetErrorText(code); + } +} /** * Saves the current system state to a text file of the MM specific format. diff --git a/MMCore/MMCore.h b/MMCore/MMCore.h index 3d313d8c0..5c937b325 100644 --- a/MMCore/MMCore.h +++ b/MMCore/MMCore.h @@ -619,12 +619,15 @@ class CMMCore bool getOverflowStatus(const char* dataStreamerLabel) throw (CMMError); void resetOverflowStatus(const char* dataStreamerLabel) throw (CMMError); bool isStreaming(const char* dataStreamerLabel) throw (CMMError); + int getStreamExitStatus(const char* dataStreamerLabel) throw (CMMError); void setStreamParameters(const char* dataStreamerLabel, bool stopOnOverflow, - int numberOfBlocks, double durationUs, double updatePeriodUs) throw (CMMError); + int numberOfBlocks, int durationMs, int updatePeriodMs) throw (CMMError); void getStreamParameters(const char* dataStreamerLabel, bool& stopOnOverflow, - int& numberOfBlocks, double& durationUs, double& updatePeriodUs) throw (CMMError); + int& numberOfBlocks, int& durationMs, int& updatePeriodMs) throw (CMMError); void setCircularAcquisitionBufferCapacity(const char* dataStreamerLabel, int capacity) throw (CMMError); long getCircularAcquisitionBufferCapacity(const char* dataStreamerLabel) throw (CMMError); + + std::string getErrorMessage(const char* deviceLabel, int code) throw (CMMError); ///@} /** \name Device discovery. */ diff --git a/MMCoreJ_wrap/MMCoreJ.i b/MMCoreJ_wrap/MMCoreJ.i index 4fb20b0b9..e1c30a7c1 100644 --- a/MMCoreJ_wrap/MMCoreJ.i +++ b/MMCoreJ_wrap/MMCoreJ.i @@ -289,8 +289,8 @@ %apply int &OUTPUT { int &ySize }; %apply bool &OUTPUT { bool &stopOnOverflow }; %apply int &OUTPUT { int &numberOfBlocks }; -%apply double &OUTPUT { double &durationUs }; -%apply double &OUTPUT { double &updatePeriodUs }; +%apply int &OUTPUT { int &durationMs }; +%apply int &OUTPUT { int &updatePeriodMs }; // Java typemap diff --git a/MMDevice/DeviceBase.h b/MMDevice/DeviceBase.h index 0b2e94d1e..efe440123 100644 --- a/MMDevice/DeviceBase.h +++ b/MMDevice/DeviceBase.h @@ -82,7 +82,11 @@ const char* const g_Msg_DEVICE_DUPLICATE_LIBRARY="Duplicate Device Library Name" const char* const g_Msg_DEVICE_PROPERTY_NOT_SEQUENCEABLE="This property is not sequenceable"; const char* const g_Msg_DEVICE_SEQUENCE_TOO_LARGE="Sequence is too large for this device"; const char* const g_Msg_DEVICE_NOT_YET_IMPLEMENTED="This command has not yet been implemented for this device."; -const char* const g_Msg_DEVICE_DATASTREAMER_BUSY_ACQUIRING = "Not allowed while data streamer is running"; +const char* const g_Msg_DEVICE_DATASTREAMER_BUSY_ACQUIRING = "Data streamer is running"; +const char* const g_Msg_DEVICE_DATASTREAMER_STOPPED_ON_USER_SELECTION = "Stopped on user request"; +const char* const g_Msg_DEVICE_DATASTREAMER_STOPPED_ON_OVERFLOW = "Stopped on circular acquisition buffer overflow"; +const char* const g_Msg_DEVICE_DATASTREAMER_STOPPED_ON_NBLOCKS_COLLECTED = "Stopped on collecting specified number of blocks"; +const char* const g_Msg_DEVICE_DATASTREAMER_STOPPED_ON_TIME_ELAPSED = "Stopped on DataStreamer time elapsed"; inline long nint( double value ) { @@ -951,6 +955,10 @@ class CDeviceBase : public T SetErrorText(DEVICE_SEQUENCE_TOO_LARGE, g_Msg_DEVICE_SEQUENCE_TOO_LARGE); SetErrorText(DEVICE_NOT_YET_IMPLEMENTED, g_Msg_DEVICE_NOT_YET_IMPLEMENTED); SetErrorText(DEVICE_DATASTREAMER_BUSY_ACQUIRING, g_Msg_DEVICE_DATASTREAMER_BUSY_ACQUIRING); + SetErrorText(DEVICE_DATASTREAMER_STOPPED_ON_USER_SELECTION, g_Msg_DEVICE_DATASTREAMER_STOPPED_ON_USER_SELECTION); + SetErrorText(DEVICE_DATASTREAMER_STOPPED_ON_OVERFLOW, g_Msg_DEVICE_DATASTREAMER_STOPPED_ON_OVERFLOW); + SetErrorText(DEVICE_DATASTREAMER_STOPPED_ON_NBLOCKS_COLLECTED, g_Msg_DEVICE_DATASTREAMER_STOPPED_ON_NBLOCKS_COLLECTED); + SetErrorText(DEVICE_DATASTREAMER_STOPPED_ON_TIME_ELAPSED, g_Msg_DEVICE_DATASTREAMER_STOPPED_ON_TIME_ELAPSED); } /** @@ -2247,7 +2255,7 @@ class CDataStreamerBase : public CDeviceBase { friend class AcquiredBlockCollection; public: - CDataStreamerBase() : numberOfBlocks_(1), durationUs_(1e6), updatePeriodUs_(1e5), + CDataStreamerBase() : numberOfBlocks_(1), durationMs_(1000), updatePeriodMs_(100), stopOnOverflow_(true), stopFlag_(false), acqCollectionCapacity_(10) { acqCollection_ = new AcquiredBlockCollection(acqCollectionCapacity_, stopOnOverflow_); @@ -2269,33 +2277,9 @@ class CDataStreamerBase : public CDeviceBase delete acqCollection_; } - virtual int GetBufferSize(unsigned& dataBufferSiize) = 0; - virtual std::unique_ptr GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize) = 0; - virtual int ProcessBuffer(std::unique_ptr& pDataBuffer, unsigned actualDataBufferSize) = 0; + virtual int StartStream() = 0; - virtual int SetStreamParameters(bool stopOnOverflow, int numberOfBlocks, double durationUs, double updatePeriodUs) - { - if (IsStreaming()) return DEVICE_DATASTREAMER_BUSY_ACQUIRING; - if (numberOfBlocks <= 0 || durationUs <= 0 || updatePeriodUs <= 0) return DEVICE_INVALID_INPUT_PARAM; - stopOnOverflow_ = stopOnOverflow; - numberOfBlocks_ = numberOfBlocks; - durationUs_ = durationUs; - updatePeriodUs_ = updatePeriodUs; - delete acqCollection_; - acqCollection_ = new AcquiredBlockCollection(acqCollectionCapacity_, stopOnOverflow_); - return DEVICE_OK; - } - - virtual int GetStreamParameters(bool& stopOnOverflow, int& numberOfBlocks, double& durationUs, double& updatePeriodUs) - { - stopOnOverflow = stopOnOverflow_; - numberOfBlocks = numberOfBlocks_; - durationUs = durationUs_; - updatePeriodUs = updatePeriodUs_; - return DEVICE_OK; - } - - virtual int StartStream() + int StartDataStreamerThreads() { if (IsStreaming()) return DEVICE_DATASTREAMER_BUSY_ACQUIRING; thdAcq_->Start(); @@ -2303,7 +2287,9 @@ class CDataStreamerBase : public CDeviceBase return DEVICE_OK; } - virtual int StopStream() { + virtual int StopStream() = 0; + + int StopDataStreamerThreads() { // a non-blocking implementaion if (thdAcq_->IsRunning()) { thdAcq_->Stop(); @@ -2314,6 +2300,33 @@ class CDataStreamerBase : public CDeviceBase } return DEVICE_OK; } + + virtual int GetBufferSize(unsigned& dataBufferSiize) = 0; + virtual std::unique_ptr GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize, int& exitCode) = 0; + virtual int ProcessBuffer(std::unique_ptr& pDataBuffer, unsigned actualDataBufferSize) = 0; + + virtual int SetStreamParameters(bool stopOnOverflow, int numberOfBlocks, int durationMs, int updatePeriodMs) + { + if (IsStreaming()) return DEVICE_DATASTREAMER_BUSY_ACQUIRING; + if (numberOfBlocks <= 0 || durationMs <= 0 || updatePeriodMs < 0) return DEVICE_INVALID_INPUT_PARAM; + stopOnOverflow_ = stopOnOverflow; + numberOfBlocks_ = numberOfBlocks; + durationMs_ = durationMs; + updatePeriodMs_ = updatePeriodMs; + delete acqCollection_; + acqCollection_ = new AcquiredBlockCollection(acqCollectionCapacity_, stopOnOverflow_); + return DEVICE_OK; + } + + virtual int GetStreamParameters(bool& stopOnOverflow, int& numberOfBlocks, int& durationMs, int& updatePeriodMs) + { + stopOnOverflow = stopOnOverflow_; + numberOfBlocks = numberOfBlocks_; + durationMs = durationMs_; + updatePeriodMs = updatePeriodMs_; + return DEVICE_OK; + } + virtual bool GetOverflowStatus() { return acqCollection_->GetOverflowStatus(); } @@ -2332,6 +2345,10 @@ class CDataStreamerBase : public CDeviceBase } } + virtual int GetStreamExitStatus() { + return thdAcq_->GetExitStatus(); + } + virtual int SetCircularAcquisitionBufferCapacity(int capacity) { if (IsStreaming()) return DEVICE_DATASTREAMER_BUSY_ACQUIRING; if (capacity <= 0) return DEVICE_INVALID_INPUT_PARAM; @@ -2375,69 +2392,86 @@ class CDataStreamerBase : public CDeviceBase CDataStreamerBase* pDataStreamerBase_; bool isRunning_; bool stopFlag_; + int exitStatus_; MMThreadLock stopLock_; MMThreadLock isRunningLock_; + MMThreadLock exitStatusLock_; // Provide description here int svc(void) throw () { - int retSize = DEVICE_OK; - int retBuffer = DEVICE_OK; + this->SetExitStatus(DEVICE_DATASTREAMER_BUSY_ACQUIRING); + int retGetBufferSize = DEVICE_OK; unsigned int expectedDataSize, actualDataSize; + int exitStatus = DEVICE_OK; unsigned int blockCounter = 0; AcquiredBlockCollection* acqCollection = pDataStreamerBase_->acqCollection_; MM::MMTime startTime = pDataStreamerBase_->GetCurrentMMTime(); MM::MMTime timeSinceStart = pDataStreamerBase_->GetCurrentMMTime() - startTime; + MM::MMTime lastCallTime = pDataStreamerBase_->GetCurrentMMTime(); std::stringstream ss; try { // check all stopping conditions while (!(this->GetStopFlag() || //read externally set stop flag blockCounter >= pDataStreamerBase_->numberOfBlocks_ || // stop if desired number of blocks have been collected (acqCollection->GetOverflowStatus() && pDataStreamerBase_->stopOnOverflow_) || // buffer overflow - timeSinceStart > MM::MMTime(pDataStreamerBase_->durationUs_))) { // collection time elapsed - Sleep((int)(pDataStreamerBase_->updatePeriodUs_ / 1000)); - timeSinceStart = pDataStreamerBase_->GetCurrentMMTime() - startTime; - retSize = pDataStreamerBase_->GetBufferSize(expectedDataSize); - if (retSize != DEVICE_OK) break; + timeSinceStart > MM::MMTime(pDataStreamerBase_->durationMs_*1000))) { // collection time elapsed + + // check for new data only if updatePeriodMs has elapsed + if (pDataStreamerBase_->updatePeriodMs_ > pDataStreamerBase_->GetCurrentMMTime().getMsec() - lastCallTime.getMsec()) { + Sleep((int)(pDataStreamerBase_->GetCurrentMMTime().getMsec() - lastCallTime.getMsec())); + continue; + } + lastCallTime = pDataStreamerBase_->GetCurrentMMTime(); + // check for new data + retGetBufferSize = pDataStreamerBase_->GetBufferSize(expectedDataSize); + if (retGetBufferSize != DEVICE_OK) break; if (expectedDataSize != 0) { std::unique_ptr newBlock(new acquired_block); - newBlock->data = pDataStreamerBase_->GetBuffer(expectedDataSize, actualDataSize); - if (newBlock->data == 0) { - retBuffer = DEVICE_ERR; - break; + newBlock->data = pDataStreamerBase_->GetBuffer(expectedDataSize, actualDataSize, exitStatus); + if (newBlock->data != 0) { + newBlock->expectedSize = expectedDataSize; + newBlock->actualSize = actualDataSize; + acqCollection->Add(newBlock); + blockCounter++; } - newBlock->expectedSize = expectedDataSize; - newBlock->actualSize = actualDataSize; - acqCollection->Add(newBlock); - blockCounter++; + if (exitStatus != DEVICE_OK) break; } + timeSinceStart = pDataStreamerBase_->GetCurrentMMTime() - startTime; + } } catch (...) { pDataStreamerBase_->LogMessage("Unknown acquisition thread exception.", true); this->SetIsRunning(false); - stopFlag_ = false; + this->SetStopFlag(false); return DEVICE_ERR; } ss << "Terminating acuisition thread for the following reason: "; if (this->GetStopFlag()) { ss << " user selection"; + this->SetExitStatus(DEVICE_DATASTREAMER_STOPPED_ON_USER_SELECTION); } else if (acqCollection->GetOverflowStatus() && pDataStreamerBase_->stopOnOverflow_) { ss << "acquisition buffer overflow"; + this->SetExitStatus(DEVICE_DATASTREAMER_STOPPED_ON_OVERFLOW); } else if (blockCounter >= pDataStreamerBase_->numberOfBlocks_) { ss << "desired number of blocks (" << blockCounter << ") have been collected"; + this->SetExitStatus(DEVICE_DATASTREAMER_STOPPED_ON_NBLOCKS_COLLECTED); } - else if (timeSinceStart > MM::MMTime(pDataStreamerBase_->durationUs_)) { - ss << "acquisition time exceeded the set limit (" << pDataStreamerBase_->durationUs_ << " microseconds)"; + else if (timeSinceStart > MM::MMTime(pDataStreamerBase_->durationMs_*1000)) { + ss << "acquisition time exceeded the set limit (" << pDataStreamerBase_->durationMs_ << " milliseconds)"; + this->SetExitStatus(DEVICE_DATASTREAMER_STOPPED_ON_TIME_ELAPSED); } - else if (retSize != DEVICE_OK) { - ss << "GetBufferSize call returned an error"; + else if (retGetBufferSize != DEVICE_OK) { + ss << "GetBufferSize call returned code " << retGetBufferSize; + this->SetExitStatus(retGetBufferSize); } - else if (retBuffer != DEVICE_OK) { - ss << "GetBuffer call returned an error"; + else if (exitStatus != DEVICE_OK) { + ss << "GetBuffer call reported exit status " << exitStatus; + this->SetExitStatus(exitStatus); } else { ss << "unknown"; @@ -2445,8 +2479,8 @@ class CDataStreamerBase : public CDeviceBase pDataStreamerBase_->LogMessage(ss.str(), true); this->SetIsRunning(false); - stopFlag_ = false; - return DEVICE_OK; + this->SetStopFlag(false); + return this->GetExitStatus(); } void SetStopFlag(bool stop) { @@ -2469,6 +2503,16 @@ class CDataStreamerBase : public CDeviceBase return isRunning_; } + void SetExitStatus(int exitStatus) { + MMThreadGuard g(this->exitStatusLock_); + exitStatus_ = exitStatus; + } + + int GetExitStatus() { + MMThreadGuard g(this->exitStatusLock_); + return exitStatus_; + } + }; class ProcessingThread : public MMDeviceThreadBase @@ -2506,7 +2550,7 @@ class CDataStreamerBase : public CDeviceBase std::stringstream ss; try { // give the device time to acquire data - Sleep((int)(pDataStreamerBase_->updatePeriodUs_ / 1000)); + Sleep(pDataStreamerBase_->updatePeriodMs_); // run while the acquisition thread is active or // there is unprocessed data in the circular acquisition buffer while (acqThr->GetIsRunning() || acqCollection->GetSize() != 0) { @@ -2519,7 +2563,7 @@ class CDataStreamerBase : public CDeviceBase } } else { - Sleep((int)(pDataStreamerBase_->updatePeriodUs_ / 1000)); + Sleep(pDataStreamerBase_->updatePeriodMs_); } } } @@ -2549,8 +2593,8 @@ class CDataStreamerBase : public CDeviceBase private: unsigned numberOfBlocks_; - double durationUs_; - double updatePeriodUs_; + int durationMs_; + int updatePeriodMs_; bool stopOnOverflow_; bool stopFlag_; AcquiredBlockCollection* acqCollection_; diff --git a/MMDevice/MMDevice.h b/MMDevice/MMDevice.h index 26f6a2cbe..1ab82d396 100644 --- a/MMDevice/MMDevice.h +++ b/MMDevice/MMDevice.h @@ -1193,6 +1193,14 @@ namespace MM { // Calls that are specific to each DataStreamer device // and should be implemented in the device adapter + /** + * To implement, tell the hardware to start streaming data, then call StartDataStreamerThreads + */ + virtual int StartStream() = 0; + /** + * To implement, tell the hardware to stop streaming data, then call StopDataStreamerThreads + */ + virtual int StopStream() = 0; /** * Get the expected size (in bytes) of the data buffer available for download from the hardware */ @@ -1202,7 +1210,7 @@ namespace MM { * specified by pDataBuffer; * update the size of the buffer and pass it as actualDataBufferSize */ - virtual std::unique_ptr GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize) = 0; + virtual std::unique_ptr GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize, int& exitCode) = 0; /** * Process the data buffer available at pDataBuffer */ @@ -1210,13 +1218,12 @@ namespace MM { // Calls that are implemented at the DeviceBase level and // remain the same for any DataStreamer device - virtual int SetStreamParameters(bool stopOnOverflow, int numberOfBuffers, double durationUs, double updatePeriodUs) = 0; - virtual int GetStreamParameters(bool& stopOnOverflow, int& numberOfBuffers, double& durationUs, double& updatePeriodUs) = 0; - virtual int StartStream() = 0; - virtual int StopStream() = 0; + virtual int SetStreamParameters(bool stopOnOverflow, int numberOfBuffers, int durationMs, int updatePeriodMs) = 0; + virtual int GetStreamParameters(bool& stopOnOverflow, int& numberOfBuffers, int& durationMs, int& updatePeriodMs) = 0; virtual bool GetOverflowStatus() = 0; virtual int ResetOverflowStatus() = 0; virtual bool IsStreaming() = 0; + virtual int GetStreamExitStatus() = 0; virtual int SetCircularAcquisitionBufferCapacity(int capacity) = 0; virtual int GetCircularAcquisitionBufferCapacity() = 0; }; diff --git a/MMDevice/MMDeviceConstants.h b/MMDevice/MMDeviceConstants.h index b7bf2e136..2043ea4db 100644 --- a/MMDevice/MMDeviceConstants.h +++ b/MMDevice/MMDeviceConstants.h @@ -79,7 +79,10 @@ #define DEVICE_OUT_OF_MEMORY 40 #define DEVICE_NOT_YET_IMPLEMENTED 41 #define DEVICE_DATASTREAMER_BUSY_ACQUIRING 42 - +#define DEVICE_DATASTREAMER_STOPPED_ON_USER_SELECTION 43 +#define DEVICE_DATASTREAMER_STOPPED_ON_OVERFLOW 44 +#define DEVICE_DATASTREAMER_STOPPED_ON_NBLOCKS_COLLECTED 45 +#define DEVICE_DATASTREAMER_STOPPED_ON_TIME_ELAPSED 46 namespace MM { const int MaxStrLength = 1024; From a5c5d99f3af478c7a3b4167f852d8774f23de9d4 Mon Sep 17 00:00:00 2001 From: "melnykov.artem" Date: Mon, 9 Jan 2023 17:02:05 -0600 Subject: [PATCH 12/14] Added acquisition pausing, a flag for pausing before overflow; added reading exit status of the processing thread --- MMCore/Devices/DataStreamerInstance.cpp | 9 ++- MMCore/Devices/DataStreamerInstance.h | 9 ++- MMCore/MMCore.cpp | 51 +++++++++++++--- MMCore/MMCore.h | 9 ++- MMCoreJ_wrap/MMCoreJ.i | 1 + MMDevice/DeviceBase.h | 81 +++++++++++++++++++++---- MMDevice/MMDevice.h | 9 ++- 7 files changed, 138 insertions(+), 31 deletions(-) diff --git a/MMCore/Devices/DataStreamerInstance.cpp b/MMCore/Devices/DataStreamerInstance.cpp index 58934875c..52f600154 100644 --- a/MMCore/Devices/DataStreamerInstance.cpp +++ b/MMCore/Devices/DataStreamerInstance.cpp @@ -29,10 +29,13 @@ int DataStreamerInstance::StartStream() { return GetImpl()->StartStream(); } int DataStreamerInstance::StopStream() { return GetImpl()->StopStream(); } bool DataStreamerInstance::GetOverflowStatus() { return GetImpl()->GetOverflowStatus(); } int DataStreamerInstance::ResetOverflowStatus() { return GetImpl()->ResetOverflowStatus(); } -int DataStreamerInstance::GetStreamExitStatus() { return GetImpl()->GetStreamExitStatus(); } +int DataStreamerInstance::GetAcquisitionExitStatus() { return GetImpl()->GetAcquisitionExitStatus(); } +int DataStreamerInstance::GetProcessingExitStatus() { return GetImpl()->GetProcessingExitStatus(); } +int DataStreamerInstance::SetAcquisitionPause(bool pause) { return GetImpl()->SetAcquisitionPause(pause); } +bool DataStreamerInstance::GetAcquisitionPause() { return GetImpl()->GetAcquisitionPause(); } bool DataStreamerInstance::IsStreaming() { return GetImpl()->IsStreaming(); } -int DataStreamerInstance::SetStreamParameters(bool stopOnOverflow, int numberOfBuffers, int durationUs, int updatePeriodUs) { return GetImpl()->SetStreamParameters(stopOnOverflow, numberOfBuffers, durationUs, updatePeriodUs); } -int DataStreamerInstance::GetStreamParameters(bool& stopOnOverflow, int& numberOfBuffers, int& durationUs, int& updatePeriodUs) { return GetImpl()->GetStreamParameters(stopOnOverflow,numberOfBuffers,durationUs,updatePeriodUs); } +int DataStreamerInstance::SetStreamParameters(bool stopOnOverflow, bool pauseAcquisitionBeforeOverflow, int numberOfBuffers, int durationUs, int updatePeriodUs) { return GetImpl()->SetStreamParameters(stopOnOverflow, pauseAcquisitionBeforeOverflow, numberOfBuffers, durationUs, updatePeriodUs); } +int DataStreamerInstance::GetStreamParameters(bool& stopOnOverflow, bool& pauseAcquisitionBeforeOverflow, int& numberOfBuffers, int& durationUs, int& updatePeriodUs) { return GetImpl()->GetStreamParameters(stopOnOverflow,pauseAcquisitionBeforeOverflow,numberOfBuffers,durationUs,updatePeriodUs); } int DataStreamerInstance::SetCircularAcquisitionBufferCapacity(int capacity) { return GetImpl()->SetCircularAcquisitionBufferCapacity(capacity); } int DataStreamerInstance::GetCircularAcquisitionBufferCapacity() { return GetImpl()->GetCircularAcquisitionBufferCapacity(); } diff --git a/MMCore/Devices/DataStreamerInstance.h b/MMCore/Devices/DataStreamerInstance.h index 6b756021c..067a02ff4 100644 --- a/MMCore/Devices/DataStreamerInstance.h +++ b/MMCore/Devices/DataStreamerInstance.h @@ -43,10 +43,13 @@ class DataStreamerInstance : public DeviceInstanceBase int StopStream(); bool GetOverflowStatus(); int ResetOverflowStatus(); - int GetStreamExitStatus(); + int GetAcquisitionExitStatus(); + int GetProcessingExitStatus(); + int SetAcquisitionPause(bool pause); + bool GetAcquisitionPause(); bool IsStreaming(); - int SetStreamParameters(bool stopOnOverflow, int numberOfBuffers, int durationUs, int updatePeriodUs); - int GetStreamParameters(bool& stopOnOverflow, int& numberOfBuffers, int& durationUs, int& updatePeriodUs); + int SetStreamParameters(bool stopOnOverflow, bool pauseAcquisitionBeforeOverflow, int numberOfBuffers, int durationUs, int updatePeriodUs); + int GetStreamParameters(bool& stopOnOverflow, bool& pauseAcquisitionBeforeOverflow, int& numberOfBuffers, int& durationUs, int& updatePeriodUs); int SetCircularAcquisitionBufferCapacity(int capacity); int GetCircularAcquisitionBufferCapacity(); }; diff --git a/MMCore/MMCore.cpp b/MMCore/MMCore.cpp index c7536c75c..a069f553d 100644 --- a/MMCore/MMCore.cpp +++ b/MMCore/MMCore.cpp @@ -6458,6 +6458,30 @@ void CMMCore::resetOverflowStatus(const char* dataStreamerLabel) throw (CMMError if (ret != DEVICE_OK) throw CMMError(getDeviceErrorText(ret, pDataStreamer).c_str(), MMERR_DEVICE_GENERIC); } +/** +* Get pause status of the specified data streamer. +*/ +bool CMMCore::getAcquisitionPause(const char* dataStreamerLabel) throw (CMMError) +{ + std::shared_ptr pDataStreamer = deviceManager_->GetDeviceOfType(dataStreamerLabel); + LOG_DEBUG(coreLogger_) << "Checking pause status of " << dataStreamerLabel; + mm::DeviceModuleLockGuard guard(pDataStreamer); + int ret = pDataStreamer->GetAcquisitionPause(); + return ret; +} + +/** +* Set acquisition pause on the specified data streamer. +*/ +void CMMCore::setAcquisitionPause(const char* dataStreamerLabel, bool pause) throw (CMMError) +{ + std::shared_ptr pDataStreamer = deviceManager_->GetDeviceOfType(dataStreamerLabel); + LOG_DEBUG(coreLogger_) << "Setting acquisition pause of " << dataStreamerLabel; + mm::DeviceModuleLockGuard guard(pDataStreamer); + int ret = pDataStreamer->SetAcquisitionPause(pause); + if (ret != DEVICE_OK) throw CMMError(getDeviceErrorText(ret, pDataStreamer).c_str(), MMERR_DEVICE_GENERIC); +} + /** * Get streaming status of the specified data streamer. */ @@ -6471,14 +6495,26 @@ bool CMMCore::isStreaming(const char* dataStreamerLabel) throw (CMMError) } /** -* Get exit status of the stream +* Get acquisition thread exit status +*/ +int CMMCore::getAcquisitionExitStatus(const char* dataStreamerLabel) throw (CMMError) +{ + std::shared_ptr pDataStreamer = deviceManager_->GetDeviceOfType(dataStreamerLabel); + LOG_DEBUG(coreLogger_) << "Getting stream exit status of " << dataStreamerLabel; + mm::DeviceModuleLockGuard guard(pDataStreamer); + int ret = pDataStreamer->GetAcquisitionExitStatus(); + return ret; +} + +/** +* Get acquisition thread exit status */ -int CMMCore::getStreamExitStatus(const char* dataStreamerLabel) throw (CMMError) +int CMMCore::getProcessingExitStatus(const char* dataStreamerLabel) throw (CMMError) { std::shared_ptr pDataStreamer = deviceManager_->GetDeviceOfType(dataStreamerLabel); LOG_DEBUG(coreLogger_) << "Getting stream exit status of " << dataStreamerLabel; mm::DeviceModuleLockGuard guard(pDataStreamer); - int ret = pDataStreamer->GetStreamExitStatus(); + int ret = pDataStreamer->GetProcessingExitStatus(); return ret; } @@ -6490,19 +6526,20 @@ int CMMCore::getStreamExitStatus(const char* dataStreamerLabel) throw (CMMError) * @param durationUs collection duration in microseconds * @param updatePeriodUs update period in microseconds */ -void CMMCore::setStreamParameters(const char* dataStreamerLabel, bool stopOnOverflow, +void CMMCore::setStreamParameters(const char* dataStreamerLabel, bool stopOnOverflow, bool pauseAcquisitionBeforeOverflow, int numberOfBlocks, int durationMs, int updatePeriodMs) { std::shared_ptr pDataStreamer = deviceManager_->GetDeviceOfType(dataStreamerLabel); LOG_DEBUG(coreLogger_) << "Setting stream parameters of " << dataStreamerLabel << " to stopOnOverflow=" << stopOnOverflow << ", " << + "pauseAcquisitionBeforeOverflow=" << pauseAcquisitionBeforeOverflow << ", " << "numberOfBlocks=" << numberOfBlocks << ", " << "durationMs=" << durationMs << ", " << "updatePeriodMs=" << updatePeriodMs; mm::DeviceModuleLockGuard guard(pDataStreamer); - int ret = pDataStreamer->SetStreamParameters(stopOnOverflow, numberOfBlocks, durationMs, updatePeriodMs); + int ret = pDataStreamer->SetStreamParameters(stopOnOverflow, pauseAcquisitionBeforeOverflow, numberOfBlocks, durationMs, updatePeriodMs); if (ret != DEVICE_OK) throw CMMError(getDeviceErrorText(ret, pDataStreamer).c_str(), MMERR_DEVICE_GENERIC); } @@ -6514,13 +6551,13 @@ void CMMCore::setStreamParameters(const char* dataStreamerLabel, bool stopOnOver * @param durationUs a return parameter that gives duration of the stream * @param updatePeriodUs a return parameter that gives the update rate of the stream */ -void CMMCore::getStreamParameters(const char* dataStreamerLabel, bool& stopOnOverflow, +void CMMCore::getStreamParameters(const char* dataStreamerLabel, bool& stopOnOverflow, bool& pauseAcquisitionBeforeOverflow, int& numberOfBlocks, int& durationMs, int& updatePeriodMs) throw (CMMError) { std::shared_ptr pDataStreamer = deviceManager_->GetDeviceOfType(dataStreamerLabel); LOG_DEBUG(coreLogger_) << "Getting stream parameters of " << dataStreamerLabel; mm::DeviceModuleLockGuard guard(pDataStreamer); - int ret = pDataStreamer->GetStreamParameters(stopOnOverflow, numberOfBlocks, durationMs, updatePeriodMs); + int ret = pDataStreamer->GetStreamParameters(stopOnOverflow, pauseAcquisitionBeforeOverflow, numberOfBlocks, durationMs, updatePeriodMs); if (ret != DEVICE_OK) throw CMMError(getDeviceErrorText(ret, pDataStreamer).c_str(), MMERR_DEVICE_GENERIC); } diff --git a/MMCore/MMCore.h b/MMCore/MMCore.h index 5c937b325..3447ae975 100644 --- a/MMCore/MMCore.h +++ b/MMCore/MMCore.h @@ -618,11 +618,14 @@ class CMMCore void stopStream(const char* dataStreamerLabel) throw (CMMError); bool getOverflowStatus(const char* dataStreamerLabel) throw (CMMError); void resetOverflowStatus(const char* dataStreamerLabel) throw (CMMError); + bool getAcquisitionPause(const char* dataStreamerLabel) throw (CMMError); + void setAcquisitionPause(const char* dataStreamerLabel, bool pause) throw (CMMError); bool isStreaming(const char* dataStreamerLabel) throw (CMMError); - int getStreamExitStatus(const char* dataStreamerLabel) throw (CMMError); - void setStreamParameters(const char* dataStreamerLabel, bool stopOnOverflow, + int getAcquisitionExitStatus(const char* dataStreamerLabel) throw (CMMError); + int getProcessingExitStatus(const char* dataStreamerLabel) throw (CMMError); + void setStreamParameters(const char* dataStreamerLabel, bool stopOnOverflow, bool pauseAcquisitionBeforeOverflow, int numberOfBlocks, int durationMs, int updatePeriodMs) throw (CMMError); - void getStreamParameters(const char* dataStreamerLabel, bool& stopOnOverflow, + void getStreamParameters(const char* dataStreamerLabel, bool& stopOnOverflow, bool& pauseAcquisitionBeforeOverflow, int& numberOfBlocks, int& durationMs, int& updatePeriodMs) throw (CMMError); void setCircularAcquisitionBufferCapacity(const char* dataStreamerLabel, int capacity) throw (CMMError); long getCircularAcquisitionBufferCapacity(const char* dataStreamerLabel) throw (CMMError); diff --git a/MMCoreJ_wrap/MMCoreJ.i b/MMCoreJ_wrap/MMCoreJ.i index e1c30a7c1..66521b138 100644 --- a/MMCoreJ_wrap/MMCoreJ.i +++ b/MMCoreJ_wrap/MMCoreJ.i @@ -288,6 +288,7 @@ %apply int &OUTPUT { int &xSize }; %apply int &OUTPUT { int &ySize }; %apply bool &OUTPUT { bool &stopOnOverflow }; +%apply bool &OUTPUT { bool &pauseBeforeOverflow }; %apply int &OUTPUT { int &numberOfBlocks }; %apply int &OUTPUT { int &durationMs }; %apply int &OUTPUT { int &updatePeriodMs }; diff --git a/MMDevice/DeviceBase.h b/MMDevice/DeviceBase.h index efe440123..03fe33ede 100644 --- a/MMDevice/DeviceBase.h +++ b/MMDevice/DeviceBase.h @@ -2282,6 +2282,8 @@ class CDataStreamerBase : public CDeviceBase int StartDataStreamerThreads() { if (IsStreaming()) return DEVICE_DATASTREAMER_BUSY_ACQUIRING; + delete acqCollection_; + acqCollection_ = new AcquiredBlockCollection(acqCollectionCapacity_, stopOnOverflow_); thdAcq_->Start(); thdProc_->Start(); return DEVICE_OK; @@ -2305,28 +2307,37 @@ class CDataStreamerBase : public CDeviceBase virtual std::unique_ptr GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize, int& exitCode) = 0; virtual int ProcessBuffer(std::unique_ptr& pDataBuffer, unsigned actualDataBufferSize) = 0; - virtual int SetStreamParameters(bool stopOnOverflow, int numberOfBlocks, int durationMs, int updatePeriodMs) + virtual int SetStreamParameters(bool stopOnOverflow, bool pauseAcquisitionBeforeOverflow, int numberOfBlocks, int durationMs, int updatePeriodMs) { if (IsStreaming()) return DEVICE_DATASTREAMER_BUSY_ACQUIRING; if (numberOfBlocks <= 0 || durationMs <= 0 || updatePeriodMs < 0) return DEVICE_INVALID_INPUT_PARAM; stopOnOverflow_ = stopOnOverflow; + pauseAcquisitionBeforeOverflow_ = pauseAcquisitionBeforeOverflow; numberOfBlocks_ = numberOfBlocks; durationMs_ = durationMs; updatePeriodMs_ = updatePeriodMs; - delete acqCollection_; - acqCollection_ = new AcquiredBlockCollection(acqCollectionCapacity_, stopOnOverflow_); return DEVICE_OK; } - virtual int GetStreamParameters(bool& stopOnOverflow, int& numberOfBlocks, int& durationMs, int& updatePeriodMs) + virtual int GetStreamParameters(bool& stopOnOverflow, bool& pauseAcquisitionBeforeOverflow, int& numberOfBlocks, int& durationMs, int& updatePeriodMs) { stopOnOverflow = stopOnOverflow_; + pauseAcquisitionBeforeOverflow = pauseAcquisitionBeforeOverflow_; numberOfBlocks = numberOfBlocks_; durationMs = durationMs_; updatePeriodMs = updatePeriodMs_; return DEVICE_OK; } + virtual int SetAcquisitionPause(bool pause) { + if (!thdAcq_->IsRunning()) return DEVICE_OK; + thdAcq_->SetPause(pause); + } + + virtual bool GetAcquisitionPause() { + return thdAcq_->GetPause(); + } + virtual bool GetOverflowStatus() { return acqCollection_->GetOverflowStatus(); } @@ -2345,10 +2356,14 @@ class CDataStreamerBase : public CDeviceBase } } - virtual int GetStreamExitStatus() { + virtual int GetAcquisitionExitStatus() { return thdAcq_->GetExitStatus(); } + virtual int GetProcessingExitStatus() { + return thdProc_->GetExitStatus(); + } + virtual int SetCircularAcquisitionBufferCapacity(int capacity) { if (IsStreaming()) return DEVICE_DATASTREAMER_BUSY_ACQUIRING; if (capacity <= 0) return DEVICE_INVALID_INPUT_PARAM; @@ -2367,7 +2382,7 @@ class CDataStreamerBase : public CDeviceBase friend class CDataStreamerBase; friend class AcquiredBlockCollection; public: - AcquisitionThread(CDataStreamerBase* p) : isRunning_(false),stopFlag_(false) + AcquisitionThread(CDataStreamerBase* p) : isRunning_(false),stopFlag_(false),pause_(false) { pDataStreamerBase_ = p; } @@ -2392,9 +2407,11 @@ class CDataStreamerBase : public CDeviceBase CDataStreamerBase* pDataStreamerBase_; bool isRunning_; bool stopFlag_; + bool pause_; int exitStatus_; MMThreadLock stopLock_; MMThreadLock isRunningLock_; + MMThreadLock pauseLock_; MMThreadLock exitStatusLock_; // Provide description here @@ -2417,6 +2434,20 @@ class CDataStreamerBase : public CDeviceBase (acqCollection->GetOverflowStatus() && pDataStreamerBase_->stopOnOverflow_) || // buffer overflow timeSinceStart > MM::MMTime(pDataStreamerBase_->durationMs_*1000))) { // collection time elapsed + if (pDataStreamerBase_->pauseAcquisitionBeforeOverflow_) { + // request a pause before overflow happens + if (acqCollection->GetSize() == acqCollection->GetCapacity()) { + this->SetPause(true); + } + else { + this->SetPause(false); + } + } + // pause if requested + if (this->GetPause()) { + Sleep((int)(pDataStreamerBase_->GetCurrentMMTime().getMsec() - lastCallTime.getMsec())); + continue; + } // check for new data only if updatePeriodMs has elapsed if (pDataStreamerBase_->updatePeriodMs_ > pDataStreamerBase_->GetCurrentMMTime().getMsec() - lastCallTime.getMsec()) { Sleep((int)(pDataStreamerBase_->GetCurrentMMTime().getMsec() - lastCallTime.getMsec())); @@ -2503,6 +2534,16 @@ class CDataStreamerBase : public CDeviceBase return isRunning_; } + void SetPause(bool pause) { + MMThreadGuard g(this->pauseLock_); + pause_ = pause; + } + + bool GetPause() { + MMThreadGuard g(this->pauseLock_); + return pause_; + } + void SetExitStatus(int exitStatus) { MMThreadGuard g(this->exitStatusLock_); exitStatus_ = exitStatus; @@ -2539,11 +2580,14 @@ class CDataStreamerBase : public CDeviceBase private: CDataStreamerBase* pDataStreamerBase_; bool isRunning_; + int exitStatus_; MMThreadLock isRunningLock_; + MMThreadLock exitStatusLock_; // Provide description here int svc(void) throw () { + this->SetExitStatus(DEVICE_DATASTREAMER_BUSY_ACQUIRING); int ret; AcquisitionThread* acqThr = pDataStreamerBase_->thdAcq_; AcquiredBlockCollection* acqCollection = pDataStreamerBase_->acqCollection_; @@ -2557,10 +2601,7 @@ class CDataStreamerBase : public CDeviceBase if (acqCollection->GetSize() != 0) { std::unique_ptr newBlock = acqCollection->Remove(); ret = pDataStreamerBase_->ProcessBuffer(std::move(newBlock->data), newBlock->actualSize); - if (ret != DEVICE_OK) { - pDataStreamerBase_->LogMessage("ProcessBuffer call returned an error.", true); - break; - } + if (ret != DEVICE_OK) break; } else { Sleep(pDataStreamerBase_->updatePeriodMs_); @@ -2570,13 +2611,19 @@ class CDataStreamerBase : public CDeviceBase catch (...) { pDataStreamerBase_->LogMessage("Unknown processing thread exception.", true); this->SetIsRunning(false); + this->SetExitStatus(DEVICE_ERR); return DEVICE_ERR; } - pDataStreamerBase_->LogMessage("Terminating processing thread.", true); + if (ret != DEVICE_OK) { + ss << "ProcessBuffer call returned code " << ret; + pDataStreamerBase_->LogMessage(ss.str(), true); + } + this->SetExitStatus(ret); + pDataStreamerBase_->LogMessage("Terminating processing thread.", true); this->SetIsRunning(false); - return DEVICE_OK; + return ret; } void SetIsRunning(bool isRunning) { @@ -2589,6 +2636,15 @@ class CDataStreamerBase : public CDeviceBase return isRunning_; } + void SetExitStatus(int exitStatus) { + MMThreadGuard g(this->exitStatusLock_); + exitStatus_ = exitStatus; + } + + int GetExitStatus() { + MMThreadGuard g(this->exitStatusLock_); + return exitStatus_; + } }; private: @@ -2597,6 +2653,7 @@ class CDataStreamerBase : public CDeviceBase int updatePeriodMs_; bool stopOnOverflow_; bool stopFlag_; + bool pauseAcquisitionBeforeOverflow_; AcquiredBlockCollection* acqCollection_; unsigned acqCollectionCapacity_; AcquisitionThread* thdAcq_; diff --git a/MMDevice/MMDevice.h b/MMDevice/MMDevice.h index 1ab82d396..c1862f634 100644 --- a/MMDevice/MMDevice.h +++ b/MMDevice/MMDevice.h @@ -1218,12 +1218,15 @@ namespace MM { // Calls that are implemented at the DeviceBase level and // remain the same for any DataStreamer device - virtual int SetStreamParameters(bool stopOnOverflow, int numberOfBuffers, int durationMs, int updatePeriodMs) = 0; - virtual int GetStreamParameters(bool& stopOnOverflow, int& numberOfBuffers, int& durationMs, int& updatePeriodMs) = 0; + virtual int SetStreamParameters(bool stopOnOverflow, bool pauseAcquisitionBeforeOverflow, int numberOfBuffers, int durationMs, int updatePeriodMs) = 0; + virtual int GetStreamParameters(bool& stopOnOverflow, bool& pauseAcquisitionBeforeOverflow, int& numberOfBuffers, int& durationMs, int& updatePeriodMs) = 0; + virtual int SetAcquisitionPause(bool pause) = 0; + virtual bool GetAcquisitionPause() = 0; virtual bool GetOverflowStatus() = 0; virtual int ResetOverflowStatus() = 0; virtual bool IsStreaming() = 0; - virtual int GetStreamExitStatus() = 0; + virtual int GetAcquisitionExitStatus() = 0; + virtual int GetProcessingExitStatus() = 0; virtual int SetCircularAcquisitionBufferCapacity(int capacity) = 0; virtual int GetCircularAcquisitionBufferCapacity() = 0; }; From 8a7057b4cbc467db5e0e5b67aff3f36587387e57 Mon Sep 17 00:00:00 2001 From: "melnykov.artem" Date: Tue, 10 Jan 2023 22:16:53 -0600 Subject: [PATCH 13/14] Replaced the simulated DataStreamer in DemoCamera with a better version --- DeviceAdapters/DemoCamera/DemoCamera.cpp | 232 +++++++++++++++++++++++ DeviceAdapters/DemoCamera/DemoCamera.h | 127 ++++--------- MMDevice/DeviceBase.h | 3 +- 3 files changed, 266 insertions(+), 96 deletions(-) diff --git a/DeviceAdapters/DemoCamera/DemoCamera.cpp b/DeviceAdapters/DemoCamera/DemoCamera.cpp index 140508d3e..3937da8c2 100644 --- a/DeviceAdapters/DemoCamera/DemoCamera.cpp +++ b/DeviceAdapters/DemoCamera/DemoCamera.cpp @@ -54,6 +54,7 @@ const char* g_DADeviceName = "D-DA"; const char* g_DA2DeviceName = "D-DA2"; const char* g_GalvoDeviceName = "DGalvo"; const char* g_MagnifierDeviceName = "DOptovar"; +const char* g_DataStreamerDeviceName = "DDataStreamer"; const char* g_HubDeviceName = "DHub"; // constants for naming pixel types (allowed values of the "PixelType" property) @@ -4675,6 +4676,237 @@ bool DemoGalvo::PointInTriangle(Point p, Point p0, Point p1, Point p2) return s > 0 && t > 0 && (s + t) < A; } +/////////////////////////////////////////////////////////// +// DemoDataStreamer +DemoDataStreamer::DemoDataStreamer() : + mockDataSize_(1024), + acqPeriod_(0), + procPeriod_(0), + errorGetBufferSizeAt_(65535), + errorGetBufferAt_(65535), + errorProcessBufferAt_(65535), + initialized_(false) +{ + // parent ID display + CreateHubIDProperty(); +} + +DemoDataStreamer::~DemoDataStreamer() +{ + Shutdown(); +} + +void DemoDataStreamer::GetName(char* pszName) const { + CDeviceUtils::CopyLimitedString(pszName, g_DataStreamerDeviceName); +} + +bool DemoDataStreamer::Busy() { + return false; +} + +int DemoDataStreamer::Initialize() +{ + + SetErrorText(errorCodeGetBufferSize, "GetBufferSize error message"); + SetErrorText(errorCodeGetBuffer, "GetBuffer error message"); + SetErrorText(errorCodeProcessBuffer, "ProcessBuffer error message"); + + int ret; + ret = CreateFloatProperty("Average data value", NAN, false); + assert(ret == DEVICE_OK); + + CPropertyAction* pAct = pAct = new CPropertyAction(this, &DemoDataStreamer::OnAcquisitionPeriod); + ret = CreateIntegerProperty("Acquisition period in ms", acqPeriod_, false, pAct); + assert(ret == DEVICE_OK); + SetPropertyLimits("Acquisition period in ms", 0, 10000); + + pAct = pAct = new CPropertyAction(this, &DemoDataStreamer::OnProcessingPeriod); + ret = CreateIntegerProperty("Processing period in ms", procPeriod_, false, pAct); + assert(ret == DEVICE_OK); + SetPropertyLimits("Processing period in ms", 0, 10000); + + pAct = pAct = new CPropertyAction(this, &DemoDataStreamer::OnGenerateGetBufferSizeErrorAt); + ret = CreateIntegerProperty("Generate GetBufferSize error at", errorGetBufferSizeAt_, false, pAct); + assert(ret == DEVICE_OK); + SetPropertyLimits("Generate GetBufferSize error at", 1, 65535); + + pAct = pAct = new CPropertyAction(this, &DemoDataStreamer::OnGenerateGetBufferErrorAt); + ret = CreateIntegerProperty("Generate GetBuffer error at", errorGetBufferAt_, false, pAct); + assert(ret == DEVICE_OK); + SetPropertyLimits("Generate GetBuffer error at", 1, 65535); + + pAct = pAct = new CPropertyAction(this, &DemoDataStreamer::OnGenerateProcessBufferErrorAt); + ret = CreateIntegerProperty("Generate ProcessBuffer error at", errorProcessBufferAt_, false, pAct); + assert(ret == DEVICE_OK); + SetPropertyLimits("Generate ProcessBuffer error at", 1, 65535); + + initialized_ = true; + return DEVICE_OK; +} + +int DemoDataStreamer::Shutdown() { + initialized_ = false; + return DEVICE_OK; +} + +int DemoDataStreamer::StartStream() { + counter_ = 1; + int ret; + ret = this->StartDataStreamerThreads(); + return ret; +} + +int DemoDataStreamer::StopStream() { + int ret; + ret = this->StopDataStreamerThreads(); + return ret; +} + +int DemoDataStreamer::GetBufferSize(unsigned& dataBufferSize) { + if (counter_ == errorGetBufferSizeAt_) return errorCodeGetBufferSize; + dataBufferSize = mockDataSize_; + return DEVICE_OK; +} + +std::unique_ptr DemoDataStreamer::GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize, int& exitStatus) { + + if (counter_ == errorGetBufferAt_) { + actualDataBufferSize = 0; + exitStatus = errorCodeGetBuffer; + return 0; + } + + if (expectedDataBufferSize <= mockDataSize_) { + actualDataBufferSize = expectedDataBufferSize; + } + else { + actualDataBufferSize = mockDataSize_; + } + + // allocate a new data array and put data in it + std::unique_ptr data(new char[actualDataBufferSize]); + int* ptr = (int*)data.get(); + for (size_t ii = 0; ii < actualDataBufferSize/4; ii++) { + *ptr = counter_; + ptr++; + } + counter_++; + exitStatus = DEVICE_OK; + Sleep(acqPeriod_); + + return data; +} + +int DemoDataStreamer::ProcessBuffer(std::unique_ptr& pDataBuffer, unsigned dataSize) { + if (counter_ == errorProcessBufferAt_) return errorCodeProcessBuffer; + double ave = 0; + int* ptr = (int*)pDataBuffer.get(); + for (size_t ii = 0; ii < dataSize/4; ii++) { + ave += *ptr; + ptr++; + } + ave = ave / (dataSize/4); + SetProperty("Average data value", to_string(ave).c_str()); + Sleep(procPeriod_); + return DEVICE_OK; +} + +/** +* Handles "Acquisition period in ms" property. +*/ +int DemoDataStreamer::OnAcquisitionPeriod(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + pProp->Set(acqPeriod_); + } + else if (eAct == MM::AfterSet) + { + if (this->IsStreaming()) return DEVICE_DATASTREAMER_BUSY_ACQUIRING; + long newPeriod; + pProp->Get(newPeriod); + if (newPeriod>pProp->GetUpperLimit() || newPeriodGetLowerLimit()) + { + pProp->Set(acqPeriod_); // revert + return DEVICE_INVALID_PROPERTY_VALUE; + } + acqPeriod_ = newPeriod; + } + return DEVICE_OK; +} + +/** +* Handles "Acquisition period in ms" property. +*/ +int DemoDataStreamer::OnProcessingPeriod(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + pProp->Set(procPeriod_); + } + else if (eAct == MM::AfterSet) + { + if (this->IsStreaming()) return DEVICE_DATASTREAMER_BUSY_ACQUIRING; + long newPeriod; + pProp->Get(newPeriod); + if (newPeriod > pProp->GetUpperLimit() || newPeriod < pProp->GetLowerLimit()) + { + pProp->Set(procPeriod_); // revert + return DEVICE_INVALID_PROPERTY_VALUE; + } + procPeriod_ = newPeriod; + } + return DEVICE_OK; +} + +int DemoDataStreamer::OnGenerateGetBufferSizeErrorAt(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + pProp->Set(errorGetBufferSizeAt_); + } + else if (eAct == MM::AfterSet) + { + if (this->IsStreaming()) return DEVICE_DATASTREAMER_BUSY_ACQUIRING; + long newval; + pProp->Get(newval); + errorGetBufferSizeAt_ = newval; + } + return DEVICE_OK; +} + +int DemoDataStreamer::OnGenerateGetBufferErrorAt(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + pProp->Set(errorGetBufferAt_); + } + else if (eAct == MM::AfterSet) + { + if (this->IsStreaming()) return DEVICE_DATASTREAMER_BUSY_ACQUIRING; + long newval; + pProp->Get(newval); + errorGetBufferAt_ = newval; + } + return DEVICE_OK; +} + +int DemoDataStreamer::OnGenerateProcessBufferErrorAt(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + if (eAct == MM::BeforeGet) + { + pProp->Set(errorProcessBufferAt_); + } + else if (eAct == MM::AfterSet) + { + if (this->IsStreaming()) return DEVICE_DATASTREAMER_BUSY_ACQUIRING; + long newval; + pProp->Get(newval); + errorProcessBufferAt_ = newval; + } + return DEVICE_OK; +} + ////////// BEGINNING OF POORLY ORGANIZED CODE ////////////// ////////// CLEANUP NEEDED //////////////////////////// diff --git a/DeviceAdapters/DemoCamera/DemoCamera.h b/DeviceAdapters/DemoCamera/DemoCamera.h index f2cbadd3e..bcbc026f4 100644 --- a/DeviceAdapters/DemoCamera/DemoCamera.h +++ b/DeviceAdapters/DemoCamera/DemoCamera.h @@ -52,8 +52,6 @@ const char* NoHubError = "Parent Hub not defined."; -const char* g_DataStreamerDeviceName = "DDataStreamer"; - // Defines which segments in a seven-segment display are lit up for each of // the numbers 0-9. Segments are: // @@ -1198,107 +1196,46 @@ class DemoGalvo : public CGalvoBase, ImgManipulator }; ////////////////////////////////////////////////////////////////////////////// -// DemoShutter class -// Simulation of shutter device +// DemoDataStreamer class +// Simulation of data streamer device ////////////////////////////////////////////////////////////////////////////// class DemoDataStreamer : public CDataStreamerBase { public: - DemoDataStreamer() : - mockDataSize_(1024*1024), - initialized_(false) - { - // parent ID display - CreateHubIDProperty(); - } - ~DemoDataStreamer() {} - - int Initialize() { - // initialize mock data - mockData_ = new char[mockDataSize_]; - char val = 0; - for (unsigned ii = 0; ii < mockDataSize_; ii++) { mockData_[ii] = val; val++; } - - SetErrorText(69, "My special error text."); - - writeFile_.open("C:\\temp\\mybinaryfile.txt", std::ios::out | std::ios::binary); - - initialized_ = true; - return DEVICE_OK; - } - int Shutdown() { - writeFile_.close(); - initialized_ = false; - return DEVICE_OK; - } - - void GetName(char* pszName) const { - CDeviceUtils::CopyLimitedString(pszName, g_DataStreamerDeviceName); - } - bool Busy() { - return false; - } - - int StartStream() { - int ret; - LogMessage("Pre-StartStream", true); - ret = this->StartDataStreamerThreads(); - return ret; - } - - int StopStream() { - int ret; - LogMessage("Pre-StoptStream", true); - ret = this->StopDataStreamerThreads(); - return ret; - } - - int GetBufferSize(unsigned& dataBufferSize) { - LogMessage("Demo DataStreamer: calling GetBufferSize", true); - dataBufferSize = mockDataSize_; - return DEVICE_OK; - } - - std::unique_ptr GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize, int& exitStatus) { - - LogMessage("Demo DataStreamer: calling GetBuffer", true); - - if (expectedDataBufferSize <= mockDataSize_) { - actualDataBufferSize = expectedDataBufferSize; - } - else { - actualDataBufferSize = mockDataSize_; - } - // allocate a new data array and put data in it - std::unique_ptr data(new char[actualDataBufferSize]); - memcpy(data.get(), mockData_, actualDataBufferSize); - exitStatus = DEVICE_OK; - LogMessage("Demo DataStreamer: finished GetBuffer", true); - - return data; - } - - int ProcessBuffer(std::unique_ptr& pDataBuffer, unsigned dataSize) { - - LogMessage("Demo DataStreamer: calling ProcessBuffer", true); - - if (!writeFile_) { - LogMessage("Demo DataStreamer: unable to wite into a file during ProcessBuffer call", false); - return 0; - } - writeFile_.write(pDataBuffer.get(), dataSize); - Sleep(2000); - LogMessage("Demo DataStreamer: finished ProcessBuffer", true); - - return DEVICE_OK; - } + DemoDataStreamer(); + ~DemoDataStreamer(); + + int Initialize(); + int Shutdown(); + void GetName(char* pszName) const; + bool Busy(); + + int StartStream(); + int StopStream(); + int GetBufferSize(unsigned& dataBufferSize); + std::unique_ptr GetBuffer(unsigned expectedDataBufferSize, unsigned& actualDataBufferSize, int& exitStatus); + int ProcessBuffer(std::unique_ptr& pDataBuffer, unsigned dataSize); + + // action interface + // ---------------- + int OnAcquisitionPeriod(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnProcessingPeriod(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnGenerateGetBufferSizeErrorAt(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnGenerateGetBufferErrorAt(MM::PropertyBase* pProp, MM::ActionType eAct); + int OnGenerateProcessBufferErrorAt(MM::PropertyBase* pProp, MM::ActionType eAct); private: bool initialized_; unsigned mockDataSize_; - char* mockData_; - std::ofstream writeFile_; - MM::MMTime changedTime_; + unsigned counter_; + long acqPeriod_; + long procPeriod_; + long errorGetBufferSizeAt_; + long errorGetBufferAt_; + long errorProcessBufferAt_; + const int errorCodeGetBufferSize = 901; + const int errorCodeGetBuffer = 902; + const int errorCodeProcessBuffer = 903; }; diff --git a/MMDevice/DeviceBase.h b/MMDevice/DeviceBase.h index 03fe33ede..7c266fda5 100644 --- a/MMDevice/DeviceBase.h +++ b/MMDevice/DeviceBase.h @@ -2332,6 +2332,7 @@ class CDataStreamerBase : public CDeviceBase virtual int SetAcquisitionPause(bool pause) { if (!thdAcq_->IsRunning()) return DEVICE_OK; thdAcq_->SetPause(pause); + return DEVICE_OK; } virtual bool GetAcquisitionPause() { @@ -2588,7 +2589,7 @@ class CDataStreamerBase : public CDeviceBase int svc(void) throw () { this->SetExitStatus(DEVICE_DATASTREAMER_BUSY_ACQUIRING); - int ret; + int ret = DEVICE_OK; AcquisitionThread* acqThr = pDataStreamerBase_->thdAcq_; AcquiredBlockCollection* acqCollection = pDataStreamerBase_->acqCollection_; std::stringstream ss; From 2b3c3880ee851f2768e90ae4c481dae10d48e15e Mon Sep 17 00:00:00 2001 From: "melnykov.artem" Date: Thu, 12 Jan 2023 20:38:23 -0600 Subject: [PATCH 14/14] Small changes to the demo DataStreamer --- DeviceAdapters/DemoCamera/DemoCamera.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/DeviceAdapters/DemoCamera/DemoCamera.cpp b/DeviceAdapters/DemoCamera/DemoCamera.cpp index 3937da8c2..20e65a82b 100644 --- a/DeviceAdapters/DemoCamera/DemoCamera.cpp +++ b/DeviceAdapters/DemoCamera/DemoCamera.cpp @@ -4680,8 +4680,8 @@ bool DemoGalvo::PointInTriangle(Point p, Point p0, Point p1, Point p2) // DemoDataStreamer DemoDataStreamer::DemoDataStreamer() : mockDataSize_(1024), - acqPeriod_(0), - procPeriod_(0), + acqPeriod_(1000), + procPeriod_(1000), errorGetBufferSizeAt_(65535), errorGetBufferAt_(65535), errorProcessBufferAt_(65535), @@ -4750,15 +4750,17 @@ int DemoDataStreamer::Shutdown() { } int DemoDataStreamer::StartStream() { + // calls to hardware should be implemented here counter_ = 1; int ret; - ret = this->StartDataStreamerThreads(); + ret = this->StartDataStreamerThreads(); // this line must be present in every StartStream implementation return ret; } int DemoDataStreamer::StopStream() { + // calls to hardware should be implemented here int ret; - ret = this->StopDataStreamerThreads(); + ret = this->StopDataStreamerThreads(); // this line must be present in every StopStream implementation return ret; }