Skip to content

Commit

Permalink
TeensyPulseGenerator: made CameraPulse functional.
Browse files Browse the repository at this point in the history
  • Loading branch information
nicost committed Dec 23, 2024
1 parent a027b24 commit 68ff458
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 6 deletions.
111 changes: 107 additions & 4 deletions DeviceAdapters/TeensyPulseGenerator/CameraPulser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,11 @@ const char* g_Invert = "Invert";
const char* g_DeviceNameCameraPulser = "TeensySendsPulsesToCamera";

CameraPulser::CameraPulser() :
pulseDuration_(1.0),
initialized_(false),
version_(0)
version_(0),
nrCamerasInUse_(0),
teensyCom_(0)
{
InitializeDefaultErrorMessages();

Expand All @@ -38,6 +41,9 @@ CameraPulser::CameraPulser() :
// Description
CreateProperty(MM::g_Keyword_Description, "Use Camera in external trigger mode and provide triggers with Teensy", MM::String, true);

for (int i = 0; i < MAX_NUMBER_PHYSICAL_CAMERAS; i++) {
usedCameras_.push_back(g_Undefined);
}

CPropertyAction* pAct = new CPropertyAction(this, &CameraPulser::OnPort);
CreateProperty(MM::g_Keyword_Port, "Undefined", MM::String, false, pAct, true);
Expand All @@ -51,7 +57,6 @@ CameraPulser::~CameraPulser()

int CameraPulser::Shutdown()
{
delete imageBuffer_;
// Rely on the cameras to shut themselves down
return DEVICE_OK;
}
Expand Down Expand Up @@ -114,6 +119,23 @@ int CameraPulser::Initialize()
pAct = new CPropertyAction(this, &CameraPulser::OnVersion);
CreateIntegerProperty(g_versionProp, version_, true, pAct);

// Pulse Duration property
uint32_t pulseDuration;
ret = teensyCom_->GetPulseDuration(pulseDuration);
if (ret != DEVICE_OK)
return ret;
pulseDuration_ = pulseDuration / 1000.0;
pAct = new CPropertyAction(this, &CameraPulser::OnPulseDuration);
CreateFloatProperty("PulseDuration-ms", pulseDuration_, false, pAct);

// Interval property
uint32_t interval;
ret = teensyCom_->GetInterval(interval);
if (ret != DEVICE_OK)
return ret;
interval_ = interval / 1000.0;
pAct = new CPropertyAction(this, &CameraPulser::OnInterval);
CreateFloatProperty("Interval-ms", interval_, false, pAct);

initialized_ = true;

Expand Down Expand Up @@ -143,6 +165,17 @@ int CameraPulser::SnapImage()
t[i].Start();
}
}
// send one pulse, even when the cameras are not in external trigger mode, this should not hurt
uint32_t response;
int ret = teensyCom_->SetNumberOfPulses(1, response);
if (ret != DEVICE_OK)
return ret;
if (response != 1)
return ERR_COMMUNICATION;
ret = teensyCom_->SetStart(response);
if (ret != DEVICE_OK)
return ret;

// I think that the CameraSnapThread destructor waits until the SnapImage function is done
// So, we are likely to be waiting here until all cameras are done snapping

Expand Down Expand Up @@ -457,6 +490,11 @@ int CameraPulser::StartSequenceAcquisition(double interval)
if (!ImageSizesAreEqual())
return ERR_NO_EQUAL_SIZE;

uint32_t response;
int ret = teensyCom_->SetNumberOfPulses(0, response);
if (ret != DEVICE_OK)
return ret;

for (unsigned int i = 0; i < usedCameras_.size(); i++)
{
MM::Camera* camera = (MM::Camera*)GetDevice(usedCameras_[i].c_str());
Expand All @@ -469,11 +507,16 @@ int CameraPulser::StartSequenceAcquisition(double interval)
camera->AddTag(MM::g_Keyword_CameraChannelIndex, usedCameras_[i].c_str(),
os.str().c_str());

int ret = camera->StartSequenceAcquisition(interval);
ret = camera->StartSequenceAcquisition(interval);
if (ret != DEVICE_OK)
return ret;
}
}
// start pulses, should even when cameras are not in external trigger mode
ret = teensyCom_->SetStart(response);
if (ret != DEVICE_OK)
return ret;

