4 Commits
1.2.2 ... 1.4.2

Author SHA1 Message Date
21a73717a5 Fixed handshake detection and reset bugs
Some checks failed
Test And Build / Lint (push) Failing after 4s
Test And Build / Build (push) Successful in 7s
2025-08-14 17:16:14 +02:00
2cbb4f9028 Forgot to add masterMacs.db to Makefile
Some checks failed
Test And Build / Lint (push) Failing after 4s
Test And Build / Build (push) Successful in 7s
2025-08-14 14:21:05 +02:00
23a911206a Removed node reset from doReset and moved it into dedicated function
Some checks failed
Test And Build / Lint (push) Failing after 4s
Test And Build / Build (push) Successful in 7s
A "normal" error reset should not trigger a node reset. However, this
option is still available via a dedicated PV xx:NodeReset and a
corresponding function in masterMacsAxis.
2025-08-12 15:51:12 +02:00
6553b468c8 Updated to sinqMotor 1.4.0 and hid all symbols
Some checks failed
Test And Build / Lint (push) Failing after 3s
Test And Build / Build (push) Successful in 7s
2025-08-12 09:44:15 +02:00
7 changed files with 111 additions and 26 deletions

View File

@@ -23,6 +23,7 @@ SOURCES += src/masterMacsController.cpp
# Store the record files
TEMPLATES += sinqMotor/db/asynRecord.db
TEMPLATES += sinqMotor/db/sinqMotor.db
TEMPLATES += db/masterMacs.db
# This file registers the motor-specific functions in the IOC shell.
DBDS += sinqMotor/src/sinqMotor.dbd

7
db/masterMacs.db Executable file
View File

@@ -0,0 +1,7 @@
# Call the nodeReset function of the corresponding masterMacsAxis.
# This record is coupled to the parameter library via nodeReset_ -> NODE_RESET.
record(longout, "$(INSTR)$(M):NodeReset") {
field(DTYP, "asynInt32")
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) NODE_RESET")
field(PINI, "NO")
}

View File

