Skip to content

Commit

Permalink
Merge pull request #548 from nicost/Octopi
Browse files Browse the repository at this point in the history
Cephla controller: Adds DA and Laser control
  • Loading branch information
nicost authored Jan 14, 2025
2 parents e62a712 + 080e01f commit 9baa6be
Show file tree
Hide file tree
Showing 13 changed files with 559 additions and 66 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<RootNamespace>Octopi-Research</RootNamespace>
<Keyword>Win32Proj</Keyword>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
<ProjectName>Cephla</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
Expand Down Expand Up @@ -91,7 +92,8 @@
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="SquidLEDShutter.cpp" />
<ClCompile Include="SquidDA.cpp" />
<ClCompile Include="SquidShutter.cpp" />
<ClCompile Include="SquidMonitoringThread.cpp" />
<ClCompile Include="SquidHub.cpp" />
<ClCompile Include="SquidXYStage.cpp" />
Expand All @@ -106,6 +108,9 @@
<Project>{b8c95f39-54bf-40a9-807b-598df2821d55}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Text Include="controller-command-set.txt" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<ClCompile Include="SquidMonitoringThread.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="SquidLEDShutter.cpp">
<ClCompile Include="SquidShutter.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="SquidXYStage.cpp">
Expand All @@ -30,6 +30,9 @@
<ClCompile Include="SquidZStage.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="SquidDA.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="crc8.h">
Expand All @@ -39,4 +42,9 @@
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Text Include="controller-command-set.txt">
<Filter>Resource Files</Filter>
</Text>
</ItemGroup>
</Project>
11 changes: 11 additions & 0 deletions DeviceAdapters/Cephla/Cephla_Controller_Docs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

# The Cephla Squid Controller
The Squid Micro-controller by the company Cephla controls multiple microscope components such as motorized XY stages, motorized Z stages, LED and laser light source, and it provides analog (0-5V) and digital outputs. Internally, the controller consists of an Arduino (Due in earlier versions, Teensy 4.1 in newer versions) board that communicates to several other boards, such as motor controllers ([TMC4361](https://www.analog.com/en/products/tmc4361.html), and [TMC2660](https://www.analog.com/en/products/TMC2660.html#part-details)), and DAC boards ([DAC 80508](https://www.ti.com/product/DAC80508) from TI). The design and firmware for the controller are [open source,](https://github.com/hongquanli/octopi-research) hence can be modified for everyone's needs.

## Cabling
The unit needs a ?V power supply with ?A minimum. Most connections are straight forward (XY stage cable, Z Stage cable). The USB connection to the computer is unconventional, i.e. you need a USB cable with ? on both ends. Communication is through a (virtual) serial port, and the device will show up as a COM port in the Windows Device Manager. Baud rate is ignored and communication will take place at highest speeds allowed by the USB connection (i.e. you can choose whatever number for the baud rate).

## Communication protocol



Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@
#define ERR_NO_PORT_SET 21002

extern const char* g_HubDeviceName;
extern const char* g_LEDShutterName;
extern const char* g_ShutterName;
extern const char* g_XYStageName;
extern const char* g_ZStageName;
extern const char* g_DAName;

const unsigned char CMD_MOVE_X = 0;
const unsigned char CMD_MOVE_Y = 1;
Expand Down Expand Up @@ -116,12 +117,15 @@ class SquidHub : public HubBase<SquidHub>

std::string port_;

int assignXYStageDevice(SquidXYStage* xyStageDevice);
int assignZStageDevice(SquidZStage* zStageDevice);
int AssignXYStageDevice(SquidXYStage* xyStageDevice);
int AssignZStageDevice(SquidZStage* zStageDevice);

bool XYStageBusy();
bool ZStageBusy();

int SetDacGain(uint8_t dacNr, bool gain);


private:
bool initialized_;
bool autoHome_;
Expand All @@ -138,15 +142,19 @@ class SquidHub : public HubBase<SquidHub>
std::atomic_bool yStageBusy_;
std::atomic_bool zStageBusy_;
std::atomic_bool busy_;
std::atomic<unsigned char> dac_div_; // 0: 1x gain: 2.5V, 1: 1x gain: 1.25V
std::atomic<unsigned char> dac_gains_; // bit mask with gains. 0 multiples dac_div with 1, 1 multiplies dac_div with 2
// i.e. dac_div_ 1 and dac_gains_ 1 for a given output results in 0-5V range.
std::mutex mutex_;
};



class SquidLEDShutter : public CShutterBase<SquidLEDShutter>
class SquidShutter : public CShutterBase<SquidShutter>
{
public:
SquidLEDShutter();
~SquidLEDShutter();
SquidShutter();
~SquidShutter();

int Initialize();
int Shutdown();
Expand All @@ -167,19 +175,24 @@ class SquidLEDShutter : public CShutterBase<SquidLEDShutter>
int OnRed(MM::PropertyBase* pProp, MM::ActionType eAct);
int OnGreen(MM::PropertyBase* pProp, MM::ActionType eAct);
int OnBlue(MM::PropertyBase* pProp, MM::ActionType eAct);
int OnHasLasers(MM::PropertyBase* pProp, MM::ActionType eAct);
int OnLaserIntensity(MM::PropertyBase* pProp, MM::ActionType eAct, long laserLine);


private:
int sendIllumination(uint8_t pattern, uint8_t intensity, uint8_t red, uint8_t green, uint8_t blue);
int sendLaserIllumination(uint8_t pattern, uint16_t intensity);
SquidHub* hub_;
bool initialized_;
bool hasLasers_;
std::string name_;
MM::MMTime changedTime_;
uint8_t pattern_;
uint8_t intensity_;
uint8_t red_;
uint8_t green_;
uint8_t blue_;
uint16_t iLaser_[5];
bool isOpen_;
uint8_t cmdNr_;
};
Expand Down Expand Up @@ -322,6 +335,49 @@ class SquidZStage : public CStageBase<SquidZStage>
};


