Skip to content

Commit

Permalink
MMCore: Enforce pre/post initialization rules
Browse files Browse the repository at this point in the history
- Most non-property operations require an initialized device
- Pre-init properties must not be set after initialization
- Device initialiation may only be attempted once per device instance

These rules have been unstated previously, but had to be observed. Now
make it an error (throw an exception).
  • Loading branch information
marktsuchida committed Sep 8, 2023
1 parent 748b59d commit be5f4c1
Show file tree
Hide file tree
Showing 16 changed files with 331 additions and 225 deletions.
20 changes: 10 additions & 10 deletions MMCore/Devices/AutoFocusInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@
#include "AutoFocusInstance.h"


int AutoFocusInstance::SetContinuousFocusing(bool state) { return GetImpl()->SetContinuousFocusing(state); }
int AutoFocusInstance::GetContinuousFocusing(bool& state) { return GetImpl()->GetContinuousFocusing(state); }
bool AutoFocusInstance::IsContinuousFocusLocked() { return GetImpl()->IsContinuousFocusLocked(); }
int AutoFocusInstance::FullFocus() { return GetImpl()->FullFocus(); }
int AutoFocusInstance::IncrementalFocus() { return GetImpl()->IncrementalFocus(); }
int AutoFocusInstance::GetLastFocusScore(double& score) { return GetImpl()->GetLastFocusScore(score); }
int AutoFocusInstance::GetCurrentFocusScore(double& score) { return GetImpl()->GetCurrentFocusScore(score); }
int AutoFocusInstance::AutoSetParameters() { return GetImpl()->AutoSetParameters(); }
int AutoFocusInstance::GetOffset(double &offset) { return GetImpl()->GetOffset(offset); }
int AutoFocusInstance::SetOffset(double offset) { return GetImpl()->SetOffset(offset); }
int AutoFocusInstance::SetContinuousFocusing(bool state) { RequireInitialized(); return GetImpl()->SetContinuousFocusing(state); }
int AutoFocusInstance::GetContinuousFocusing(bool& state) { RequireInitialized(); return GetImpl()->GetContinuousFocusing(state); }
bool AutoFocusInstance::IsContinuousFocusLocked() { RequireInitialized(); return GetImpl()->IsContinuousFocusLocked(); }
int AutoFocusInstance::FullFocus() { RequireInitialized(); return GetImpl()->FullFocus(); }
int AutoFocusInstance::IncrementalFocus() { RequireInitialized(); return GetImpl()->IncrementalFocus(); }
int AutoFocusInstance::GetLastFocusScore(double& score) { RequireInitialized(); return GetImpl()->GetLastFocusScore(score); }
int AutoFocusInstance::GetCurrentFocusScore(double& score) { RequireInitialized(); return GetImpl()->GetCurrentFocusScore(score); }
int AutoFocusInstance::AutoSetParameters() { RequireInitialized(); return GetImpl()->AutoSetParameters(); }
int AutoFocusInstance::GetOffset(double &offset) { RequireInitialized(); return GetImpl()->GetOffset(offset); }
int AutoFocusInstance::SetOffset(double offset) { RequireInitialized(); return GetImpl()->SetOffset(offset); }
74 changes: 41 additions & 33 deletions MMCore/Devices/CameraInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,50 +22,53 @@
#include "CameraInstance.h"


int CameraInstance::SnapImage() { return GetImpl()->SnapImage(); }
const unsigned char* CameraInstance::GetImageBuffer() { return GetImpl()->GetImageBuffer(); }
const unsigned char* CameraInstance::GetImageBuffer(unsigned channelNr) { return GetImpl()->GetImageBuffer(channelNr); }
const unsigned int* CameraInstance::GetImageBufferAsRGB32() { return GetImpl()->GetImageBufferAsRGB32(); }
unsigned CameraInstance::GetNumberOfComponents() const { return GetImpl()->GetNumberOfComponents(); }
int CameraInstance::SnapImage() { RequireInitialized(); return GetImpl()->SnapImage(); }
const unsigned char* CameraInstance::GetImageBuffer() { RequireInitialized(); return GetImpl()->GetImageBuffer(); }
const unsigned char* CameraInstance::GetImageBuffer(unsigned channelNr) { RequireInitialized(); return GetImpl()->GetImageBuffer(channelNr); }
const unsigned int* CameraInstance::GetImageBufferAsRGB32() { RequireInitialized(); return GetImpl()->GetImageBufferAsRGB32(); }
unsigned CameraInstance::GetNumberOfComponents() const { RequireInitialized(); return GetImpl()->GetNumberOfComponents(); }