return DEVICE_OK;
}

Expand Down Expand Up @@ -531,14 +574,18 @@ int CameraPulser::StopSequenceAcquisition()
}
}
std::ostringstream os;
os << "Stopp Sequence after sending " << response << " pulses.";
os << "Stopped Sequence after sending " << response << " pulses.";
GetCoreCallback()->LogMessage(this, os.str().c_str(), false);

return DEVICE_OK;
}

int CameraPulser::GetBinning() const
{
if (usedCameras_.empty())
{
return 1;
}
MM::Camera* camera0 = (MM::Camera*)GetDevice(usedCameras_[0].c_str());
int binning = 0;
if (camera0 != 0)
Expand Down Expand Up @@ -614,6 +661,7 @@ int CameraPulser::Logical2Physical(int logical)

int CameraPulser::OnPhysicalCamera(MM::PropertyBase* pProp, MM::ActionType eAct, long i)
{

if (eAct == MM::BeforeGet)
{
pProp->Set(usedCameras_[i].c_str());
Expand Down Expand Up @@ -713,4 +761,59 @@ int CameraPulser::OnVersion(MM::PropertyBase* pProp, MM::ActionType pAct)
return DEVICE_OK;
}

int CameraPulser::OnPulseDuration(MM::PropertyBase* pProp, MM::ActionType eAct)
{
if (eAct == MM::BeforeGet)
{
pProp->Set(pulseDuration_);
}
else if (eAct == MM::AfterSet)
{
pProp->Get(pulseDuration_);

// Send pulse duration command if initialized
if (initialized_)
{
uint32_t pulseDurationUs = static_cast<uint32_t>(pulseDuration_ * 1000.0);
uint32_t param;
int ret = teensyCom_->SetPulseDuration(pulseDurationUs, param);
if (ret != DEVICE_OK)
return ret;
if (param != pulseDurationUs)
{
GetCoreCallback()->LogMessage(this, "PulseDuration sent not the same as pulseDuration echoed back", false);
return ERR_COMMUNICATION;

}
}
}
return DEVICE_OK;
}

int CameraPulser::OnInterval(MM::PropertyBase* pProp, MM::ActionType eAct)
{
if (eAct == MM::BeforeGet)
{
pProp->Set(interval_);
}
else if (eAct == MM::AfterSet)
{
pProp->Get(interval_);

// Send interval command if initialized
if (initialized_)
{
uint32_t interval = static_cast<uint32_t> (interval_ * 1000.0);
uint32_t parm;
int ret = teensyCom_->SetInterval(interval, parm);
if (ret != DEVICE_OK)
return ret;
if (parm != interval)
{
GetCoreCallback()->LogMessage(this, "Interval sent not the same as interval echoed back", false);
return ERR_COMMUNICATION;
}
}
}
return DEVICE_OK;
}
8 changes: 6 additions & 2 deletions DeviceAdapters/TeensyPulseGenerator/CameraPulser.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,18 @@ class CameraPulser : public CCameraBase<CameraPulser>
int OnPhysicalCamera(MM::PropertyBase* pProp, MM::ActionType eAct, long i);
int OnBinning(MM::PropertyBase* pProp, MM::ActionType eAct);
int OnVersion(MM::PropertyBase* pProp, MM::ActionType pAct);
int OnPulseDuration(MM::PropertyBase* pProp, MM::ActionType eAct);
int OnInterval(MM::PropertyBase* pProp, MM::ActionType eAct);

private:
bool ImageSizesAreEqual();
int Logical2Physical(int logical);

unsigned char* imageBuffer_;

std::vector<std::string> availableCameras_;
std::vector<std::string> usedCameras_;
std::string usedCamera_;
double interval_; // Interval in ms
double pulseDuration_; // Pulse duration in milli-seconds
bool initialized_;
unsigned int nrCamerasInUse_;
ImgBuffer img_;
Expand All @@ -81,4 +83,6 @@ class CameraPulser : public CCameraBase<CameraPulser>
TeensyCom* teensyCom_;

uint32_t version_;
uint32_t nrPulses_; // nr Pulses we request
uint32_t nrPulsesCounted_; // as returned by the Teensy
};

0 comments on commit 68ff458

Please sign in to comment.