Compare commits

...

7 Commits

Author SHA1 Message Date
295cd34993 Factored out error handling in a dedicated function
This makes it possible to reuse the error handling of the base axis in
derived axis types (e.g. seleneGuide driver).
2025-04-09 15:12:49 +02:00
b62a5fd699 Removed readInt32 method, since it is not needed. 2025-04-04 13:30:52 +02:00
a990da4245 Added functions to get/set motorPosition.
Changed to functions motorPosition and setMotorPosition in order to
retrieve / set motor positions from / to the paramLib.
2025-03-31 10:53:39 +02:00
83a74ce8d0 Added new sinqMotor version as minimum requirement 2025-03-19 15:04:16 +01:00
445dd44c19 Removed a doubling of functionality
ipPortUser / lowLevelPortUser are already defined in the sinqMotor
library
2025-03-10 17:02:28 +01:00
d471041c59 Removed friend class declaration and replaced access to private
properties with accessors
2025-03-10 16:55:10 +01:00
967613447b Added error reset function. 2025-03-10 14:31:15 +01:00
6 changed files with 386 additions and 334 deletions

View File

@ -14,7 +14,7 @@ REQUIRED+=sinqMotor
motorBase_VERSION=7.2.2
# Specify the version of sinqMotor we want to build against
sinqMotor_VERSION=0.8.0
sinqMotor_VERSION=0.11.0
# These headers allow to depend on this library for derived drivers.
HEADERS += src/turboPmacAxis.h

View File