std::string CameraInstance::GetComponentName(unsigned component)
{
RequireInitialized();
DeviceStringBuffer nameBuf(this, "GetComponentName");
int err = GetImpl()->GetComponentName(component, nameBuf.GetBuffer());
ThrowIfError(err, "Cannot get component name at index " +
ToString(component));
return nameBuf.Get();
}

int unsigned CameraInstance::GetNumberOfChannels() const { return GetImpl()->GetNumberOfChannels(); }
int unsigned CameraInstance::GetNumberOfChannels() const { RequireInitialized(); return GetImpl()->GetNumberOfChannels(); }

std::string CameraInstance::GetChannelName(unsigned channel)
{
RequireInitialized();
DeviceStringBuffer nameBuf(this, "GetChannelName");
int err = GetImpl()->GetChannelName(channel, nameBuf.GetBuffer());
ThrowIfError(err, "Cannot get channel name at index " + ToString(channel));
return nameBuf.Get();
}

long CameraInstance::GetImageBufferSize()const { return GetImpl()->GetImageBufferSize(); }
unsigned CameraInstance::GetImageWidth() const { return GetImpl()->GetImageWidth(); }
unsigned CameraInstance::GetImageHeight() const { return GetImpl()->GetImageHeight(); }
unsigned CameraInstance::GetImageBytesPerPixel() const { return GetImpl()->GetImageBytesPerPixel(); }
unsigned CameraInstance::GetBitDepth() const { return GetImpl()->GetBitDepth(); }
double CameraInstance::GetPixelSizeUm() const { return GetImpl()->GetPixelSizeUm(); }
int CameraInstance::GetBinning() const { return GetImpl()->GetBinning(); }
int CameraInstance::SetBinning(int binSize) { return GetImpl()->SetBinning(binSize); }
void CameraInstance::SetExposure(double exp_ms) { return GetImpl()->SetExposure(exp_ms); }
double CameraInstance::GetExposure() const { return GetImpl()->GetExposure(); }
int CameraInstance::SetROI(unsigned x, unsigned y, unsigned xSize, unsigned ySize) { return GetImpl()->SetROI(x, y, xSize, ySize); }
int CameraInstance::GetROI(unsigned& x, unsigned& y, unsigned& xSize, unsigned& ySize) { return GetImpl()->GetROI(x, y, xSize, ySize); }
int CameraInstance::ClearROI() { return GetImpl()->ClearROI(); }
long CameraInstance::GetImageBufferSize() const { RequireInitialized(); return GetImpl()->GetImageBufferSize(); }
unsigned CameraInstance::GetImageWidth() const { RequireInitialized(); return GetImpl()->GetImageWidth(); }
unsigned CameraInstance::GetImageHeight() const { RequireInitialized(); return GetImpl()->GetImageHeight(); }
unsigned CameraInstance::GetImageBytesPerPixel() const { RequireInitialized(); return GetImpl()->GetImageBytesPerPixel(); }
unsigned CameraInstance::GetBitDepth() const { RequireInitialized(); return GetImpl()->GetBitDepth(); }
double CameraInstance::GetPixelSizeUm() const { RequireInitialized(); return GetImpl()->GetPixelSizeUm(); }
int CameraInstance::GetBinning() const { RequireInitialized(); return GetImpl()->GetBinning(); }
int CameraInstance::SetBinning(int binSize) { RequireInitialized(); return GetImpl()->SetBinning(binSize); }
void CameraInstance::SetExposure(double exp_ms) { RequireInitialized(); return GetImpl()->SetExposure(exp_ms); }
double CameraInstance::GetExposure() const { RequireInitialized(); return GetImpl()->GetExposure(); }
int CameraInstance::SetROI(unsigned x, unsigned y, unsigned xSize, unsigned ySize) { RequireInitialized(); return GetImpl()->SetROI(x, y, xSize, ySize); }
int CameraInstance::GetROI(unsigned& x, unsigned& y, unsigned& xSize, unsigned& ySize) { RequireInitialized(); return GetImpl()->GetROI(x, y, xSize, ySize); }
int CameraInstance::ClearROI() { RequireInitialized(); return GetImpl()->ClearROI(); }

/**
* Queries if the camera supports multiple simultaneous ROIs.
*/
bool CameraInstance::SupportsMultiROI()
{
RequireInitialized();
return GetImpl()->SupportsMultiROI();
}

Expand All @@ -76,6 +79,7 @@ bool CameraInstance::SupportsMultiROI()
*/
bool CameraInstance::IsMultiROISet()
{
RequireInitialized();
return GetImpl()->IsMultiROISet();
}

