Skip to content

Commit

Permalink
make "clear axis status" configurable via option interface
Browse files Browse the repository at this point in the history
  • Loading branch information
lrossa committed Feb 10, 2025
1 parent ad3622d commit 36ad045
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 7 deletions.
2 changes: 1 addition & 1 deletion iocs/phytronIOC/iocBoot/iocPhytron/st.cmd.mcc
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ drvAsynIPPortConfigure("testRemote","192.168.167.116:22222",0,0,1)
#asynSetTraceInfoMask("testRemote", 0, 0x0F)

#phytronCreateMCC(phytronPort, asynPort, address, movingPollPeriod, idlePollPeriod, timeout, do-not-reset
phytronCreateMCC("phyMotionPort", "testRemote", 0, 10, 10, 1000)
phytronCreateMCC("phyMotionPort", "testRemote", 0, 1000, 1000, 1000, 1)
asynSetOption("phyMotionPort", 0, "fakeHomedEnable", "true")

#phytronCreateAxis(phytronPort, module, axis)
Expand Down
1 change: 1 addition & 0 deletions iocs/phytronIOC/iocBoot/iocPhytron/st.cmd.phytron
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ drvAsynIPPortConfigure("testRemote","10.5.1.181:22222",0,0,1)
phytronCreateController ("phyMotionPort", "testRemote", 10, 10, 1000)
asynSetOption("phyMotionPort", 0, "pollMethod", "parallel")
asynSetOption("phyMotionPort", 0, "fakeHomedEnable", "true")
asynSetOption("phyMotionPort", 0, "clearAxisStatus", "true")

