Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 100 additions & 4 deletions DeviceAdapters/EvidentIX85Win/EvidentHubWin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -977,6 +977,19 @@ int EvidentHubWin::ExecuteCommand(const std::string& command, std::string& respo
return ret;
}

void EvidentHubWin::ExecuteCommandFireAndForget(const std::string& command,
std::function<void(int, const std::string&)> callback)
{
CommandTask task(command);
task.completionCallback = std::move(callback);

{
std::lock_guard<std::mutex> lock(queueMutex_);
commandQueue_.push(std::move(task));
}
queueCV_.notify_one();
}

void EvidentHubWin::CommandWorkerThread()
{
while (workerRunning_)
Expand Down Expand Up @@ -1008,16 +1021,25 @@ void EvidentHubWin::CommandWorkerThread()

// Execute command (outside queue lock to allow new submissions)
std::string response;
int ret = DEVICE_ERR;

try
{
int ret = ExecuteCommandInternal(task.command, response);
task.responsePromise.set_value(std::make_pair(ret, response));
ret = ExecuteCommandInternal(task.command, response);
}
catch (...)
{
task.responsePromise.set_exception(std::current_exception());
if (task.completionCallback)
task.completionCallback(DEVICE_ERR, "");
else
task.responsePromise.set_exception(std::current_exception());
continue;
}

if (task.completionCallback)
task.completionCallback(ret, response);
else
task.responsePromise.set_value(std::make_pair(ret, response));
}
}

Expand Down Expand Up @@ -1259,8 +1281,9 @@ int EvidentHubWin::DoDeviceDetection()
model_.SetDevicePresent(DeviceType_OffsetLens, true);
availableDevices_.push_back(DeviceType_OffsetLens);
detectedDevicesByName_.push_back(g_OffsetLensDeviceName);
model_.SetLimits(DeviceType_OffsetLens, OFFSET_LENS_MIN_POS, OFFSET_LENS_MAX_POS);

// Query initial offset lens position
// Query initial offset lens position and hardware range
QueryOffsetLens();
}

Expand Down Expand Up @@ -1874,12 +1897,81 @@ int EvidentHubWin::QueryOffsetLens()
{
int pos = ParseIntParameter(params[0]);
model_.SetPosition(DeviceType_OffsetLens, pos);

long nosepiecePos = model_.GetPosition(DeviceType_Nosepiece);
if (nosepiecePos >= 1 && nosepiecePos <= NOSEPIECE_MAX_POS)
QueryOffsetLensRange(static_cast<int>(nosepiecePos));
else
model_.SetLimits(DeviceType_OffsetLens, OFFSET_LENS_MIN_POS, OFFSET_LENS_MAX_POS);

return DEVICE_OK;
}

return ERR_DEVICE_NOT_AVAILABLE;
}

int EvidentHubWin::QueryOffsetLensRange(int nosepiecePos)
{
std::string cmd = BuildCommand(CMD_OFFSET_LENS_RANGE, nosepiecePos);
std::string response;
int ret = ExecuteCommand(cmd, response);
if (ret != DEVICE_OK)
{
model_.SetLimits(DeviceType_OffsetLens, OFFSET_LENS_MIN_POS, OFFSET_LENS_MAX_POS);
return ret;
}

ApplyOffsetLensRange(nosepiecePos, ret, response);
return DEVICE_OK;
}

void EvidentHubWin::QueryOffsetLensRangeAsync(int nosepiecePos)
{
std::string cmd = BuildCommand(CMD_OFFSET_LENS_RANGE, nosepiecePos);
ExecuteCommandFireAndForget(cmd,
[this, nosepiecePos](int ret, const std::string& response)
{
ApplyOffsetLensRange(nosepiecePos, ret, response);
});
}

void EvidentHubWin::ApplyOffsetLensRange(int nosepiecePos, int ret, const std::string& response)
{
if (ret != DEVICE_OK)
{
model_.SetLimits(DeviceType_OffsetLens, OFFSET_LENS_MIN_POS, OFFSET_LENS_MAX_POS);
return;
}

std::vector<std::string> params = ParseParameters(response);
if (params.size() >= 2)
{
long lower = ParseLongParameter(params[0]);
long upper = ParseLongParameter(params[1]);

if (lower >= OFFSET_LENS_MIN_POS && upper <= OFFSET_LENS_MAX_POS && lower <= upper)
{
model_.SetLimits(DeviceType_OffsetLens, lower, upper);
std::ostringstream msg;
msg << "Offset lens range for nosepiece " << nosepiecePos
<< ": " << lower << " to " << upper << " steps";
LogMessage(msg.str().c_str(), true);
return;
}

std::ostringstream msg;
msg << "Invalid GABRANGE response for nosepiece " << nosepiecePos
<< ": lower=" << lower << " upper=" << upper << "; using defaults";
LogMessage(msg.str().c_str(), false);
}
else
{
LogMessage("GABRANGE response missing parameters; using defaults", false);
}

model_.SetLimits(DeviceType_OffsetLens, OFFSET_LENS_MIN_POS, OFFSET_LENS_MAX_POS);
}