Expand All @@ -85,6 +89,7 @@ bool CameraInstance::IsMultiROISet()
*/
int CameraInstance::GetMultiROICount(unsigned int& count)
{
RequireInitialized();
return GetImpl()->GetMultiROICount(count);
}

Expand All @@ -101,6 +106,7 @@ int CameraInstance::SetMultiROI(const unsigned int* xs, const unsigned int* ys,
const unsigned* widths, const unsigned int* heights,
unsigned numROIs)
{
RequireInitialized();
return GetImpl()->SetMultiROI(xs, ys, widths, heights, numROIs);
}

Expand All @@ -117,17 +123,19 @@ int CameraInstance::SetMultiROI(const unsigned int* xs, const unsigned int* ys,
int CameraInstance::GetMultiROI(unsigned* xs, unsigned* ys, unsigned* widths,
unsigned* heights, unsigned* length)
{
RequireInitialized();
return GetImpl()->GetMultiROI(xs, ys, widths, heights, length);
}

int CameraInstance::StartSequenceAcquisition(long numImages, double interval_ms, bool stopOnOverflow) { return GetImpl()->StartSequenceAcquisition(numImages, interval_ms, stopOnOverflow); }
int CameraInstance::StartSequenceAcquisition(double interval_ms) { return GetImpl()->StartSequenceAcquisition(interval_ms); }
int CameraInstance::StopSequenceAcquisition() { return GetImpl()->StopSequenceAcquisition(); }
int CameraInstance::PrepareSequenceAcqusition() { return GetImpl()->PrepareSequenceAcqusition(); }
bool CameraInstance::IsCapturing() { return GetImpl()->IsCapturing(); }
int CameraInstance::StartSequenceAcquisition(long numImages, double interval_ms, bool stopOnOverflow) { RequireInitialized(); return GetImpl()->StartSequenceAcquisition(numImages, interval_ms, stopOnOverflow); }
int CameraInstance::StartSequenceAcquisition(double interval_ms) { RequireInitialized(); return GetImpl()->StartSequenceAcquisition(interval_ms); }
int CameraInstance::StopSequenceAcquisition() { RequireInitialized(); return GetImpl()->StopSequenceAcquisition(); }
int CameraInstance::PrepareSequenceAcqusition() { RequireInitialized(); return GetImpl()->PrepareSequenceAcqusition(); }
bool CameraInstance::IsCapturing() { RequireInitialized(); return GetImpl()->IsCapturing(); }

std::string CameraInstance::GetTags()
{
RequireInitialized();
// TODO Probably makes sense to deserialize here.
// Also note the danger of limiting serialized metadata to MM::MaxStrLength
// (CCameraBase takes no precaution to limit string length; it is an
Expand All @@ -137,12 +145,12 @@ std::string CameraInstance::GetTags()
return serializedMetadataBuf.Get();
}

void CameraInstance::AddTag(const char* key, const char* deviceLabel, const char* value) { return GetImpl()->AddTag(key, deviceLabel, value); }
void CameraInstance::RemoveTag(const char* key) { return GetImpl()->RemoveTag(key); }
int CameraInstance::IsExposureSequenceable(bool& isSequenceable) const { return GetImpl()->IsExposureSequenceable(isSequenceable); }
int CameraInstance::GetExposureSequenceMaxLength(long& nrEvents) const { return GetImpl()->GetExposureSequenceMaxLength(nrEvents); }
int CameraInstance::StartExposureSequence() { return GetImpl()->StartExposureSequence(); }
int CameraInstance::StopExposureSequence() { return GetImpl()->StopExposureSequence(); }
int CameraInstance::ClearExposureSequence() { return GetImpl()->ClearExposureSequence(); }
int CameraInstance::AddToExposureSequence(double exposureTime_ms) { return GetImpl()->AddToExposureSequence(exposureTime_ms); }
int CameraInstance::SendExposureSequence() const { return GetImpl()->SendExposureSequence(); }
void CameraInstance::AddTag(const char* key, const char* deviceLabel, const char* value) { RequireInitialized(); return GetImpl()->AddTag(key, deviceLabel, value); }
void CameraInstance::RemoveTag(const char* key) { RequireInitialized(); return GetImpl()->RemoveTag(key); }
int CameraInstance::IsExposureSequenceable(bool& isSequenceable) const { RequireInitialized(); return GetImpl()->IsExposureSequenceable(isSequenceable); }
int CameraInstance::GetExposureSequenceMaxLength(long& nrEvents) const { RequireInitialized(); return GetImpl()->GetExposureSequenceMaxLength(nrEvents); }
int CameraInstance::StartExposureSequence() { RequireInitialized(); return GetImpl()->StartExposureSequence(); }
int CameraInstance::StopExposureSequence() { RequireInitialized(); return GetImpl()->StopExposureSequence(); }
int CameraInstance::ClearExposureSequence() { RequireInitialized(); return GetImpl()->ClearExposureSequence(); }
int CameraInstance::AddToExposureSequence(double exposureTime_ms) { RequireInitialized(); return GetImpl()->AddToExposureSequence(exposureTime_ms); }
int CameraInstance::SendExposureSequence() const { RequireInitialized(); return GetImpl()->SendExposureSequence(); }
23 changes: 21 additions & 2 deletions MMCore/Devices/DeviceInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,13 @@ DeviceInstance::ThrowIfError(int code, const std::string& message) const
throw e;
}