#phytronCreateAxis(phytronPort, module, axis)
phytronCreateAxis("phyMotionPort", 1, 1)
Expand Down
102 changes: 96 additions & 6 deletions phytronApp/src/phytronAxisMotor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ phytronController::phytronController(phytronController::TYPE iCtrlType, const ch
, iDefaultPollMethod_(pollMethodSerial)
, fake_homed_enable_(false)
, allow_exit_on_error_(false)
, statusResetTime_(0.0)
{
asynStatus status;
static const char *functionName = "phytronController::phytronController";
Expand Down Expand Up @@ -590,6 +591,7 @@ asynStatus phytronController::readOption(asynUser* pasynUser, const char* szKey,
if (szKey && szValue) {
*szValue = '\0';
if (epicsStrCaseCmp(szKey, "pollMethod") == 0) {
// polling methods: serial, axis-parallel or controller-parallel; axis may have "default"
const char* szMethod;
phytronAxis* pAxis(getAxis(pasynUser));
enum pollMethod iMethod(pAxis ? pAxis->iPollMethod_ : iDefaultPollMethod_);
Expand All @@ -603,11 +605,30 @@ asynStatus phytronController::readOption(asynUser* pasynUser, const char* szKey,
snprintf(szValue, iMaxChars, "%d/%s", static_cast<int>(iMethod), szMethod);
return asynSuccess;
}

if (epicsStrCaseCmp(szKey, "clearAxisStatus") == 0) {
// "clear axis status" before move
phytronAxis* pAxis(getAxis(pasynUser));
float fTime(fabs(pAxis ? pAxis->statusResetTime_ : statusResetTime_));
if (!isfinite(fTime))
snprintf(szValue, iMaxChars, "default");
else if (fTime >= 0.001)
snprintf(szValue, iMaxChars, "%g", fTime);
else if (fTime > 0)
snprintf(szValue, iMaxChars, "on");
else
snprintf(szValue, iMaxChars, "off");
return asynSuccess;
}

if (epicsStrCaseCmp(szKey, "fakeHomedEnable") == 0) {
// configure "fake homed" bit
snprintf(szValue, iMaxChars, "%s", fake_homed_enable_ ? "true" : "false");
return asynSuccess;
}

if (epicsStrCaseCmp(szKey, "fakeHomedCache") == 0) {
// show "fake homed" cache
int iLen(0);
szValue[0] = '\0';
for (int i = 0; i < ARRAY_SIZE(fake_homed_cache_); ++i) {
Expand All @@ -619,7 +640,9 @@ asynStatus phytronController::readOption(asynUser* pasynUser, const char* szKey,
}
return asynSuccess;
}

if (epicsStrCaseCmp(szKey, "allowExitOnError") == 0) {
// configure "allow exit on error": after detection of this, the IOC exists and should be restarted by procServ
snprintf(szValue, iMaxChars, "%s", allow_exit_on_error_ ? "true" : "false");
return asynSuccess;
}
Expand Down Expand Up @@ -660,7 +683,7 @@ asynStatus phytronController::writeOption(asynUser* pasynUser, const char* szKey
if (epicsParseInt64(szValue, &iTmp, 0, NULL) == 0) {
if (iTmp < (pAxis ? static_cast<epicsInt64>(pollMethodDefault) : static_cast<epicsInt64>(pollMethodSerial)) ||
iTmp > static_cast<epicsInt64>(pollMethodControllerParallel))
goto wrongValue;
goto wrongValue_parallel;
iMethod = static_cast<pollMethod>(iTmp);
} else {
while (isspace(*szValue)) ++szValue;
Expand All @@ -685,7 +708,7 @@ asynStatus phytronController::writeOption(asynUser* pasynUser, const char* szKey
(iLen == 19 && !epicsStrnCaseCmp(szValue, "controller-parallel", 19)))
iMethod = pollMethodControllerParallel;
else
goto wrongValue;
goto wrongValue_parallel;
}
if (iCtrlType_ != TYPE_PHYMOTION && iMethod != pollMethodDefault && iMethod != pollMethodSerial)
{
Expand All @@ -700,7 +723,44 @@ asynStatus phytronController::writeOption(asynUser* pasynUser, const char* szKey
return asynSuccess;
}

if (epicsStrCaseCmp(szKey, "clearAxisStatus") == 0) {
// configure "clear axis status" before move
float fTime(0.), *pfTime(&statusResetTime_);
getAddress(pasynUser, &iAxisNo);
if (iAxisNo > 0) {
pAxis = getAxis(iAxisNo);
if (!pAxis) {
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"phytronController:writeOption(%s, %s) wrong axis", szKey, szValue);
return asynError;
}
pfTime = &pAxis->statusResetTime_;
}

if (epicsParseFloat(szValue, &fTime, NULL) == 0 && fTime >= 0. && fTime <= 10.)
;
else if (pAxis && epicsStrCaseCmp(szValue, "default") == 0)
fTime = epicsNAN;
else if (epicsStrCaseCmp(szValue, "t") == 0 || epicsStrCaseCmp(szValue, "true") == 0 ||
epicsStrCaseCmp(szValue, "y") == 0 || epicsStrCaseCmp(szValue, "yes") == 0 ||
epicsStrCaseCmp(szValue, "on") == 0)
fTime = 0.000001;
else if (epicsStrCaseCmp(szValue, "f") == 0 || epicsStrCaseCmp(szValue, "false") == 0 ||
epicsStrCaseCmp(szValue, "n") == 0 || epicsStrCaseCmp(szValue, "no") == 0 ||
epicsStrCaseCmp(szValue, "off") == 0)
fTime = 0.;
else {
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"phytronController:writeOption(%s, %s) wrong value - allowed is seconds (0..10) or boolean%s",
szKey, szValue, pAxis ? " or \"default\"" : "");
goto wrongValue;
}
*pfTime = fTime;
return asynSuccess;
}

if (epicsStrCaseCmp(szKey, "fakeHomedEnable") == 0) {
// configure "fake homed" bit: ORed real homed status with autosave position
if (epicsParseInt64(szValue, &iTmp, 0, NULL) == 0)
fake_homed_enable_ = (iTmp != 0);
else if (epicsStrCaseCmp(szValue, "t") == 0 || epicsStrCaseCmp(szValue, "true") == 0 ||
Expand All @@ -717,11 +777,12 @@ asynStatus phytronController::writeOption(asynUser* pasynUser, const char* szKey
epicsStrCaseCmp(szValue, "off") == 0)
fake_homed_enable_ = false;
else
goto wrongValue;
goto wrongValue_bool;
return asynSuccess;
}

if (epicsStrCaseCmp(szKey, "allowExitOnError") == 0) {
// configure "allow exit on error": after detection of this, the IOC exists and should be restarted by procServ
if (epicsParseInt64(szValue, &iTmp, 0, NULL) == 0)
allow_exit_on_error_ = (iTmp != 0);
else if (epicsStrCaseCmp(szValue, "t") == 0 || epicsStrCaseCmp(szValue, "true") == 0 ||
Expand All @@ -733,17 +794,24 @@ asynStatus phytronController::writeOption(asynUser* pasynUser, const char* szKey
epicsStrCaseCmp(szValue, "off") == 0)
allow_exit_on_error_ = false;
else
goto wrongValue;
goto wrongValue_bool;
return asynSuccess;
}

finish:
return asynMotorController::writeOption(pasynUser, szKey, szValue);

wrongValue:
wrongValue_parallel:
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"phytronController:writeOption(%s, %s) wrong value - allowed are %sserial,axis-parallel,%sparallel",
szKey, szValue, pAxis ? "default," : "", pAxis ? "controller-" : "");
goto wrongValue;

wrongValue_bool:
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"phytronController:writeOption(%s, %s) wrong value - allowed is boolean", szKey, szValue);

wrongValue:
return asynError;
}

Expand Down Expand Up @@ -1278,6 +1346,7 @@ phytronAxis::phytronAxis(phytronController *pC, int iAxisNo)
, brakeReleased_(0)
, iPollMethod_(pollMethodDefault)
, homeState_(0)
, statusResetTime_(0.0)
{
//Controller always supports encoder. Encoder enable/disable is set through UEIP
setIntegerParam(pC_->motorStatusHasEncoder_, 1);
Expand Down Expand Up @@ -1321,8 +1390,27 @@ void phytronAxis::report(FILE *fp, int level)
*/
phytronStatus phytronAxis::clearAxisError(std::vector<std::string>* pCmdList)
{
float fTime(statusResetTime_);
if (pC_->iCtrlType_ != phytronController::TYPE_PHYMOTION )
return phytronSuccess; // not supported
if (!isfinite(fTime))
{
fTime = fabs(pC_->statusResetTime_);
if (fTime <= 0.)
return phytronSuccess; // not needed
}
if (fTime <= 0.0)
return phytronSuccess; // not needed
if (fTime > 10.)
fTime = 10.;
if (fTime >= 0.001) // reset status and wait
{
phytronStatus iResult(pC_->sendPhytronCommand(std::string("SEC") + &axisModuleNo_[1]));
epicsThreadSleep(statusResetTime_);
statusResetTime_ = -statusResetTime_;
return iResult;
}
statusResetTime_ = -statusResetTime_;
if (pCmdList)
{
pCmdList->push_back(std::string("SEC") + &axisModuleNo_[1]);
Expand Down Expand Up @@ -1983,7 +2071,7 @@ bool phytronAxis::parseAnswer(std::vector<std::string> &asValues)
}
}
else
bResult = !(iAxisStatus & 0xF800); // axis internal/limit-switch/power-stage/SFI/ENDAT error
bResult = !(iAxisStatus & 0xE800); // axis internal/power-stage/SFI/ENDAT error
setIntegerParam(pC_->motorStatusHighLimit_, iHighLimit);
setIntegerParam(pC_->motorStatusLowLimit_, iLowLimit);
setIntegerParam(pC_->motorStatusAtHome_, (iAxisStatus & 0x40)/0x40);
Expand All @@ -1999,6 +2087,8 @@ bool phytronAxis::parseAnswer(std::vector<std::string> &asValues)
setIntegerParam(pC_->axisStatus_, iAxisStatus); // Update the axis status record ($(P)$(M)_STATUS)

finish:
if (!bResult && statusResetTime_ < 0.) // axis status reset needed
statusResetTime_ = -statusResetTime_;
setIntegerParam(pC_->motorStatusProblem_, bResult ? 0 : 1);
callParamCallbacks();
asValues.erase(asValues.begin(), asValues.begin() + iRemoveCount);
Expand Down
2 changes: 2 additions & 0 deletions phytronApp/src/phytronAxisMotor.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ class phytronAxis : public asynMotorAxis
int brakeReleased_; ///< state of brake
enum pollMethod iPollMethod_; ///< individual poll method for this axis
int homeState_; ///< state machine for work around homing to limit switches
float statusResetTime_; ///< error state flag for SEC command: 0=off, <0: configured but not needed, >0: need status reset; 0s<n<0.001s=no wait, 0.001s<n<10s wait time

friend class phytronController;
};
Expand Down Expand Up @@ -238,6 +239,7 @@ class phytronController : public asynMotorController
bool allow_exit_on_error_; ///< allow exit(1) on error
std::string sLastSUI_; ///< last response to SUI command (MCC only)
std::string sCtrlType_; ///< controller type
float statusResetTime_; ///< error state flag for SEC command: 0=off, <0: configured but not needed, >0: need status reset; 0s<n<0.001s=no wait, 0.001s<n<10s wait time

static void epicsInithookFunction(initHookState iState);

Expand Down

0 comments on commit 36ad045

Please sign in to comment.