@@ -357,7 +357,10 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
if (timedOut) {
setAxisParamChecked(this, motorMessageText,
"Timed out while waiting for a handshake");
"Timed out while waiting for a handshake. "
"Please call the support.");
poll_status = asynError;
}
pC_->read(axisNo_, 86, response);
@@ -377,14 +380,10 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
pMasterMacsA_->waitForHandshake = false;
pMasterMacsA_->targetReachedUninitialized = false;
} else {
// Still waiting for the handshake - try again in the next busy
// poll. This is already part of the movement procedure.
*moving = true;
setAxisParamChecked(this, motorStatusMoving, *moving);
setAxisParamChecked(this, motorStatusDone, !(*moving));
return asynSuccess;
return poll_status;
}
}
@@ -403,6 +402,9 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
return rw_status;
}
// If we wait for a handshake, but the motor was moving in its last poll
// cycle and has reached its target, it is not moving. Otherwise it is
// considered moving, even if we're still waiting for the handshake.
if (pMasterMacsA_->targetReachedUninitialized) {
*moving = false;
} else {
@@ -679,7 +681,6 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
if (pl_status != asynSuccess) {
return pl_status;
}
return poll_status;
}
@@ -805,15 +806,26 @@ asynStatus masterMacsAxis::doReset() {
asynStatus status = asynSuccess;
// Reset the controller ("node reset")
status = pC_->write(axisNo_, 16, "");
// Reset any errors
status = pC_->write(axisNo_, 17, "");
if (status != asynSuccess) {
setAxisParamChecked(this, motorStatusProblem, true);
}
// Reset any errors in the controller. Since the node reset results in a
// Move out of the handshake wait loop, if we're currently inside it.
pMasterMacsA_->waitForHandshake = false;
// Disable the axis
return enable(false);
}
asynStatus masterMacsAxis::nodeReset() {
asynStatus status = asynSuccess;
// Reset the controller ("node reset"). Since the node reset results in a
// power cycle, we use the corresponding timeout.
status = pC_->write(axisNo_, 17, "", PowerCycleTimeout);
status = pC_->write(axisNo_, 16, "", PowerCycleTimeout);
if (status != asynSuccess) {
setAxisParamChecked(this, motorStatusProblem, true);
}

View File

@@ -4,9 +4,9 @@
#include "sinqAxis.h"
#include <memory>
struct masterMacsAxisImpl;
struct HIDDEN masterMacsAxisImpl;
class masterMacsAxis : public sinqAxis {
class HIDDEN masterMacsAxis : public sinqAxis {
public:
/**
* @brief Construct a new masterMacsAxis
@@ -75,12 +75,27 @@ class masterMacsAxis : public sinqAxis {
*/
asynStatus doReset();
/**
* @brief Performs a "node reset" on the axis as defined in the CANopen
* standard
*
* A "node reset" is a factory reset on the axis which completely deletes
* all configured information (e.g. limits or speed) from the axis. The
* MasterMACS controller then reapplies the initial configuration to this
* axis. It can therefore be seen as a "hard" version of the normal error
* reset performed by the `doReset` method.
*
* @return asynStatus
*/
asynStatus nodeReset();
/**
* @brief Readout of some values from the controller at IOC startup
*
* The following steps are performed:
* - Read out the motor status, motor position, velocity and acceleration
* from the MCU and store this information in the parameter library.
* - Read out the motor status, motor position, velocity and
* acceleration from the MCU and store this information in the parameter
* library.
* - Set the enable PV accordint to the initial status of the axis.
*
* @return asynStatus
@@ -96,8 +111,8 @@ class masterMacsAxis : public sinqAxis {
asynStatus enable(bool on);
/**
* @brief Read the encoder type (incremental or absolute) for this axis from
* the MCU and store the information in the PV ENCODER_TYPE.
* @brief Read the encoder type (incremental or absolute) for this axis
* from the MCU and store the information in the PV ENCODER_TYPE.
*
* @return asynStatus
*/
@@ -112,7 +127,8 @@ class masterMacsAxis : public sinqAxis {
bool needInit();
/**
* @brief Instruct the axis to run its init() function during the next poll
* @brief Instruct the axis to run its init() function during the next
* poll
*
* @param needInit
*/
@@ -124,8 +140,8 @@ class masterMacsAxis : public sinqAxis {
virtual masterMacsController *pController() override { return pC_; };
/**
* @brief Read the Master MACS status with the xR10 command and store the
* result in axisStatus_
* @brief Read the Master MACS status with the xR10 command and store
* the result in axisStatus_
*
*/
asynStatus readAxisStatus();
@@ -203,8 +219,8 @@ class masterMacsAxis : public sinqAxis {
bool powerEnabled();
/**
* @brief Read the Master MACS status with the xR10 command and store the
* result in axisStatus_
* @brief Read the Master MACS status with the xR10 command and store
* the result in axisStatus_
*
*/
asynStatus readAxisError();

View File

@@ -14,6 +14,9 @@
struct masterMacsControllerImpl {
double comTimeout;
// Indices of additional ParamLib entries
int nodeReset;
};
/**
@@ -68,6 +71,20 @@ masterMacsController::masterMacsController(const char *portName,
.comTimeout = comTimeout,
});
// =========================================================================
// Create additional parameter library entries
status =
createParam("NODE_RESET", asynParamInt32, &pMasterMacsC_->nodeReset);
if (status != asynSuccess) {
asynPrint(this->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\" => %s, line %d\nFATAL ERROR (creating a "
"parameter failed with %s).\nTerminating IOC",
portName, __PRETTY_FUNCTION__, __LINE__,
stringifyAsynStatus(status));
exit(-1);
}
// =========================================================================
/*
@@ -120,6 +137,22 @@ masterMacsAxis *masterMacsController::getMasterMacsAxis(int axisNo) {
return dynamic_cast<masterMacsAxis *>(asynAxis);
}
asynStatus masterMacsController::writeInt32(asynUser *pasynUser,
epicsInt32 value) {
int function = pasynUser->reason;
// =====================================================================
masterMacsAxis *axis = getMasterMacsAxis(pasynUser);
// Handle custom PVs
if (function == nodeReset()) {
return axis->nodeReset();
} else {
return sinqController::writeInt32(pasynUser, value);
}
}
asynStatus masterMacsController::read(int axisNo, int tcpCmd, char *response,
double comTimeout) {
return writeRead(axisNo, tcpCmd, NULL, response);
@@ -459,6 +492,8 @@ asynStatus masterMacsController::readInt32(asynUser *pasynUser,
double masterMacsController::comTimeout() { return pMasterMacsC_->comTimeout; }
int masterMacsController::nodeReset() { return pMasterMacsC_->nodeReset; }
/***************************************************************************/
/** The following functions are C-wrappers, and can be called directly from
* iocsh */

View File

@@ -15,11 +15,11 @@
// Forward declaration of the controller class to resolve the cyclic dependency
// between the controller and the axis .h-file. See
// https://en.cppreference.com/w/cpp/language/class.
class masterMacsAxis;
class HIDDEN masterMacsAxis;
struct masterMacsControllerImpl;
struct HIDDEN masterMacsControllerImpl;
class masterMacsController : public sinqController {
class HIDDEN masterMacsController : public sinqController {
public:
/**
@@ -65,6 +65,17 @@ class masterMacsController : public sinqController {
*/
masterMacsAxis *getMasterMacsAxis(int axisNo);
/**
* @brief Overloaded function of sinqController
*
* The function is overloaded to allow resetting the node
*
* @param pasynUser Specify the axis via the asynUser
* @param value New value
* @return asynStatus
*/
virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
/**
* @brief Send a command to the hardware (S mode)
*
@@ -141,6 +152,9 @@ class masterMacsController : public sinqController {
*/
double comTimeout();
// Accessors for additional PVs
int nodeReset();
private:
std::unique_ptr<masterMacsControllerImpl> pMasterMacsC_;
};