void
DeviceInstance::RequireInitialized() const
{
if (!initialized_)
ThrowError("Operation not permitted on uninitialized device");
}

void
DeviceInstance::DeviceStringBuffer::ThrowBufferOverflowError() const
{
Expand Down Expand Up @@ -159,6 +166,9 @@ void
DeviceInstance::SetProperty(const std::string& name,
const std::string& value) const
{
if (initialized_ && GetPropertyInitStatus(name.c_str()))
ThrowError("Cannot set pre-init property after initialization");

LOG_DEBUG(Logger()) << "Will set property \"" << name << "\" to \"" <<
value << "\"";

Expand Down Expand Up @@ -315,7 +325,10 @@ DeviceInstance::GetErrorText(int code) const

bool
DeviceInstance::Busy()
{ return pImpl_->Busy(); }
{
RequireInitialized();
return pImpl_->Busy();
}

double
DeviceInstance::GetDelayMs() const
Expand All @@ -332,12 +345,19 @@ DeviceInstance::UsesDelay()
void
DeviceInstance::Initialize()
{
// Device initialization can only be attempted once per instance lifetime.
if (initializeCalled_)
ThrowError("Device already initialized (or initialization already attempted)");
initializeCalled_ = true;
ThrowIfError(pImpl_->Initialize());
initialized_ = true;
}

void
DeviceInstance::Shutdown()
{
// Note we do not require device to be initialized before calling Shutdown().
initialized_ = false;
ThrowIfError(pImpl_->Shutdown());
}

Expand All @@ -358,7 +378,6 @@ DeviceInstance::SetCallback(MM::Core* callback) {
pImpl_->SetCallback(callback);
}


bool
DeviceInstance::SupportsDeviceDetection()
{
Expand Down
3 changes: 3 additions & 0 deletions MMCore/Devices/DeviceInstance.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ class DeviceInstance
DeleteDeviceFunction deleteFunction_;
mm::logging::Logger deviceLogger_;
mm::logging::Logger coreLogger_;
bool initializeCalled_ = false;
bool initialized_ = false;

public:
DeviceInstance(const DeviceInstance&) = delete;
Expand Down Expand Up @@ -112,6 +114,7 @@ class DeviceInstance
void ThrowError(const std::string& message) const;
void ThrowIfError(int code) const;
void ThrowIfError(int code, const std::string& message) const;
void RequireInitialized() const;

/// Utility class for getting fixed-length strings from the device interface.
/**
Expand Down
33 changes: 17 additions & 16 deletions MMCore/Devices/GalvoInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,26 @@
#include "GalvoInstance.h"


int GalvoInstance::PointAndFire(double x, double y, double time_us) { return GetImpl()->PointAndFire(x, y, time_us); }
int GalvoInstance::SetSpotInterval(double pulseInterval_us) { return GetImpl()->SetSpotInterval(pulseInterval_us); }
int GalvoInstance::SetPosition(double x, double y) { return GetImpl()->SetPosition(x, y); }
int GalvoInstance::GetPosition(double& x, double& y) { return GetImpl()->GetPosition(x, y); }
int GalvoInstance::SetIlluminationState(bool on) { return GetImpl()->SetIlluminationState(on); }
double GalvoInstance::GetXRange() { return GetImpl()->GetXRange(); }
double GalvoInstance::GetXMinimum() { return GetImpl()->GetXMinimum(); }
double GalvoInstance::GetYRange() { return GetImpl()->GetYRange(); }
double GalvoInstance::GetYMinimum() { return GetImpl()->GetYMinimum(); }
int GalvoInstance::AddPolygonVertex(int polygonIndex, double x, double y) { return GetImpl()->AddPolygonVertex(polygonIndex, x, y); }
int GalvoInstance::DeletePolygons() { return GetImpl()->DeletePolygons(); }
int GalvoInstance::RunSequence() { return GetImpl()->RunSequence(); }
int GalvoInstance::LoadPolygons() { return GetImpl()->LoadPolygons(); }
int GalvoInstance::SetPolygonRepetitions(int repetitions) { return GetImpl()->SetPolygonRepetitions(repetitions); }
int GalvoInstance::RunPolygons() { return GetImpl()->RunPolygons(); }
int GalvoInstance::StopSequence() { return GetImpl()->StopSequence(); }
int GalvoInstance::PointAndFire(double x, double y, double time_us) { RequireInitialized(); return GetImpl()->PointAndFire(x, y, time_us); }
int GalvoInstance::SetSpotInterval(double pulseInterval_us) { RequireInitialized(); return GetImpl()->SetSpotInterval(pulseInterval_us); }
int GalvoInstance::SetPosition(double x, double y) { RequireInitialized(); return GetImpl()->SetPosition(x, y); }
int GalvoInstance::GetPosition(double& x, double& y) { RequireInitialized(); return GetImpl()->GetPosition(x, y); }
int GalvoInstance::SetIlluminationState(bool on) { RequireInitialized(); return GetImpl()->SetIlluminationState(on); }
double GalvoInstance::GetXRange() { RequireInitialized(); return GetImpl()->GetXRange(); }
double GalvoInstance::GetXMinimum() { RequireInitialized(); return GetImpl()->GetXMinimum(); }
double GalvoInstance::GetYRange() { RequireInitialized(); return GetImpl()->GetYRange(); }
double GalvoInstance::GetYMinimum() { RequireInitialized(); return GetImpl()->GetYMinimum(); }
int GalvoInstance::AddPolygonVertex(int polygonIndex, double x, double y) { RequireInitialized(); return GetImpl()->AddPolygonVertex(polygonIndex, x, y); }
int GalvoInstance::DeletePolygons() { RequireInitialized(); return GetImpl()->DeletePolygons(); }
int GalvoInstance::RunSequence() { RequireInitialized(); return GetImpl()->RunSequence(); }
int GalvoInstance::LoadPolygons() { RequireInitialized(); return GetImpl()->LoadPolygons(); }
int GalvoInstance::SetPolygonRepetitions(int repetitions) { RequireInitialized(); return GetImpl()->SetPolygonRepetitions(repetitions); }
int GalvoInstance::RunPolygons() { RequireInitialized(); return GetImpl()->RunPolygons(); }
int GalvoInstance::StopSequence() { RequireInitialized(); return GetImpl()->StopSequence(); }

std::string GalvoInstance::GetChannel()
{
RequireInitialized();
DeviceStringBuffer nameBuf(this, "GetChannel");
int err = GetImpl()->GetChannel(nameBuf.GetBuffer());
ThrowIfError(err, "Cannot get current channel name");
Expand Down
4 changes: 4 additions & 0 deletions MMCore/Devices/HubInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
std::vector<std::string>
HubInstance::GetInstalledPeripheralNames()
{
RequireInitialized();

std::vector<MM::Device*> peripherals = GetInstalledPeripherals();

std::vector<std::string> names;
Expand All @@ -59,6 +61,8 @@ HubInstance::GetInstalledPeripheralNames()
std::string
HubInstance::GetInstalledPeripheralDescription(const std::string& peripheralName)
{
RequireInitialized();

std::vector<MM::Device*> peripherals = GetInstalledPeripherals();
for (std::vector<MM::Device*>::iterator it = peripherals.begin(), end = peripherals.end();
it != end; ++it)
Expand Down
2 changes: 1 addition & 1 deletion MMCore/Devices/ImageProcessorInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@
#include "ImageProcessorInstance.h"


int ImageProcessorInstance::Process(unsigned char* buffer, unsigned width, unsigned height, unsigned byteDepth) { return GetImpl()->Process(buffer, width, height, byteDepth); }
int ImageProcessorInstance::Process(unsigned char* buffer, unsigned width, unsigned height, unsigned byteDepth) { RequireInitialized(); return GetImpl()->Process(buffer, width, height, byteDepth); }
2 changes: 1 addition & 1 deletion MMCore/Devices/MagnifierInstance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@
#include "MagnifierInstance.h"


double MagnifierInstance::GetMagnification() { return GetImpl()->GetMagnification(); }
double MagnifierInstance::GetMagnification() { RequireInitialized(); return GetImpl()->GetMagnification(); }
Loading

0 comments on commit be5f4c1

Please sign in to comment.