@ -1,5 +1,7 @@
# turboPmac
## <span style="color:red">Please read the documentation of sinqMotor first: https://git.psi.ch/sinq-epics-modules/sinqmotor</span>
## Overview
This is a driver for the Turbo PMAC motion controller with the SINQ communication protocol. It is based on the sinqMotor shared library (https://git.psi.ch/sinq-epics-modules/sinqmotor). The header files contain detailed documentation for all public functions. The headers themselves are exported when building the library to allow other drivers to depend on this one.
@ -21,11 +23,11 @@ turboPmac exports the following IOC shell functions:
- `turboPmacController`: Create a new controller object.
- `turboPmacAxis`: Create a new axis object.
The full mcu.cmd file looks like this:
The full turboPmacX.cmd file looks like this:
```
# Define the name of the controller and the corresponding port
epicsEnvSet("NAME","mcu")
epicsEnvSet("NAME","turboPmacX")
epicsEnvSet("ASYN_PORT","p$(NAME)")
# Create the TCP/IP socket used to talk with the controller. The socket can be adressed from within the IOC shell via the port name
@ -47,8 +49,8 @@ turboPmacAxis("$(NAME)",5);
# Set the number of subsequent timeouts
setMaxSubsequentTimeouts("$(NAME)", 20);
# Configure the timeout frequency watchdog:
setThresholdComTimeout("$(NAME)", 100, 1);
# Configure the timeout frequency watchdog: A maximum of 10 timeouts are allowed in 300 seconds before an alarm message is sent.
setThresholdComTimeout("$(NAME)", 300, 10);
# Parametrize the EPICS record database with the substitution file named after the MCU.
epicsEnvSet("SINQDBPATH","$(sinqMotor_DB)/sinqMotor.db")

File diff suppressed because it is too large Load Diff

View File

@ -81,6 +81,14 @@ class turboPmacAxis : public sinqAxis {
*/
asynStatus init();
/**
* @brief Implementation of the `doReset` function from sinqAxis.
*
* @param on
* @return asynStatus
*/
asynStatus doReset();
/**
* @brief Enable / disable the axis.
*
@ -104,6 +112,16 @@ class turboPmacAxis : public sinqAxis {
*/
asynStatus rereadEncoder();
/**
* @brief Interpret the error code and populate the user message accordingly
*
* @param error
* @param userMessage
* @param sizeUserMessage
* @return asynStatus
*/
asynStatus handleError(int error, char *userMessage, int sizeUserMessage);
protected:
turboPmacController *pC_;
@ -112,9 +130,6 @@ class turboPmacAxis : public sinqAxis {
// The axis status is used when enabling / disabling the motor
int axisStatus_;
private:
friend class turboPmacController;
};
#endif

View File

@ -49,27 +49,12 @@ turboPmacController::turboPmacController(const char *portName,
asynStatus status = asynSuccess;
// Initialization of all member variables
lowLevelPortUser_ = nullptr;
comTimeout_ = comTimeout;
// Maximum allowed number of subsequent timeouts before the user is
// informed.
maxSubsequentTimeouts_ = 10;
// =========================================================================;
/*
We try to connect to the port via the port name provided by the constructor.
If this fails, the function is terminated via exit
*/
pasynOctetSyncIO->connect(ipPortConfigName, 0, &lowLevelPortUser_, NULL);
if (status != asynSuccess || lowLevelPortUser_ == nullptr) {
errlogPrintf("Controller \"%s\" => %s, line %d\nFATAL ERROR "
"(cannot connect to MCU controller).\nTerminating IOC",
portName, __PRETTY_FUNCTION__, __LINE__);
exit(-1);
}
// =========================================================================
// Create additional parameter library entries
@ -103,15 +88,15 @@ turboPmacController::turboPmacController(const char *portName,
const char *message_from_device =
"\006"; // Hex-code for ACK (acknowledge) -> Each message from the MCU
// is terminated by this value
status = pasynOctetSyncIO->setInputEos(
lowLevelPortUser_, message_from_device, strlen(message_from_device));
status = pasynOctetSyncIO->setInputEos(ipPortUser_, message_from_device,
strlen(message_from_device));
if (status != asynSuccess) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"Controller \"%s\" => %s, line %d\nFATAL ERROR "
"(setting input EOS failed with %s).\nTerminating IOC",
portName, __PRETTY_FUNCTION__, __LINE__,
stringifyAsynStatus(status));
pasynOctetSyncIO->disconnect(lowLevelPortUser_);
pasynOctetSyncIO->disconnect(ipPortUser_);
exit(-1);
}
@ -123,7 +108,7 @@ turboPmacController::turboPmacController(const char *portName,
"with %s).\nTerminating IOC",
portName, __PRETTY_FUNCTION__, __LINE__,
stringifyAsynStatus(status));
pasynOctetSyncIO->disconnect(lowLevelPortUser_);
pasynOctetSyncIO->disconnect(ipPortUser_);
exit(-1);
}
}
@ -254,8 +239,8 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
trying to reconnect. If the problem persists, ask them to call the support
*/
status = pasynOctetSyncIO->write(lowLevelPortUser_, fullCommand,
fullComandLength, comTimeout_, &nbytesOut);
status = pasynOctetSyncIO->write(ipPortUser_, fullCommand, fullComandLength,
comTimeout_, &nbytesOut);
msgPrintControlKey writeKey =
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
@ -279,7 +264,7 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
checkMaxSubsequentTimeouts(timeoutCounter, axis);
timeoutCounter += 1;
status = pasynOctetSyncIO->write(lowLevelPortUser_, fullCommand,
status = pasynOctetSyncIO->write(ipPortUser_, fullCommand,
fullComandLength, comTimeout_,
&nbytesOut);
if (status != asynTimeout) {
@ -300,12 +285,12 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
stringifyAsynStatus(status), msgPrintControl_.getSuffix());
}
} else {
msgPrintControl_.resetCount(writeKey);
msgPrintControl_.resetCount(writeKey, pasynUserSelf);
}
// Read the response from the MCU buffer
status = pasynOctetSyncIO->read(lowLevelPortUser_, response, MAXBUF_,
comTimeout_, &nbytesIn, &eomReason);
status = pasynOctetSyncIO->read(ipPortUser_, response, MAXBUF_, comTimeout_,
&nbytesIn, &eomReason);
msgPrintControlKey readKey =
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
@ -330,9 +315,8 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
checkMaxSubsequentTimeouts(timeoutCounter, axis);
timeoutCounter += 1;
status =
pasynOctetSyncIO->read(lowLevelPortUser_, response, MAXBUF_,
comTimeout_, &nbytesIn, &eomReason);
status = pasynOctetSyncIO->read(ipPortUser_, response, MAXBUF_,
comTimeout_, &nbytesIn, &eomReason);
if (status != asynTimeout) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"Controller \"%s\", axis %d => %s, line "
@ -351,7 +335,7 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
stringifyAsynStatus(status), msgPrintControl_.getSuffix());
}
} else {
msgPrintControl_.resetCount(readKey);
msgPrintControl_.resetCount(readKey, pasynUserSelf);
}
if (timeoutStatus == asynError) {
@ -377,7 +361,7 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
eomReason, msgPrintControl_.getSuffix());
}
} else {
msgPrintControl_.resetCount(terminateKey);
msgPrintControl_.resetCount(terminateKey, pasynUserSelf);
}
/*
@ -412,7 +396,7 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
modResponse, command);
status = asynError;
} else {
msgPrintControl_.resetCount(numResponsesKey);
msgPrintControl_.resetCount(numResponsesKey, pasynUserSelf);
}
// Create custom error messages for different failure modes, if no error
@ -500,23 +484,14 @@ asynStatus turboPmacController::writeInt32(asynUser *pasynUser,
}
}
asynStatus turboPmacController::readInt32(asynUser *pasynUser,
epicsInt32 *value) {
// PMACs can be disabled
if (pasynUser->reason == motorCanDisable_) {
*value = 1;
return asynSuccess;
} else {
return sinqController::readInt32(pasynUser, value);
}
}
asynStatus turboPmacController::errMsgCouldNotParseResponse(
const char *command, const char *response, int axisNo,
const char *functionName, int lineNumber) {
asynStatus turboPmacController::couldNotParseResponse(const char *command,
const char *response,
int axisNo,
const char *functionName,
int lineNumber) {
char modifiedResponse[MAXBUF_] = {0};
adjustResponseForPrint(modifiedResponse, response, MAXBUF_);
return sinqController::errMsgCouldNotParseResponse(
return sinqController::couldNotParseResponse(
command, modifiedResponse, axisNo, functionName, lineNumber);
}

View File

@ -51,17 +51,6 @@ class turboPmacController : public sinqController {
*/
turboPmacAxis *getTurboPmacAxis(int axisNo);
/**
* @brief Overloaded function of sinqController
*
* The function is overloaded in order to read motorCanDisable_.
*
* @param pasynUser
* @param value
* @return asynStatus
*/
virtual asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value);
/**
* @brief Overloaded function of sinqController
*
@ -73,9 +62,6 @@ class turboPmacController : public sinqController {
*/
virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
protected:
asynUser *lowLevelPortUser_;
/**
* @brief Send a command to the hardware and receive a response
*
@ -96,13 +82,13 @@ class turboPmacController : public sinqController {
int numExpectedResponses);
/**
* @brief Specialized version of sinqController::errMsgCouldNotParseResponse
* @brief Specialized version of sinqController::couldNotParseResponse
* for turboPmac
*
* This is an overloaded version of
* sinqController::errMsgCouldNotParseResponse which calls
* sinqController::couldNotParseResponse which calls
* adjustResponseForLogging on response before handing it over to
* sinqController::errMsgCouldNotParseResponse.
* sinqController::couldNotParseResponse.
*
* @param command Command which led to the unparseable message
* @param response Response which wasn't parseable
@ -113,17 +99,20 @@ class turboPmacController : public sinqController {
called. It is recommended to use a macro, e.g. __LINE__.
* @return asynStatus Returns asynError.
*/
asynStatus errMsgCouldNotParseResponse(const char *command,
const char *response, int axisNo_,
const char *functionName,
int lineNumber);
asynStatus couldNotParseResponse(const char *command, const char *response,
int axisNo_, const char *functionName,
int lineNumber);
// Accessors for additional PVs
int rereadEncoderPosition() { return rereadEncoderPosition_; }
int readConfig() { return readConfig_; }
protected:
// Set the maximum buffer size. This is an empirical value which must be
// large enough to avoid overflows for all commands to the device /
// responses from it.
static const uint32_t MAXBUF_ = 200;
protected:
/*
Timeout for the communication process in seconds
*/
@ -136,8 +125,6 @@ class turboPmacController : public sinqController {
int rereadEncoderPosition_;
int readConfig_;
#define LAST_turboPmac_PARAM readConfig_
friend class turboPmacAxis;
};
#define NUM_turboPmac_DRIVER_PARAMS \
(&LAST_turboPmac_PARAM - &FIRST_turboPmac_PARAM + 1)