int EvidentHubWin::UpdateNosepieceIndicator(int position)
{
// Check if MCU is present
Expand Down Expand Up @@ -2173,6 +2265,10 @@ void EvidentHubWin::ProcessNotification(const std::string& message)
{
model_.SetPosition(DeviceType_Nosepiece, pos);

// Refresh offset lens range for the new objective (async — must not block callback thread)
if (model_.IsDevicePresent(DeviceType_OffsetLens) && pos >= 1 && pos <= NOSEPIECE_MAX_POS)
QueryOffsetLensRangeAsync(pos);

// Note: MCU indicator I1 is updated automatically by SDK when using OBSEQ

// Check if we've reached the target position
Expand Down
7 changes: 7 additions & 0 deletions DeviceAdapters/EvidentIX85Win/EvidentHubWin.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <string>
#include <vector>
#include <queue>
#include <functional>
#include <future>
#include <thread>
#include <atomic>
Expand All @@ -42,6 +43,7 @@ struct CommandTask
{
std::string command;
std::promise<std::pair<int, std::string>> responsePromise;
std::function<void(int, const std::string&)> completionCallback; // optional fire-and-forget path

CommandTask(std::string cmd) : command(std::move(cmd)) {}

Expand Down Expand Up @@ -84,6 +86,8 @@ class EvidentHubWin : public HubBase<EvidentHubWin>
// Command execution (thread-safe with worker thread queue)
std::future<std::pair<int, std::string>> ExecuteCommandAsync(const std::string& command);
int ExecuteCommand(const std::string& command, std::string& response);
void ExecuteCommandFireAndForget(const std::string& command,
std::function<void(int, const std::string&)> callback);
int SendCommand(const std::string& command);
int GetResponse(std::string& response, long timeoutMs = -1);

Expand Down Expand Up @@ -149,6 +153,9 @@ class EvidentHubWin : public HubBase<EvidentHubWin>
int QueryCorrectionCollar();
int QueryManualControl();
int QueryOffsetLens();
int QueryOffsetLensRange(int nosepiecePos); // blocking — call only from non-callback context
void QueryOffsetLensRangeAsync(int nosepiecePos); // non-blocking — safe from SDK callback thread
void ApplyOffsetLensRange(int nosepiecePos, int ret, const std::string& response);

// Manual Control Unit (MCU) helpers
int UpdateNosepieceIndicator(int position);
Expand Down
23 changes: 18 additions & 5 deletions DeviceAdapters/EvidentIX85Win/EvidentIX85Win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5056,9 +5056,11 @@ int EvidentOffsetLens::SetPositionUm(double pos)
// Convert μm to steps
long steps = static_cast<long>(pos / stepSizeUm_);

// Clamp to limits
if (steps < OFFSET_LENS_MIN_POS) steps = OFFSET_LENS_MIN_POS;
if (steps > OFFSET_LENS_MAX_POS) steps = OFFSET_LENS_MAX_POS;
// Clamp to hardware-reported limits for the current objective
long minSteps, maxSteps;
hub->GetModel()->GetLimits(EvidentIX85Win::DeviceType_OffsetLens, minSteps, maxSteps);
if (steps < minSteps) steps = minSteps;
if (steps > maxSteps) steps = maxSteps;

hub->GetModel()->SetBusy(EvidentIX85Win::DeviceType_OffsetLens, true);

Expand Down Expand Up @@ -5117,8 +5119,19 @@ int EvidentOffsetLens::SetOrigin()

int EvidentOffsetLens::GetLimits(double& lower, double& upper)
{
lower = OFFSET_LENS_MIN_POS * stepSizeUm_;
upper = OFFSET_LENS_MAX_POS * stepSizeUm_;
EvidentHubWin* hub = GetHub();
if (hub)
{
long minSteps, maxSteps;
hub->GetModel()->GetLimits(EvidentIX85Win::DeviceType_OffsetLens, minSteps, maxSteps);
lower = minSteps * stepSizeUm_;
upper = maxSteps * stepSizeUm_;
}
else
{
lower = OFFSET_LENS_MIN_POS * stepSizeUm_;
upper = OFFSET_LENS_MAX_POS * stepSizeUm_;
}
return DEVICE_OK;
}

Expand Down
2 changes: 1 addition & 1 deletion DeviceAdapters/EvidentIX85Win/EvidentProtocolWin.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ const char* const CMD_OFFSET_LENS_MOVE = "ABM";
const char* const CMD_OFFSET_LENS_STOP = "ABSTP";
const char* const CMD_OFFSET_LENS_POSITION = "ABP";
const char* const CMD_OFFSET_LENS_NOTIFY = "NABP";
const char* const CMD_OFFSET_LENS_RANGE = "ABRANGE";
const char* const CMD_OFFSET_LENS_RANGE = "GABRANGE";
const char* const CMD_OFFSET_LENS_LIMIT = "ABLMT";
const char* const CMD_OFFSET_LENS_LOST_MOTION = "ABLM";
const char* const CMD_OFFSET_LENS_BASE_POSITION = "ABBP";
Expand Down
Loading