class SquidDA : public CSignalIOBase<SquidDA>
{
public:
SquidDA(uint8_t dacNr);
~SquidDA();

// MMDevice API
// ------------
int Initialize();
int Shutdown();

void GetName(char* pszName) const;
bool Busy();

// DA API
int SetGateOpen(bool open);
int GetGateOpen(bool& open);
int SetSignal(double volts);
int GetSignal(double& volts);
int GetLimits(double& minVolts, double& maxVolts);

int IsDASequenceable(bool& isSequenceable) const;

// action interface
// ----------------
int OnVolts(MM::PropertyBase* pProp, MM::ActionType eAct);
int OnVoltRange(MM::PropertyBase* pProp, MM::ActionType eAct);

private:
int SendVoltage(double volt);
SquidHub* hub_;

bool initialized_;
bool busy_;
double maxV_;
double volts_;
double gatedVolts_;
long dacNr_;
bool gateOpen_;
std::string name_;
};


class SquidMessageParser {
public:
SquidMessageParser(unsigned char* inputStream, long inputStreamLength);
Expand Down
174 changes: 174 additions & 0 deletions DeviceAdapters/Cephla/SquidDA.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
#include "Squid.h"

const char* g_DAName = "DA";
const char* g_Volts = "Volts";
const char* g_VoltRange = "Volt-Range";
const char* g_0_5V = "0-5V";
const char* g_0_2_5V = "0-2.5V";


SquidDA::SquidDA(uint8_t dacNr) :
hub_(0),
initialized_(false),
busy_(false),
volts_(0.0),
maxV_(5.0),
gatedVolts_(0.0),
gateOpen_(true),
dacNr_(dacNr)
{
CPropertyAction* pAct = new CPropertyAction(this, &SquidDA::OnVoltRange);
CreateStringProperty(g_VoltRange, g_0_5V, false, pAct, true);
AddAllowedValue(g_VoltRange, g_0_2_5V);
AddAllowedValue(g_VoltRange, g_0_5V);
}


SquidDA::~SquidDA()
{
if (initialized_)
{
Shutdown();
}
}


int SquidDA::Shutdown() {
initialized_ = false;
return DEVICE_OK;
}


void SquidDA::GetName(char* pszName) const
{
std::ostringstream os;
os << g_DAName << "_" << ((int)dacNr_ + 1);
CDeviceUtils::CopyLimitedString(pszName, os.str().c_str());
}


int SquidDA::Initialize()
{
hub_ = static_cast<SquidHub*>(GetParentHub());
if (!hub_ || !hub_->IsPortAvailable()) {
return ERR_NO_PORT_SET;
}
char hubLabel[MM::MaxStrLength];
hub_->GetLabel(hubLabel);

bool setGain = maxV_ == 5.0;;
int ret = hub_->SetDacGain((uint8_t) dacNr_, setGain);
if (ret != DEVICE_OK)
return ret;

CPropertyAction* pAct = new CPropertyAction(this, &SquidDA::OnVolts);
ret = CreateFloatProperty(g_Volts, 0.0, false, pAct);
if (ret != DEVICE_OK)
return ret;
SetPropertyLimits(g_Volts, 0.0, maxV_);

return DEVICE_OK;
}


bool SquidDA::Busy() { return hub_->Busy(); }


int SquidDA::SetGateOpen(bool open)
{
gateOpen_ = open;
if (open)
{
SendVoltage(volts_);
}
else
{
SendVoltage(0.0);
}
return DEVICE_OK;
}

int SquidDA::GetGateOpen(bool& open)
{
open = gateOpen_;
return DEVICE_OK;
};


int SquidDA::SetSignal(double volts)
{
volts_ = volts;
if (gateOpen_)
{
return SendVoltage(volts_);
}
return DEVICE_OK;
}

int SquidDA::GetSignal(double& volts)
{
volts_ = volts;
return DEVICE_OK;
}


int SquidDA::GetLimits(double& minVolts, double& maxVolts)
{
minVolts = 0;
maxVolts = maxV_;
return DEVICE_OK;
}


int SquidDA::IsDASequenceable(bool& isSequenceable) const { isSequenceable = false; return DEVICE_OK; }


// action interface
// ----------------
int SquidDA::OnVoltRange(MM::PropertyBase* pProp, MM::ActionType eAct)
{
if (eAct == MM::BeforeGet)
{
pProp->Set(maxV_ == 2.5 ? g_0_2_5V : g_0_5V);
}
else if (eAct == MM::AfterSet)
{
std::string response;
pProp->Get(response);
maxV_ = response == g_0_2_5V ? 2.5 : 5.0;
}
return DEVICE_OK;
}


int SquidDA::OnVolts(MM::PropertyBase* pProp, MM::ActionType eAct)
{
if (eAct == MM::BeforeGet)
{
pProp->Set(volts_);
}
else if (eAct == MM::AfterSet)
{
pProp->Get(volts_);
return SetSignal(volts_);
}
return DEVICE_OK;
}


int SquidDA::SendVoltage(double volts)
{
const unsigned cmdSize = 8;
unsigned char cmd[cmdSize];
for (unsigned i = 0; i < cmdSize; i++) {
cmd[i] = 0;
}
cmd[1] = CMD_ANALOG_WRITE_ONBOARD_DAC;
cmd[2] = (uint8_t) dacNr_;
uint16_t value = (uint16_t) (volts / maxV_ * 65535);
cmd[3] = (value >> 8) & 0xff;
cmd[4] = value & 0xff;
return hub_->SendCommand(cmd, cmdSize);
}


Loading

0 comments on commit 9baa6be

Please sign in to comment.