From 7485d179219586b1822792dba9e1d4dc0fae71ba Mon Sep 17 00:00:00 2001 From: Matthew Player <31096650+MatthewPlayer@users.noreply.github.com> Date: Fri, 23 Aug 2024 10:15:40 +0100 Subject: [PATCH 1/3] Add Scientifica Motion 8 device adapter The existing Scientifica driver does not support the racks Scientifica now sell. --- .../ScientificaMotion8/ScientificaMotion8.cpp | 1074 +++++++++++++++++ .../ScientificaMotion8/ScientificaMotion8.h | 159 +++ .../ScientificaMotion8.vcxproj | 108 ++ .../ScientificaMotion8.vcxproj.filters | 39 + .../ScientificaRxPacket.cpp | 120 ++ .../ScientificaMotion8/ScientificaRxPacket.h | 92 ++ .../ScientificaTxPacket.cpp | 110 ++ .../ScientificaMotion8/ScientificaTxPacket.h | 84 ++ micromanager.sln | 2 + 9 files changed, 1788 insertions(+) create mode 100644 DeviceAdapters/ScientificaMotion8/ScientificaMotion8.cpp create mode 100644 DeviceAdapters/ScientificaMotion8/ScientificaMotion8.h create mode 100644 DeviceAdapters/ScientificaMotion8/ScientificaMotion8.vcxproj create mode 100644 DeviceAdapters/ScientificaMotion8/ScientificaMotion8.vcxproj.filters create mode 100644 DeviceAdapters/ScientificaMotion8/ScientificaRxPacket.cpp create mode 100644 DeviceAdapters/ScientificaMotion8/ScientificaRxPacket.h create mode 100644 DeviceAdapters/ScientificaMotion8/ScientificaTxPacket.cpp create mode 100644 DeviceAdapters/ScientificaMotion8/ScientificaTxPacket.h diff --git a/DeviceAdapters/ScientificaMotion8/ScientificaMotion8.cpp b/DeviceAdapters/ScientificaMotion8/ScientificaMotion8.cpp new file mode 100644 index 000000000..c2aa6aeec --- /dev/null +++ b/DeviceAdapters/ScientificaMotion8/ScientificaMotion8.cpp @@ -0,0 +1,1074 @@ +/////////////////////////////////////////////////////////////////////////////// +// FILE: ScientificaMotion8.h +// PROJECT: Micro-Manager +// SUBSYSTEM: DeviceAdapters +//----------------------------------------------------------------------------- +// DESCRIPTION: Scientifica Motion 8 rack adapter +// COPYRIGHT: University of California, San Francisco, 2006 +// LICENSE: This file is distributed under the BSD 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: Nenad Amodaj, nenad@amodaj.com, 06/01/2006 +// +// Scientifica Specific Parts +// AUTHOR: Matthew Player (ElecSoft Solutions) + +#include "ScientificaMotion8.h" +#include "ScientificaRxPacket.h" + +#include "ModuleInterface.h" +#include +#include +#include + +#ifdef WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#define AXIS_X 0 +#define AXIS_Y 1 +#define AXIS_Z 2 +#define AXIS_F 6 + +const char* g_DeviceNameM8Hub = "Scientifica-Motion8-Hub"; +const char* g_DeviceNameM8XY_Device1 = "Scientifica-Motion8-XY_Device_1"; +const char* g_DeviceNameM8Z_Device1 = "Scientifica-Motion8-Z_Device_1"; +const char* g_DeviceNameM8XY_Device2 = "Scientifica-Moiton8-XY_Device_2"; +const char* g_DeviceNameM8Z_Device2 = "Scientifica-Moition8-Z_Device_2"; +const char* g_DeviceNameFilter_Device1 = "Scientifica-Motion8-Filter_Device_1"; +const char* g_DeviceNameFilter_Device2 = "Scientifica-Motion8-Filter_Device_2"; + +// static lock +MMThreadLock ScientificaMotion8Hub::lock_; + +/////////////////////////////////////////////////////////////////////////////// +// Exported MMDevice API +/////////////////////////////////////////////////////////////////////////////// +MODULE_API void InitializeModuleData() +{ + RegisterDevice(g_DeviceNameM8Hub, MM::HubDevice, "Hub (required)"); + RegisterDevice(g_DeviceNameM8XY_Device1, MM::XYStageDevice, "XY Stage (Device 1)"); + RegisterDevice(g_DeviceNameM8Z_Device1, MM::StageDevice, "Z Stage (Device 1)"); + RegisterDevice(g_DeviceNameM8XY_Device2, MM::XYStageDevice, "XY Stage (Device 2)"); + RegisterDevice(g_DeviceNameM8Z_Device2, MM::StageDevice, "Z Stage (Device 2)"); + RegisterDevice(g_DeviceNameFilter_Device1, MM::StateDevice, "Filter Wheel (Device 1)"); + RegisterDevice(g_DeviceNameFilter_Device2, MM::StateDevice, "Filter Wheel (Device 2)"); +} + +MODULE_API MM::Device* CreateDevice(const char* deviceName) +{ + if (deviceName == 0) + return 0; + + if (strcmp(deviceName, g_DeviceNameM8Hub) == 0) + { + return new ScientificaMotion8Hub; + } + else if (strcmp(deviceName, g_DeviceNameM8XY_Device1) == 0) + { + return new M8XYStage(0); + } + else if (strcmp(deviceName, g_DeviceNameM8Z_Device1) == 0) + { + return new M8ZStage(0); + } + else if (strcmp(deviceName, g_DeviceNameM8XY_Device2) == 0) + { + return new M8XYStage(1); + } + else if (strcmp(deviceName, g_DeviceNameM8Z_Device2) == 0) + { + return new M8ZStage(1); + } + else if (strcmp(deviceName, g_DeviceNameFilter_Device1) == 0) + { + return new M8FilterCubeTurret(0); + } + else if (strcmp(deviceName, g_DeviceNameFilter_Device2) == 0) + { + return new M8FilterCubeTurret(1); + } + + return 0; +} + +MODULE_API void DeleteDevice(MM::Device* pDevice) +{ + delete pDevice; +} + +/////////////////////////////////////////////////////////////////////////////// +// M8XYStage implementation +/////////////////////////////////////////////////////////////////////////////// + +ScientificaMotion8Hub::ScientificaMotion8Hub() : + initialized_ (false) +{ + InitializeDefaultErrorMessages(); + + // Parent ID display + CreateHubIDProperty(); + + CPropertyAction* pAct = new CPropertyAction(this, &ScientificaMotion8Hub::OnPort); + CreateProperty(MM::g_Keyword_Port, "Undefined", MM::String, false, pAct, true); + + device_1_x_channel_ = 0xFF; + device_1_y_channel_ = 0xFF; + device_1_z_channel_ = 0xFF; + device_1_f_channel_ = 0xFF; + + device_2_x_channel_ = 0xFF; + device_2_y_channel_ = 0xFF; + device_2_z_channel_ = 0xFF; + device_2_f_channel_ = 0xFF; +} + +ScientificaMotion8Hub::~ScientificaMotion8Hub() +{ + Shutdown(); +} + +void ScientificaMotion8Hub::GetName(char* name) const +{ + CDeviceUtils::CopyLimitedString(name, g_DeviceNameM8Hub); +} + +bool ScientificaMotion8Hub::Busy() +{ + return false; +} + +//Is DetectDevice() implemented +bool ScientificaMotion8Hub::SupportsDeviceDetection(void) +{ + return true; +} + +//Used to automate discovery of correct serial port +MM::DeviceDetectionStatus ScientificaMotion8Hub::DetectDevice(void) +{ + if (initialized_) + return MM::CanCommunicate; + + MM::DeviceDetectionStatus result = MM::Misconfigured; + char answerTO[MM::MaxStrLength]; + + try + { + std::string portLowerCase = port_; + for (std::string::iterator its = portLowerCase.begin(); its != portLowerCase.end(); ++its) + { + *its = (char)tolower(*its); + } + if (0 < portLowerCase.length() && 0 != portLowerCase.compare("undefined") && 0 != portLowerCase.compare("unknown")) + { + result = MM::CanNotCommunicate; + + GetCoreCallback()->GetDeviceProperty(port_.c_str(), "AnswerTimeout", answerTO); + + GetCoreCallback()->SetDeviceProperty(port_.c_str(), MM::g_Keyword_BaudRate, "115200"); + GetCoreCallback()->SetDeviceProperty(port_.c_str(), MM::g_Keyword_StopBits, "1"); + + GetCoreCallback()->SetDeviceProperty(port_.c_str(), "AnswerTimeout", "300.0"); + GetCoreCallback()->SetDeviceProperty(port_.c_str(), "DelayBetweenCharsMs", "0"); + + MM::Device* pS = GetCoreCallback()->GetDevice(this, port_.c_str()); + pS->Initialize(); + + CDeviceUtils::SleepMs(1000); + MMThreadGuard myLock(lock_); + PurgeComPort(port_.c_str()); + + std::string version; + bool supportedVersion = CheckControllerVersion(); + if (!supportedVersion) + { + LogMessage("Controller needs updating to 0.9.27 or above. Please use LinLab 3 0.5.16 or above to update the controller."); + result = MM::Misconfigured; + } + else + { + int ret = ReadControllerMap(); + if (ret == DEVICE_OK && + ((device_1_x_channel_ != 0xFF) || (device_1_y_channel_ != 0xFF) || (device_1_z_channel_ != 0xFF) || (device_2_x_channel_ != 0xFF) || (device_2_y_channel_ != 0xFF) || (device_2_z_channel_ != 0xFF))) + { + result = MM::CanCommunicate; + } + } + + pS->Shutdown(); + + GetCoreCallback()->SetDeviceProperty(port_.c_str(), "AnswerTimeout", answerTO); + } + } + catch (...) + { + LogMessage("Exception in DetectDevice!", false); + } + + return result; +} + +ScientificaRxPacket* ScientificaMotion8Hub::WriteRead(ScientificaTxPacket* tx, int expected_length) +{ + ScientificaRxPacket* rx_packet = NULL; + + MMThreadGuard myLock(lock_); + + PurgeComPort(port_.c_str()); + + const unsigned char* data = tx->GetPacketToSend(); + int len = tx->GetEncodedLength(); + + int return_status = WriteToComPort(port_.c_str(), data, len); + + if (return_status != DEVICE_OK) + { + return NULL; + } + + unsigned char rxBuffer[256]; //256 is the maximum size of a packet + int bufferIndex = 0; + unsigned long actualBytesRead = 0; + + MM::MMTime startTime = GetCurrentMMTime(); + bool readZero = false; + + while (!readZero && ((GetCurrentMMTime() - startTime).getMsec() < 250)) + { + return_status = ReadFromComPort(port_.c_str(), &rxBuffer[bufferIndex], 256 - bufferIndex, actualBytesRead); + if (return_status != DEVICE_OK) + break; + + for (int i = bufferIndex; i < (bufferIndex + actualBytesRead); i++) + { + if (rxBuffer[i] == 0) + { + readZero = true; + break; + } + } + + bufferIndex += actualBytesRead; + } + + if (!readZero) + { + rx_packet = NULL; + } + + if (bufferIndex > 0) + { + rx_packet = new ScientificaRxPacket(rxBuffer, bufferIndex - 1); //rxBuffer is decoded into to rx_packet + + if (rx_packet->RemainingBytes() < expected_length) + { + delete rx_packet; + rx_packet = NULL; + } + } + + return rx_packet; +} + + +bool ScientificaMotion8Hub::CheckControllerVersion() +{ + bool supportedVersion = false; + std::string version; + ScientificaTxPacket* txPacket = new ScientificaTxPacket(0xBB, 0, 1); + ScientificaRxPacket* rxPacket = NULL; + + rxPacket = WriteRead(txPacket, 6); + + if (rxPacket != NULL) + { + uint16_t major; + uint16_t minor; + uint16_t patch; + + rxPacket->GetUInt16(&major); + rxPacket->GetUInt16(&minor); + rxPacket->GetUInt16(&patch); + + if (minor >= 9 || (minor == 9 && patch > 27)) + { + supportedVersion = true; + } + + std::ostringstream oss; + oss << major << "." << minor << "." << patch; + version = oss.str(); + + LogMessage("Controller version: " + version, false); + + delete rxPacket; + } + + return supportedVersion; +} + +int ScientificaMotion8Hub::Stop(uint8_t device) +{ + ScientificaTxPacket* txPacket = new ScientificaTxPacket(0xBB, 2, 7); + ScientificaRxPacket* rxPacket = NULL; + + int ret = DEVICE_OK; + + rxPacket = WriteRead(txPacket, 0); + + if (rxPacket == NULL) + { + ret = DEVICE_SERIAL_TIMEOUT; + } + else + { + delete rxPacket; + } + + return ret; +} + +int ScientificaMotion8Hub::SetPosition(uint8_t device, uint8_t axis, long steps) +{ + ScientificaTxPacket* txPacket = new ScientificaTxPacket(0xBB, 2, 0xC); + txPacket->AddUInt8(device); + txPacket->AddUInt8(axis); + txPacket->AddInt32(steps); + ScientificaRxPacket* rxPacket = NULL; + + int ret = DEVICE_OK; + + rxPacket = WriteRead(txPacket, 0); + + if (rxPacket == NULL) + { + ret = DEVICE_SERIAL_TIMEOUT; + } + else + { + delete rxPacket; + } + + return ret; +} + +int ScientificaMotion8Hub::IsMoving(uint8_t device, bool* is_moving) +{ + if(is_moving == NULL) + return DEVICE_ERR; + + ScientificaTxPacket* txPacket = new ScientificaTxPacket(0xBB, 2, 0xF); + txPacket->AddUInt8(device); + ScientificaRxPacket* rxPacket = NULL; + + int ret = DEVICE_OK; + rxPacket = WriteRead(txPacket, 1); + + if (rxPacket == NULL) + { + ret = DEVICE_SERIAL_TIMEOUT; + } + else + { + uint8_t moving; + rxPacket->GetByte(&moving); + *is_moving = moving != 0; + delete rxPacket; + } + + return ret; +} + +int ScientificaMotion8Hub::ReadControllerMap(void) +{ + unsigned char tx[3]; + tx[0] = 0xBB; + tx[1] = 0; + tx[2] = 6; + + ScientificaTxPacket* txPacket = new ScientificaTxPacket(0xBB, 0, 6); + ScientificaRxPacket* rxPacket = NULL; + + device_1_x_channel_ = 0xFF; + device_1_y_channel_ = 0xFF; + device_1_z_channel_ = 0xFF; + device_1_f_channel_ = 0xFF; + + device_2_x_channel_ = 0xFF; + device_2_y_channel_ = 0xFF; + device_2_z_channel_ = 0xFF; + device_2_f_channel_ = 0xFF; + + + int ret = DEVICE_OK; + rxPacket = WriteRead(txPacket, 16); + + if (rxPacket == NULL) + { + ret = DEVICE_SERIAL_TIMEOUT; + } + else + { + for (int ch = 0; ch < 8; ch++) + { + uint8_t device; + uint8_t axis; + + rxPacket->GetByte(&device); + rxPacket->GetByte(&axis); + + if (device == 0) + { + if (axis == AXIS_X) + device_1_x_channel_ = ch; + else if (axis == AXIS_Y) + device_1_y_channel_ = ch; + else if (axis == AXIS_Z) + device_1_z_channel_ = ch; + else if (axis == AXIS_F) + device_1_f_channel_ = ch; + + } + else if (device == 1) + { + if (axis == AXIS_X) + device_2_x_channel_ = ch; + else if (axis == AXIS_Y) + device_2_y_channel_ = ch; + else if (axis == AXIS_Z) + device_2_z_channel_ = ch; + else if (axis == AXIS_F) + device_2_f_channel_ = ch; + } + } + + delete rxPacket; + } + + return ret; +} + + +int ScientificaMotion8Hub::Initialize() +{ + // Name + int ret = CreateProperty(MM::g_Keyword_Name, g_DeviceNameM8Hub, MM::String, true); + if (DEVICE_OK != ret) + return ret; + + CDeviceUtils::SleepMs(2000); + + MMThreadGuard myLock(lock_); + + initialized_ = true; + + return DEVICE_OK; +} + + +//Detext and instantiate all avalible chile peripherals +int ScientificaMotion8Hub::DetectInstalledDevices() +{ + if (MM::CanCommunicate == DetectDevice()) + { + ReadControllerMap(); + + std::vector peripherals; + peripherals.clear(); + + if((device_1_x_channel_ != 0xFF) || (device_1_y_channel_ != 0xFF)) + { + peripherals.push_back(g_DeviceNameM8XY_Device1); + } + if (device_1_z_channel_ != 0xFF) + { + peripherals.push_back(g_DeviceNameM8Z_Device1); + } + if (device_1_f_channel_ != 0xFF) + { + peripherals.push_back(g_DeviceNameFilter_Device1); + } + if ((device_2_x_channel_ != 0xFF) || (device_2_y_channel_ != 0xFF)) + { + peripherals.push_back(g_DeviceNameM8XY_Device2); + } + if (device_2_z_channel_ != 0xFF) + { + peripherals.push_back(g_DeviceNameM8Z_Device2); + } + if (device_2_f_channel_ != 0xFF) + { + peripherals.push_back(g_DeviceNameFilter_Device2); + } + + for (size_t i = 0; i < peripherals.size(); i++) + { + MM::Device* pDev = ::CreateDevice(peripherals[i].c_str()); + if (pDev) + { + AddInstalledDevice(pDev); + } + } + + } + + return DEVICE_OK; +} + +int ScientificaMotion8Hub::Shutdown() +{ + initialized_ = false; + return DEVICE_OK; +} + +int ScientificaMotion8Hub::OnPort(MM::PropertyBase* pProp, MM::ActionType pAct) +{ + if (pAct == MM::BeforeGet) + { + pProp->Set(port_.c_str()); + } + else if (pAct == MM::AfterSet) + { + pProp->Get(port_); + } + return DEVICE_OK; +} + +M8XYStage::M8XYStage(uint8_t device) +{ + CreateProperty(MM::g_Keyword_Name, "Scientifica-Motion8-XYStage", MM::String, true); + device_ = device; + + name_ = device == 0 ? g_DeviceNameM8XY_Device1 : g_DeviceNameM8XY_Device2; +} + +M8XYStage::~M8XYStage() +{ + +} + +bool M8XYStage::Busy() +{ + bool is_moving = false; + + int ret = DEVICE_OK; + + MM::Hub* hub = GetParentHub(); + if (!hub) + return DEVICE_INTERNAL_INCONSISTENCY; + + ScientificaMotion8Hub* parentHub = dynamic_cast(hub); + if (!parentHub) + return DEVICE_INTERNAL_INCONSISTENCY; + + ret = parentHub->IsMoving(device_, &is_moving); + + return ret; +} + +void M8XYStage::GetName(char* name) const +{ + CDeviceUtils::CopyLimitedString(name, name_.c_str()); +} + +int M8XYStage::Initialize() +{ + return DEVICE_OK; +} + +int M8XYStage::Shutdown() +{ + return DEVICE_OK; +} + +int M8XYStage::SetPositionSteps(long x, long y) +{ + MM::Hub* hub = GetParentHub(); + if (!hub) + return DEVICE_INTERNAL_INCONSISTENCY; + + ScientificaMotion8Hub* parentHub = dynamic_cast(hub); + if (!parentHub) + return DEVICE_INTERNAL_INCONSISTENCY; + + ScientificaTxPacket* txPacket = new ScientificaTxPacket(0xBB, 2, 3); + txPacket->AddUInt8(device_); + txPacket->AddInt32(x); + txPacket->AddInt32(y); + ScientificaRxPacket* rxPacket = NULL; + + int ret = DEVICE_OK; + + rxPacket = parentHub->WriteRead(txPacket, 0); + + if (rxPacket == NULL) + { + ret = DEVICE_SERIAL_TIMEOUT; + } + else + { + delete rxPacket; + } + + return ret; +} + +int M8XYStage::GetPositionSteps(long& x, long& y) +{ + MM::Hub* hub = GetParentHub(); + if (!hub) + return DEVICE_INTERNAL_INCONSISTENCY; + + ScientificaMotion8Hub* parentHub = dynamic_cast(hub); + if (!parentHub) + return DEVICE_INTERNAL_INCONSISTENCY; + + ScientificaTxPacket* txPacket = new ScientificaTxPacket(0xBB, 0, 0x14); + txPacket->AddUInt8(device_); + ScientificaRxPacket* rxPacket = NULL; + + int ret = DEVICE_OK; + + rxPacket = parentHub->WriteRead(txPacket, 29); + + if (rxPacket == NULL) + { + ret = DEVICE_SERIAL_TIMEOUT; + } + else + { + uint8_t device; + rxPacket->GetByte(&device); //Called to skip the device byte + int32_t x_from_device; + int32_t y_from_device; + rxPacket->GetInt32(&x_from_device); + rxPacket->GetInt32(&y_from_device); + x = x_from_device; + y = y_from_device; + delete rxPacket; + } + + return ret; +} + +int M8XYStage::Home() +{ + return DEVICE_OK; +} + +int M8XYStage::Stop() +{ + int ret = DEVICE_OK; + + MM::Hub* hub = GetParentHub(); + if (!hub) + return DEVICE_INTERNAL_INCONSISTENCY; + + ScientificaMotion8Hub* parentHub = dynamic_cast(hub); + if (!parentHub) + return DEVICE_INTERNAL_INCONSISTENCY; + + ret = parentHub->Stop(device_); + + return ret; +} + +int M8XYStage::SetOrigin() +{ + int ret; + ret = SetXOrigin(); + if (ret == DEVICE_OK) + ret = SetYOrigin(); + + return ret; +} + +int M8XYStage::SetXOrigin() +{ + int ret = DEVICE_OK; + + MM::Hub* hub = GetParentHub(); + if (!hub) + return DEVICE_INTERNAL_INCONSISTENCY; + + ScientificaMotion8Hub* parentHub = dynamic_cast(hub); + if (!parentHub) + return DEVICE_INTERNAL_INCONSISTENCY; + + ret = parentHub->SetPosition(device_, AXIS_X, 0); + + return ret; +} + +int M8XYStage::SetYOrigin() +{ + int ret = DEVICE_OK; + + MM::Hub* hub = GetParentHub(); + if (!hub) + return DEVICE_INTERNAL_INCONSISTENCY; + + ScientificaMotion8Hub* parentHub = dynamic_cast(hub); + if (!parentHub) + return DEVICE_INTERNAL_INCONSISTENCY; + + ret = parentHub->SetPosition(device_, AXIS_Y, 0); +} + +M8ZStage::M8ZStage(uint8_t device) +{ + CreateProperty(MM::g_Keyword_Name, "Scientifica-Motion8-ZStage", MM::String, true); + device_ = device; + + + name_ = device == 0 ? g_DeviceNameM8Z_Device1 : g_DeviceNameM8Z_Device2; +} + +M8ZStage::~M8ZStage() +{ + +} + +bool M8ZStage::Busy() +{ + bool is_moving = false; + + int ret = DEVICE_OK; + + MM::Hub* hub = GetParentHub(); + if (!hub) + return DEVICE_INTERNAL_INCONSISTENCY; + + ScientificaMotion8Hub* parentHub = dynamic_cast(hub); + if (!parentHub) + return DEVICE_INTERNAL_INCONSISTENCY; + + ret = parentHub->IsMoving(device_, &is_moving); + + return ret; +} + +void M8ZStage::GetName(char* name) const +{ + CDeviceUtils::CopyLimitedString(name, name_.c_str()); +} + +int M8ZStage::Initialize() +{ + return DEVICE_OK; +} + +int M8ZStage::Shutdown() +{ + return DEVICE_OK; +} + +int M8ZStage::SetPositionUm(double pos) +{ + long steps = round(pos / 0.01); + return SetPositionSteps(steps); + +} +int M8ZStage::GetPositionUm(double& pos) +{ + long steps; + int ret = GetPositionSteps(steps); + if (ret != DEVICE_OK) + return ret; + + pos = steps * 0.01; + + return DEVICE_OK; +} + +int M8ZStage::SetPositionSteps(long z) +{ + MM::Hub* hub = GetParentHub(); + if (!hub) + return DEVICE_INTERNAL_INCONSISTENCY; + + ScientificaMotion8Hub* parentHub = dynamic_cast(hub); + if (!parentHub) + return DEVICE_INTERNAL_INCONSISTENCY; + + ScientificaTxPacket* txPacket = new ScientificaTxPacket(0xBB, 2, 3); + txPacket->AddUInt8(device_); + txPacket->AddUInt8(AXIS_Z); + txPacket->AddInt32(z); + ScientificaRxPacket* rxPacket = NULL; + + int ret = DEVICE_OK; + + rxPacket = parentHub->WriteRead(txPacket, 0); + + if (rxPacket == NULL) + { + ret = DEVICE_SERIAL_TIMEOUT; + } + else + { + delete rxPacket; + } + + return ret; +} + +int M8ZStage::GetPositionSteps(long& z) +{ + MM::Hub* hub = GetParentHub(); + if (!hub) + return DEVICE_INTERNAL_INCONSISTENCY; + + ScientificaMotion8Hub* parentHub = dynamic_cast(hub); + if (!parentHub) + return DEVICE_INTERNAL_INCONSISTENCY; + + ScientificaTxPacket* txPacket = new ScientificaTxPacket(0xBB, 0, 0x14); + txPacket->AddUInt8(device_); + ScientificaRxPacket* rxPacket = NULL; + + int ret = DEVICE_OK; + + rxPacket = parentHub->WriteRead(txPacket, 29); + + if (rxPacket == NULL) + { + ret = DEVICE_SERIAL_TIMEOUT; + } + else + { + + uint8_t device; + + rxPacket->GetByte(&device); //Called to skip the device byte + + int32_t ignore_from_device; + rxPacket->GetInt32(&ignore_from_device); //Called to skip the x value + rxPacket->GetInt32(&ignore_from_device); //Called to skip the y value + + int32_t z_from_device; + rxPacket->GetInt32(&z_from_device); + z = z_from_device; + + delete rxPacket; + } + + + return ret; +} + +int M8ZStage::Home() +{ + return DEVICE_OK; +} + +int M8ZStage::Stop() +{ + int ret = DEVICE_OK; + + MM::Hub* hub = GetParentHub(); + if (!hub) + return DEVICE_INTERNAL_INCONSISTENCY; + + ScientificaMotion8Hub* parentHub = dynamic_cast(hub); + if (!parentHub) + return DEVICE_INTERNAL_INCONSISTENCY; + + ret = parentHub->Stop(device_); + + return ret; +} + +int M8ZStage::SetOrigin() +{ + int ret = DEVICE_OK; + + MM::Hub* hub = GetParentHub(); + if (!hub) + return DEVICE_INTERNAL_INCONSISTENCY; + + ScientificaMotion8Hub* parentHub = dynamic_cast(hub); + if (!parentHub) + return DEVICE_INTERNAL_INCONSISTENCY; + + ret = parentHub->SetPosition(device_, AXIS_Z, 0); +} + +M8FilterCubeTurret::M8FilterCubeTurret(uint8_t device) +{ + // CreateProperty(MM::g_Keyword_Name, "Scientifica-Motion8-ZStage", MM::String, true); + device_ = device; + numPositions_ = 3; + + name_ = device == 0 ? g_DeviceNameFilter_Device1 : g_DeviceNameFilter_Device2; + +} + +M8FilterCubeTurret::~M8FilterCubeTurret() +{ + +} + +int M8FilterCubeTurret::Initialize() +{ + return DEVICE_OK; +} + +int M8FilterCubeTurret::Shutdown() +{ + return DEVICE_OK; +} + +void M8FilterCubeTurret::GetName(char* name) const +{ + CDeviceUtils::CopyLimitedString(name, name_.c_str()); +} + +bool M8FilterCubeTurret::Busy() +{ + bool is_moving = false; + + MM::Hub* hub = GetParentHub(); + if (!hub) + return is_moving; + + ScientificaMotion8Hub* parentHub = dynamic_cast(hub); + if (!parentHub) + return is_moving; + + ScientificaTxPacket* txPacket = new ScientificaTxPacket(0xBB, 0, 0x11); + ScientificaRxPacket* rxPacket = NULL; + + int ret = DEVICE_OK; + + rxPacket = parentHub->WriteRead(txPacket, 18); + + if (rxPacket != NULL) + { + + if (device_ == 0) + { + rxPacket->Skip(5); //Skip to Device 1 filter state + } + else + { + rxPacket->Skip(14); //Skip to Device 2 filter state + } + + uint8_t filterState; + rxPacket->GetByte(&filterState); + + is_moving = filterState != 0; + + delete rxPacket; + } + + return is_moving; +} + +int M8FilterCubeTurret::OnState(MM::PropertyBase* pProp, MM::ActionType eAct) +{ + LogMessage("M8FilterCubeTurret::PositionGetSet\n", true); + + if (eAct == MM::BeforeGet) + { + int filterIndex; + int ret = GetFilter(filterIndex); + if (ret != DEVICE_OK) + return ret; + pProp->Set((long)filterIndex); + } + else if (eAct == MM::AfterSet) + { + long filterIndex; + pProp->Get(filterIndex); + + if ((filterIndex > 0) && (filterIndex <= numPositions_)) + return SetFilter(filterIndex); + else + return DEVICE_UNKNOWN_POSITION; + } + + return DEVICE_OK; +} + +int M8FilterCubeTurret::SetFilter(int filterIndex) +{ + MM::Hub* hub = GetParentHub(); + if (!hub) + return DEVICE_INTERNAL_INCONSISTENCY; + + ScientificaMotion8Hub* parentHub = dynamic_cast(hub); + if (!parentHub) + return DEVICE_INTERNAL_INCONSISTENCY; + + ScientificaTxPacket* txPacket = new ScientificaTxPacket(0xBB, 2, 0x0E); + txPacket->AddUInt8(device_); + txPacket->AddUInt8(filterIndex); + + ScientificaRxPacket* rxPacket = NULL; + + int ret = DEVICE_OK; + rxPacket = parentHub->WriteRead(txPacket, 18); + + if (rxPacket == NULL) + { + ret = DEVICE_SERIAL_TIMEOUT; + } + else + { + delete rxPacket; + } + + return ret; +} + +int M8FilterCubeTurret::GetFilter(int& filterIndex) +{ + MM::Hub* hub = GetParentHub(); + if (!hub) + return DEVICE_INTERNAL_INCONSISTENCY; + + ScientificaMotion8Hub* parentHub = dynamic_cast(hub); + if (!parentHub) + return DEVICE_INTERNAL_INCONSISTENCY; + + ScientificaTxPacket* txPacket = new ScientificaTxPacket(0xBB, 2, 0x0E); + ScientificaRxPacket* rxPacket = NULL; + + int ret = DEVICE_OK; + + rxPacket = parentHub->WriteRead(txPacket, 2); + + if (rxPacket == NULL) + { + ret = DEVICE_SERIAL_TIMEOUT; + } + else + { + + rxPacket->Skip(1); //Skip device index + uint8_t filter; + rxPacket->GetByte(&filter); + + if (filter < numPositions_) + filter = filter; + else + ret = DEVICE_UNKNOWN_POSITION; + + + delete rxPacket; + } + + return ret; +} \ No newline at end of file diff --git a/DeviceAdapters/ScientificaMotion8/ScientificaMotion8.h b/DeviceAdapters/ScientificaMotion8/ScientificaMotion8.h new file mode 100644 index 000000000..e385a4550 --- /dev/null +++ b/DeviceAdapters/ScientificaMotion8/ScientificaMotion8.h @@ -0,0 +1,159 @@ +/////////////////////////////////////////////////////////////////////////////// +// FILE: ScientificaMotion8.h +// PROJECT: Micro-Manager +// SUBSYSTEM: DeviceAdapters +//----------------------------------------------------------------------------- +// DESCRIPTION: Scientifica Motion 8 rack adapter +// COPYRIGHT: University of California, San Francisco, 2006 +// LICENSE: This file is distributed under the BSD 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: Nenad Amodaj, nenad@amodaj.com, 06/01/2006 +// +// Scientifica Specific Parts +// AUTHOR: Matthew Player (ElecSoft Solutions) + +#ifndef _SCIENTIFICA_MOTION_8_H_ +#define _SCIENTIFICA_MOTION_8_H_ + +#include "MMDevice.h" +#include "DeviceBase.h" +#include +#include +#include "ScientificaTxPacket.h" +#include "ScientificaRxPacket.h" + +class ScientificaMotion8Hub : public HubBase +{ +public: + ScientificaMotion8Hub(); + ~ScientificaMotion8Hub(); + + int Initialize(); + int Shutdown(); + void GetName(char* pName) const; + bool Busy(); + + bool SupportsDeviceDetection(void); + MM::DeviceDetectionStatus DetectDevice(void); + int DetectInstalledDevices(); + + int OnPort(MM::PropertyBase* pPropt, MM::ActionType eAct); + + ScientificaRxPacket* WriteRead(ScientificaTxPacket* tx, int expected_length); + bool CheckControllerVersion(); + int Stop(uint8_t device); + int SetPosition(uint8_t device, uint8_t axis, long steps); + int IsMoving(uint8_t device, bool* moving); + bool initialized_; +private: + std::string port_; + static MMThreadLock lock_; + int ReadControllerMap(void); + + + uint8_t device_1_x_channel_; + uint8_t device_1_y_channel_; + uint8_t device_1_z_channel_; + uint8_t device_1_f_channel_; + + uint8_t device_2_x_channel_; + uint8_t device_2_y_channel_; + uint8_t device_2_z_channel_; + uint8_t device_2_f_channel_; +}; + + +class M8XYStage : public CXYStageBase +{ +public: + M8XYStage(uint8_t device); + ~M8XYStage(); + + bool Busy(); + void GetName(char* pName) const; + + int Initialize(); + int Shutdown(); + + // XYStage API + int SetPositionSteps(long x, long y); + int GetPositionSteps(long& x, long& y); + int Home(); + int Stop(); + int SetOrigin(); + int SetXOrigin(); + int SetYOrigin(); + int GetLimitsUm(double& xMin, double& xMax, double& yMin, double& yMax) { return DEVICE_UNSUPPORTED_COMMAND; } + int GetStepLimits(long& xMin, long& xMax, long& yMin, long& yMax) { return DEVICE_UNSUPPORTED_COMMAND; } + double GetStepSizeXUm() { return 0.01; } + double GetStepSizeYUm() { return 0.01; } + int IsXYStageSequenceable(bool& isSequenceable) const { isSequenceable = false; return DEVICE_OK; } +private: + uint8_t device_; + std::string name_; +}; + +class M8ZStage : public CStageBase +{ +public: + M8ZStage(uint8_t device); + ~M8ZStage(); + + //Device API + int Initialize(); + int Shutdown(); + void GetName(char* pName) const; + bool Busy(); + + // Stage API + int GetPositionUm(double& pos); + int SetPositionUm(double pos); + int SetPositionSteps(long steps); + int GetPositionSteps(long& steps); + int Home(); + int Stop(); + int SetOrigin(); + int GetLimits(double& min, double& max) { return DEVICE_UNSUPPORTED_COMMAND; } + int IsStageSequenceable(bool& isSequenceable) const { isSequenceable = false; return DEVICE_OK; } + bool IsContinuousFocusDrive() const { return false; } +private: + uint8_t device_; + std::string name_; +}; + +class M8FilterCubeTurret : public CStateDeviceBase +{ +public: + M8FilterCubeTurret(uint8_t device); + ~M8FilterCubeTurret(); + + + //Device API + int Initialize(); + int Shutdown(); + void GetName(char* pName) const; + bool Busy(); + + unsigned long GetNumberOfPositions()const { return numPositions_; } + + int OnState(MM::PropertyBase* pProp, MM::ActionType eAct); +private: + uint8_t device_; + std::string name_; + + int SetFilter(int filterIndex); + int GetFilter(int& filterIndex); + + int numPositions_; +}; + +#endif diff --git a/DeviceAdapters/ScientificaMotion8/ScientificaMotion8.vcxproj b/DeviceAdapters/ScientificaMotion8/ScientificaMotion8.vcxproj new file mode 100644 index 000000000..0a54c5289 --- /dev/null +++ b/DeviceAdapters/ScientificaMotion8/ScientificaMotion8.vcxproj @@ -0,0 +1,108 @@ + + + + + Debug + x64 + + + Release + x64 + + + + {E4E9FA4F-E9DD-4483-9140-2FD472C28F1D} + Scientifica + Win32Proj + 10.0 + + + + DynamicLibrary + MultiByte + v142 + false + + + DynamicLibrary + MultiByte + v142 + true + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + false + false + + + + X64 + + + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + EnableFastChecks + true + + + 4290;%(DisableSpecificWarnings) + + + true + Windows + + + + + + + X64 + + + WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + + + 4290;%(DisableSpecificWarnings) + + + Windows + true + true + + + + + + + + + + + + + + + + + {b8c95f39-54bf-40a9-807b-598df2821d55} + + + + + + \ No newline at end of file diff --git a/DeviceAdapters/ScientificaMotion8/ScientificaMotion8.vcxproj.filters b/DeviceAdapters/ScientificaMotion8/ScientificaMotion8.vcxproj.filters new file mode 100644 index 000000000..97d6f0163 --- /dev/null +++ b/DeviceAdapters/ScientificaMotion8/ScientificaMotion8.vcxproj.filters @@ -0,0 +1,39 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/DeviceAdapters/ScientificaMotion8/ScientificaRxPacket.cpp b/DeviceAdapters/ScientificaMotion8/ScientificaRxPacket.cpp new file mode 100644 index 000000000..0760c0a60 --- /dev/null +++ b/DeviceAdapters/ScientificaMotion8/ScientificaRxPacket.cpp @@ -0,0 +1,120 @@ +/////////////////////////////////////////////////////////////////////////////// +// FILE: ScientificaRxPacket.h +// PROJECT: Micro-Manager +// SUBSYSTEM: DeviceAdapters +//----------------------------------------------------------------------------- +// DESCRIPTION: Helper class to parse packets from Scientifica motion 8 racks +// +// LICENSE: This file is distributed under the BSD 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: Matthew Player (ElecSoft Solutions) + +#include "ScientificaRxPacket.h" + +#define MAX_PACKET_SIZE 256 + +ScientificaRxPacket::ScientificaRxPacket(unsigned char* data, int data_length) +{ + index_ = 0; + data_ = new unsigned char[MAX_PACKET_SIZE]; + + //COBS Decoding + int block_remaining = 0; + int block_length = 0xFF; + int write = 0; + + for (int i = 0; i < MAX_PACKET_SIZE; i++) + { + data_[i] = 0; + } + + for (int i = 0; i < data_length; i++) + { + if (block_remaining != 0) + { + if (data[i] != 0) + { + data_[write] = data[i]; + write++; + } + } + else + { + if (block_length != 0xFF) + { + data_[write] = 0; + write++; + } + block_remaining = data[i]; + block_length = data[i]; + } + + block_remaining--; + } + + data_length_ = write; + + if (data_length_ < 4) + { + status = 0; + echo = 0; + command1 = 0; + command2 = 0; + } + else + { + status = data_[0]; + echo = data_[1]; + command1 = data_[2]; + command2 = data_[3]; + index_ = 4; + } +} + +ScientificaRxPacket::~ScientificaRxPacket() +{ + delete[] data_; +} + +bool ScientificaRxPacket::GetByte(uint8_t* value) +{ + if (index_ + 1 > data_length_) + return false; + + *value = data_[index_]; + index_++; + return true; +} + +bool ScientificaRxPacket::GetUInt16(uint16_t* value) +{ + if (index_ + 2 > data_length_) + return false; + + *value = data_[index_]; + *value |= data_[index_ + 1] << 8; + index_ += 2; + return true; +} + +bool ScientificaRxPacket::GetInt32(int32_t* value) +{ + if (index_ + 4 > data_length_) + return false; + + *value = data_[index_]; + *value |= data_[index_ + 1] << 8; + *value |= data_[index_ + 2] << 16; + *value |= data_[index_ + 3] << 24; + index_ += 4; + return true; +} \ No newline at end of file diff --git a/DeviceAdapters/ScientificaMotion8/ScientificaRxPacket.h b/DeviceAdapters/ScientificaMotion8/ScientificaRxPacket.h new file mode 100644 index 000000000..47e94a895 --- /dev/null +++ b/DeviceAdapters/ScientificaMotion8/ScientificaRxPacket.h @@ -0,0 +1,92 @@ +/////////////////////////////////////////////////////////////////////////////// +// FILE: ScientificaRxPacket.h +// PROJECT: Micro-Manager +// SUBSYSTEM: DeviceAdapters +//----------------------------------------------------------------------------- +// DESCRIPTION: Helper class to parse packets from Scientifica motion 8 racks +// +// LICENSE: This file is distributed under the BSD 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: Matthew Player (ElecSoft Solutions) + +#pragma once +#include +class ScientificaRxPacket +{ +public: + /** + * @brief Constructor + */ + ScientificaRxPacket(unsigned char* buffer, int buffer_size); + + /** + * @brief Destructor + */ + ~ScientificaRxPacket(); + + /** + * @brief Get next unsigned 8 bit integer from packet + * @param[in] value Destination for value + * @return true if successful, false if not enough data + */ + bool GetByte(uint8_t* value); + + /** + * @brief Get next unsigned 16 bit integer from packet + * @param[in] value Destination for value + * @return true if successful, false if not enough data + */ + bool GetUInt16(uint16_t* value); + + /** + * @brief Get next signed 32 bit integer from packet + * @param[in] value Destination for value + * @return true if successful, false if not enough data + */ + bool GetInt32(int32_t* value); + + /** + * @brief Get the remaining number of bytes in the packet + * @return The number of bytes remaining in the packet + */ + int RemainingBytes() { return data_length_ - index_; } + + /** + * @brief Get the length of the packet + * @return The length of the packet + */ + int Length() { return data_length_; } + + /** + * @brief Get the data buffer + * @return The data buffer + */ + unsigned char* GetData() { return data_; } + + /** + * @brief Skip the next given number of bytes in the packet + * @param[in] count The number of bytes to skip + */ + void Skip(int count) { index_ += count; } + + +private: + unsigned char* data_; + int data_length_; + int index_; + + uint8_t status; + uint8_t echo; + uint8_t command1; + uint8_t command2; +}; + diff --git a/DeviceAdapters/ScientificaMotion8/ScientificaTxPacket.cpp b/DeviceAdapters/ScientificaMotion8/ScientificaTxPacket.cpp new file mode 100644 index 000000000..7a6b17104 --- /dev/null +++ b/DeviceAdapters/ScientificaMotion8/ScientificaTxPacket.cpp @@ -0,0 +1,110 @@ +/////////////////////////////////////////////////////////////////////////////// +// FILE: ScientificaTxPacket.h +// PROJECT: Micro-Manager +// SUBSYSTEM: DeviceAdapters +//----------------------------------------------------------------------------- +// DESCRIPTION: Helper class to build packets to send to Scientifica motion 8 racks +// +// LICENSE: This file is distributed under the BSD 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: Matthew Player (ElecSoft Solutions) + +#include "ScientificaTxPacket.h" + +#define MAX_PACKET_SIZE 256 + +ScientificaTxPacket::ScientificaTxPacket(uint8_t echo, uint8_t command1, uint8_t command2) +{ + packet_ = new uint8_t[MAX_PACKET_SIZE]; + encoded_ = new uint8_t[MAX_PACKET_SIZE]; + write_index_ = 0; + encoded_length_ = 0; + + packet_[0] = echo; + packet_[1] = command1; + packet_[2] = command2; + write_index_ = 3; +} +ScientificaTxPacket::~ScientificaTxPacket() +{ + delete[] packet_; + delete[] encoded_; +} + +unsigned char* ScientificaTxPacket::GetPacketToSend() +{ + int block_start = 0; + int block_length = 1; + int write = 1; + + for (int i = 0; i < MAX_PACKET_SIZE; i++) + { + encoded_[i] = 0; + } + //COBS Encoding + for (int i = 0; i < write_index_; i++) + { + if (packet_[i] != 0) + { + encoded_[write] = packet_[i]; + block_length++; + write++; + } + + if ((block_length == 0xFF) || (packet_[i] == 0)) + { + encoded_[block_start] = block_length; + block_start = write; + encoded_[write] = 0; + write++; + block_length = 1; + } + } + encoded_[block_start] = block_length; + encoded_[write] = 0x0; //Add packet deliminator + write++; + + encoded_length_ = write; + return (unsigned char*)encoded_; +} + +void ScientificaTxPacket::Clear() +{ + write_index_ = 0; +} + +void ScientificaTxPacket::AddUInt8(uint8_t byte) +{ + packet_[write_index_++] = byte; +} + +void ScientificaTxPacket::AddUInt16(uint16_t word) +{ + packet_[write_index_++] = word & 0xff; + packet_[write_index_++] = (word >> 8) & 0xff; +} + +void ScientificaTxPacket::AddUInt32(uint32_t dword) +{ + packet_[write_index_++] = dword & 0xff; + packet_[write_index_++] = (dword >> 8) & 0xff; + packet_[write_index_++] = (dword >> 16) & 0xff; + packet_[write_index_++] = (dword >> 24) & 0xff; +} + +void ScientificaTxPacket::AddInt32(int32_t dword) +{ + packet_[write_index_++] = dword & 0xff; + packet_[write_index_++] = (dword >> 8) & 0xff; + packet_[write_index_++] = (dword >> 16) & 0xff; + packet_[write_index_++] = (dword >> 24) & 0xff; +} diff --git a/DeviceAdapters/ScientificaMotion8/ScientificaTxPacket.h b/DeviceAdapters/ScientificaMotion8/ScientificaTxPacket.h new file mode 100644 index 000000000..dc304b88f --- /dev/null +++ b/DeviceAdapters/ScientificaMotion8/ScientificaTxPacket.h @@ -0,0 +1,84 @@ +/////////////////////////////////////////////////////////////////////////////// +// FILE: ScientificaTxPacket.h +// PROJECT: Micro-Manager +// SUBSYSTEM: DeviceAdapters +//----------------------------------------------------------------------------- +// DESCRIPTION: Helper class to build packets to send to Scientifica motion 8 racks +// +// LICENSE: This file is distributed under the BSD 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: Matthew Player (ElecSoft Solutions) + +#pragma once +#include + +class ScientificaTxPacket +{ +public: + /** + * @brief Constructor + */ + ScientificaTxPacket(uint8_t echo, uint8_t command1, uint8_t command2); + + /** + * @brief Destructor + */ + ~ScientificaTxPacket(); + + /** + * @brief Get the encoded packet ready to send + * @return encoded packet to send + */ + unsigned char* GetPacketToSend(); + + /** + * @brief Get the length of the encoded packet + * @return The length of the encoded packet + */ + int GetEncodedLength() { return encoded_length_; } + + /** + * @brief Clear all data from the packet + */ + void Clear(); + + /** + * @brief Add an unsigned 8 bit integer to packet + * @param[in] byte value to add + */ + void AddUInt8(uint8_t byte); + + /** + * @brief Add an unsigned 16 bit integer to packet + * @param[in] word value to add + */ + void AddUInt16(uint16_t word); + + /** + * @brief Add an unsigned 32 bit integer to packet + * @param[in] dword value to add + */ + void AddUInt32(uint32_t dword); + + /** + * @brief Add an signed 32 bit integer to packet + * @param[in] dword value to add + */ + void AddInt32(int32_t dword); + +private: + uint8_t* packet_; + uint8_t* encoded_; + int write_index_; + int encoded_length_; +}; + diff --git a/micromanager.sln b/micromanager.sln index 1f1ef0562..8aaa6b37f 100644 --- a/micromanager.sln +++ b/micromanager.sln @@ -496,6 +496,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Hikrobot", "DeviceAdapters\ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "OpenFlexure", "DeviceAdapters\OpenFlexure\OpenFlexure.vcxproj", "{149B6A9D-40FB-4FDF-BC0C-6B68E3BC4938}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ScientificaMotion8", "DeviceAdapters\ScientificaMotion8\ScientificaMotion8.vcxproj", "{E4E9FA4F-E9DD-4483-9140-2FD472C28F1D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 From 4b47d267964909bcf6756ee54b7eca4a6ff2499f Mon Sep 17 00:00:00 2001 From: Matthew Player <31096650+MatthewPlayer@users.noreply.github.com> Date: Tue, 27 Aug 2024 08:32:21 +0100 Subject: [PATCH 2/3] Fix build warnings on ScientificaMotion 8 Project --- .../ScientificaMotion8/ScientificaMotion8.cpp | 50 +++++++++++++++---- .../ScientificaMotion8/ScientificaMotion8.h | 6 +-- .../ScientificaTxPacket.cpp | 4 +- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/DeviceAdapters/ScientificaMotion8/ScientificaMotion8.cpp b/DeviceAdapters/ScientificaMotion8/ScientificaMotion8.cpp index c2aa6aeec..627ac0bc9 100644 --- a/DeviceAdapters/ScientificaMotion8/ScientificaMotion8.cpp +++ b/DeviceAdapters/ScientificaMotion8/ScientificaMotion8.cpp @@ -249,7 +249,7 @@ ScientificaRxPacket* ScientificaMotion8Hub::WriteRead(ScientificaTxPacket* tx, i if (return_status != DEVICE_OK) break; - for (int i = bufferIndex; i < (bufferIndex + actualBytesRead); i++) + for (unsigned int i = bufferIndex; i < (bufferIndex + actualBytesRead); i++) { if (rxBuffer[i] == 0) { @@ -324,6 +324,7 @@ int ScientificaMotion8Hub::Stop(uint8_t device) int ret = DEVICE_OK; + txPacket->AddUInt8(device); rxPacket = WriteRead(txPacket, 0); if (rxPacket == NULL) @@ -419,7 +420,7 @@ int ScientificaMotion8Hub::ReadControllerMap(void) } else { - for (int ch = 0; ch < 8; ch++) + for (uint8_t ch = 0; ch < 8; ch++) { uint8_t device; uint8_t axis; @@ -565,11 +566,11 @@ bool M8XYStage::Busy() MM::Hub* hub = GetParentHub(); if (!hub) - return DEVICE_INTERNAL_INCONSISTENCY; + return true; ScientificaMotion8Hub* parentHub = dynamic_cast(hub); if (!parentHub) - return DEVICE_INTERNAL_INCONSISTENCY; + return true; ret = parentHub->IsMoving(device_, &is_moving); @@ -723,6 +724,27 @@ int M8XYStage::SetYOrigin() return DEVICE_INTERNAL_INCONSISTENCY; ret = parentHub->SetPosition(device_, AXIS_Y, 0); + return ret; +} + +int M8XYStage::GetLimitsUm(double& xMin, double& xMax, double& yMin, double& yMax) +{ + (void)xMin; + (void)xMax; + (void)yMin; + (void)yMax; + + return DEVICE_UNSUPPORTED_COMMAND; +} + +int M8XYStage::GetStepLimits(long& xMin, long& xMax, long& yMin, long& yMax) +{ + (void)xMin; + (void)xMax; + (void)yMin; + (void)yMax; + + return DEVICE_UNSUPPORTED_COMMAND; } M8ZStage::M8ZStage(uint8_t device) @@ -747,11 +769,11 @@ bool M8ZStage::Busy() MM::Hub* hub = GetParentHub(); if (!hub) - return DEVICE_INTERNAL_INCONSISTENCY; + return true; ScientificaMotion8Hub* parentHub = dynamic_cast(hub); if (!parentHub) - return DEVICE_INTERNAL_INCONSISTENCY; + return true; ret = parentHub->IsMoving(device_, &is_moving); @@ -775,7 +797,7 @@ int M8ZStage::Shutdown() int M8ZStage::SetPositionUm(double pos) { - long steps = round(pos / 0.01); + long steps = (long)round(pos / 0.01); return SetPositionSteps(steps); } @@ -902,6 +924,15 @@ int M8ZStage::SetOrigin() return DEVICE_INTERNAL_INCONSISTENCY; ret = parentHub->SetPosition(device_, AXIS_Z, 0); + + return ret; +} + +int M8ZStage::GetLimits(double& min, double& max) +{ + (void)min; + (void)max; + return DEVICE_UNSUPPORTED_COMMAND; } M8FilterCubeTurret::M8FilterCubeTurret(uint8_t device) @@ -949,8 +980,6 @@ bool M8FilterCubeTurret::Busy() ScientificaTxPacket* txPacket = new ScientificaTxPacket(0xBB, 0, 0x11); ScientificaRxPacket* rxPacket = NULL; - int ret = DEVICE_OK; - rxPacket = parentHub->WriteRead(txPacket, 18); if (rxPacket != NULL) @@ -1014,7 +1043,7 @@ int M8FilterCubeTurret::SetFilter(int filterIndex) ScientificaTxPacket* txPacket = new ScientificaTxPacket(0xBB, 2, 0x0E); txPacket->AddUInt8(device_); - txPacket->AddUInt8(filterIndex); + txPacket->AddUInt8((uint8_t)filterIndex); ScientificaRxPacket* rxPacket = NULL; @@ -1048,6 +1077,7 @@ int M8FilterCubeTurret::GetFilter(int& filterIndex) int ret = DEVICE_OK; + txPacket->AddUInt8((uint8_t)filterIndex); rxPacket = parentHub->WriteRead(txPacket, 2); if (rxPacket == NULL) diff --git a/DeviceAdapters/ScientificaMotion8/ScientificaMotion8.h b/DeviceAdapters/ScientificaMotion8/ScientificaMotion8.h index e385a4550..00b098e41 100644 --- a/DeviceAdapters/ScientificaMotion8/ScientificaMotion8.h +++ b/DeviceAdapters/ScientificaMotion8/ScientificaMotion8.h @@ -92,8 +92,8 @@ class M8XYStage : public CXYStageBase int SetOrigin(); int SetXOrigin(); int SetYOrigin(); - int GetLimitsUm(double& xMin, double& xMax, double& yMin, double& yMax) { return DEVICE_UNSUPPORTED_COMMAND; } - int GetStepLimits(long& xMin, long& xMax, long& yMin, long& yMax) { return DEVICE_UNSUPPORTED_COMMAND; } + int GetLimitsUm(double& xMin, double& xMax, double& yMin, double& yMax); + int GetStepLimits(long& xMin, long& xMax, long& yMin, long& yMax); double GetStepSizeXUm() { return 0.01; } double GetStepSizeYUm() { return 0.01; } int IsXYStageSequenceable(bool& isSequenceable) const { isSequenceable = false; return DEVICE_OK; } @@ -122,7 +122,7 @@ class M8ZStage : public CStageBase int Home(); int Stop(); int SetOrigin(); - int GetLimits(double& min, double& max) { return DEVICE_UNSUPPORTED_COMMAND; } + int GetLimits(double& min, double& max); int IsStageSequenceable(bool& isSequenceable) const { isSequenceable = false; return DEVICE_OK; } bool IsContinuousFocusDrive() const { return false; } private: diff --git a/DeviceAdapters/ScientificaMotion8/ScientificaTxPacket.cpp b/DeviceAdapters/ScientificaMotion8/ScientificaTxPacket.cpp index 7a6b17104..e45683836 100644 --- a/DeviceAdapters/ScientificaMotion8/ScientificaTxPacket.cpp +++ b/DeviceAdapters/ScientificaMotion8/ScientificaTxPacket.cpp @@ -62,14 +62,14 @@ unsigned char* ScientificaTxPacket::GetPacketToSend() if ((block_length == 0xFF) || (packet_[i] == 0)) { - encoded_[block_start] = block_length; + encoded_[block_start] = (uint8_t)block_length; block_start = write; encoded_[write] = 0; write++; block_length = 1; } } - encoded_[block_start] = block_length; + encoded_[block_start] = (uint8_t)block_length; encoded_[write] = 0x0; //Add packet deliminator write++; From 54e895f0e385006244a5e267701084abcd321cf4 Mon Sep 17 00:00:00 2001 From: "Mark A. Tsuchida" Date: Wed, 28 Aug 2024 14:18:35 -0500 Subject: [PATCH 3/3] Repair micromanager.sln --- micromanager.sln | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/micromanager.sln b/micromanager.sln index 8aaa6b37f..a2e021c9a 100644 --- a/micromanager.sln +++ b/micromanager.sln @@ -1990,6 +1990,12 @@ Global {149B6A9D-40FB-4FDF-BC0C-6B68E3BC4938}.Release|x64.Build.0 = Release|x64 {149B6A9D-40FB-4FDF-BC0C-6B68E3BC4938}.Release|x86.ActiveCfg = Release|Win32 {149B6A9D-40FB-4FDF-BC0C-6B68E3BC4938}.Release|x86.Build.0 = Release|Win32 + {E4E9FA4F-E9DD-4483-9140-2FD472C28F1D}.Debug|x64.ActiveCfg = Debug|x64 + {E4E9FA4F-E9DD-4483-9140-2FD472C28F1D}.Debug|x64.Build.0 = Debug|x64 + {E4E9FA4F-E9DD-4483-9140-2FD472C28F1D}.Debug|x86.ActiveCfg = Debug|x64 + {E4E9FA4F-E9DD-4483-9140-2FD472C28F1D}.Release|x64.ActiveCfg = Release|x64 + {E4E9FA4F-E9DD-4483-9140-2FD472C28F1D}.Release|x64.Build.0 = Release|x64 + {E4E9FA4F-E9DD-4483-9140-2FD472C28F1D}.Release|x86.ActiveCfg = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE