Compare commits
27 Commits
fix_timing
...
1.5.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 7a96ed2b71 | |||
| cf43a1c57a | |||
| 85317e24cd | |||
| 1ee483f8e9 | |||
| 002b5d2616 | |||
| ce80426790 | |||
| 72f3965881 | |||
| d41e7bf054 | |||
| 30bfa1cac5 | |||
| 235816fd20 | |||
| bd0966d2c9 | |||
| 9d5d90574a | |||
| 6effc5e906 | |||
| bc5de11b16 | |||
| aa488627f9 | |||
| ccaee6c5d1 | |||
| 323b030581 | |||
| b206012df2 | |||
| 21ec7e8467 | |||
| 398bc8241a | |||
| 8ca684604d | |||
| 72fe2b3681 | |||
| 5911e62029 | |||
| 682024091f | |||
| 335de72bc5 | |||
| 8e5055d6b8 | |||
| 1cab6e14ff |
24
.gitea/workflows/action.yaml
Normal file
24
.gitea/workflows/action.yaml
Normal file
@@ -0,0 +1,24 @@
|
||||
name: Test And Build
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
Lint:
|
||||
runs-on: linepics
|
||||
steps:
|
||||
- name: checkout repo
|
||||
uses: actions/checkout@v4
|
||||
- name: cppcheck
|
||||
run: cppcheck --std=c++17 --addon=cert --addon=misc --error-exitcode=1 src/*.cpp
|
||||
- name: formatting
|
||||
run: clang-format --style=file --Werror --dry-run src/*.cpp
|
||||
Build:
|
||||
runs-on: linepics
|
||||
steps:
|
||||
- name: checkout repo
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: 'true'
|
||||
- run: |
|
||||
sed -i 's/ARCH_FILTER=.*/ARCH_FILTER=linux%/' Makefile
|
||||
echo -e "\nIGNORE_SUBMODULES += sinqmotor" >> Makefile
|
||||
make install
|
||||
@@ -1,58 +0,0 @@
|
||||
default:
|
||||
image: docker.psi.ch:5000/sinqdev/sinqepics:latest
|
||||
|
||||
stages:
|
||||
- lint
|
||||
- build
|
||||
- test
|
||||
|
||||
cppcheck:
|
||||
stage: lint
|
||||
script:
|
||||
- cppcheck --std=c++17 --addon=cert --addon=misc --error-exitcode=1 src/*.cpp
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
tags:
|
||||
- sinq
|
||||
|
||||
formatting:
|
||||
stage: lint
|
||||
script:
|
||||
- clang-format --style=file --Werror --dry-run src/*.cpp
|
||||
artifacts:
|
||||
expire_in: 1 week
|
||||
tags:
|
||||
- sinq
|
||||
|
||||
# clangtidy:
|
||||
# stage: lint
|
||||
# script:
|
||||
# - curl https://docker.psi.ch:5000/v2/_catalog
|
||||
# # - dnf update -y
|
||||
# # - dnf install -y clang-tools-extra
|
||||
# # - clang-tidy sinqEPICSApp/src/*.cpp sinqEPICSApp/src/*.c sinqEPICSApp/src/*.h -checks=cppcoreguidelines-*,cert-*
|
||||
# # tags:
|
||||
# # - sinq
|
||||
|
||||
build_module:
|
||||
stage: build
|
||||
script:
|
||||
- export SINQMOTOR_VERSION="$(grep 'sinqMotor_VERSION=' Makefile | cut -d= -f2)"
|
||||
- git clone --depth 1 --branch "${SINQMOTOR_VERSION}" https://gitlab-ci-token:${CI_JOB_TOKEN}@git.psi.ch/sinq-epics-modules/sinqmotor.git
|
||||
- pushd sinqmotor
|
||||
- sed -i 's/ARCH_FILTER=.*/ARCH_FILTER=linux%/' Makefile
|
||||
- echo "LIBVERSION=${SINQMOTOR_VERSION}" >> Makefile
|
||||
- make install
|
||||
- popd
|
||||
- sed -i 's/ARCH_FILTER=.*/ARCH_FILTER=linux%/' Makefile
|
||||
- echo "LIBVERSION=${CI_COMMIT_TAG:-0.0.1}" >> Makefile
|
||||
- make install
|
||||
- cp -rT "/ioc/modules/turboPmac/$(ls -U /ioc/modules/turboPmac/ | head -1)" "./turboPmac-${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}"
|
||||
artifacts:
|
||||
name: "turboPmac-${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}"
|
||||
paths:
|
||||
- "turboPmac-${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}/*"
|
||||
expire_in: 1 week
|
||||
when: always
|
||||
tags:
|
||||
- sinq
|
||||
2
Makefile
2
Makefile
@@ -34,4 +34,4 @@ TEMPLATES += db/turboPmac.db
|
||||
DBDS += sinqMotor/src/sinqMotor.dbd
|
||||
DBDS += src/turboPmac.dbd
|
||||
|
||||
USR_CFLAGS += -Wall -Wextra -Weffc++ -Wunused-result -Werror # -Wpedantic // Does not work because EPICS macros trigger warnings
|
||||
USR_CFLAGS += -Wall -Wextra -Wunused-result -Werror -fvisibility=hidden # -Wpedantic // Does not work because EPICS macros trigger warnings
|
||||
Submodule sinqMotor updated: 55a9fe6f3e...cff64f5ecf
@@ -230,8 +230,7 @@ static asynStatus sendPmacGetBuffer(pmacPvt *pPmacPvt, asynUser *pasynUser,
|
||||
|
||||
// =============================================================================
|
||||
|
||||
epicsShareFunc int pmacAsynIPPortConfigure(const char *portName,
|
||||
const char *hostInfo) {
|
||||
int pmacAsynIPPortConfigure(const char *portName, const char *hostInfo) {
|
||||
asynStatus status = asynSuccess;
|
||||
asynInterface *int32LowerLevelInterface = NULL;
|
||||
asynInterface *octetLowerLevelInterface = NULL;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define asynInterposePmac_H
|
||||
|
||||
#include <epicsExport.h>
|
||||
#include <macros.h>
|
||||
#include <shareLib.h>
|
||||
|
||||
/*
|
||||
@@ -25,8 +26,7 @@ extern "C" {
|
||||
* 172.23.243.156:1025)
|
||||
* @return status
|
||||
*/
|
||||
epicsShareFunc int pmacAsynIPPortConfigure(const char *portName,
|
||||
const char *hostInfo);
|
||||
int HIDDEN pmacAsynIPPortConfigure(const char *portName, const char *hostInfo);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -15,6 +15,14 @@
|
||||
|
||||
struct turboPmacAxisImpl {
|
||||
bool waitForHandshake;
|
||||
/*
|
||||
This flag is set to true, if the controller is currently enabling /
|
||||
disabling the motor and false otherwise. This flag is used in the doPoll
|
||||
method to check if the enableRBV PV should be set or not in order to prevent
|
||||
a premature change of state (controller reports that the motor is already
|
||||
enabled / disabled while it is not ready yet to receive new commands).
|
||||
*/
|
||||
bool enableDisable;
|
||||
time_t timeAtHandshake;
|
||||
// The axis status is used when enabling / disabling the motor
|
||||
int axisStatus;
|
||||
@@ -62,11 +70,13 @@ turboPmacAxis::turboPmacAxis(turboPmacController *pC, int axisNo,
|
||||
axes.push_back(this);
|
||||
}
|
||||
|
||||
pTurboPmacA_ = std::make_unique<turboPmacAxisImpl>(
|
||||
(turboPmacAxisImpl){.waitForHandshake = false,
|
||||
.timeAtHandshake = 0,
|
||||
.axisStatus = 0,
|
||||
.needInit = false});
|
||||
pTurboPmacA_ = std::make_unique<turboPmacAxisImpl>((turboPmacAxisImpl){
|
||||
.waitForHandshake = false,
|
||||
.enableDisable = false,
|
||||
.timeAtHandshake = 0,
|
||||
.axisStatus = 0,
|
||||
.needInit = false,
|
||||
});
|
||||
|
||||
// Provide initial values for some parameter library entries
|
||||
status = pC_->setIntegerParam(axisNo_, pC_->rereadEncoderPosition(), 0);
|
||||
@@ -123,8 +133,16 @@ asynStatus turboPmacAxis::init() {
|
||||
double motorVelocity = 0.0;
|
||||
double motorVmax = 0.0;
|
||||
double motorAccel = 0.0;
|
||||
int acoDelay = 0.0; // Offset time for the movement watchdog caused by
|
||||
// the air cushions in milliseconds.
|
||||
|
||||
// Conversion factor between engineering units (EU) and encoder counts
|
||||
double counts_to_eu = 0.0;
|
||||
|
||||
// Deadband in counts. Can be a fraction of a count, hence double.
|
||||
double deadband_counts = 0.0;
|
||||
|
||||
// Offset time for the movement watchdog caused by the air cushions in
|
||||
// milliseconds.
|
||||
int acoDelay = 0.0;
|
||||
int axStatus = 0;
|
||||
|
||||
// The parameter library takes some time to be initialized. Therefore we
|
||||
@@ -154,12 +172,16 @@ asynStatus turboPmacAxis::init() {
|
||||
|
||||
/*
|
||||
Read out the axis status, the current position, current and maximum speed,
|
||||
acceleration and the air cushion delay.
|
||||
acceleration, the air cushion delay, the scaling factor between counts and
|
||||
engineering units ([Qxx00] = engineering units / counts) and the deadband
|
||||
Ixx65.
|
||||
*/
|
||||
snprintf(command, sizeof(command),
|
||||
"P%2.2d00 Q%2.2d10 Q%2.2d03 Q%2.2d04 Q%2.2d06 P%2.2d22", axisNo_,
|
||||
axisNo_, axisNo_, axisNo_, axisNo_, axisNo_);
|
||||
status = pC_->writeRead(axisNo_, command, response, 6);
|
||||
"P%2.2d00 Q%2.2d10 Q%2.2d03 Q%2.2d04 Q%2.2d06 P%2.2d22 Q%2.2d00 "
|
||||
"I%2.2d65",
|
||||
axisNo_, axisNo_, axisNo_, axisNo_, axisNo_, axisNo_, axisNo_,
|
||||
axisNo_);
|
||||
status = pC_->writeRead(axisNo_, command, response, 8);
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(
|
||||
pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
@@ -171,8 +193,9 @@ asynStatus turboPmacAxis::init() {
|
||||
pC_->portName, axisNo(), __PRETTY_FUNCTION__, __LINE__);
|
||||
pTurboPmacA_->needInit = true;
|
||||
}
|
||||
nvals = sscanf(response, "%d %lf %lf %lf %lf %d", &axStatus, &motorPos,
|
||||
&motorVmax, &motorVelocity, &motorAccel, &acoDelay);
|
||||
nvals = sscanf(response, "%d %lf %lf %lf %lf %d %lf %lf", &axStatus,
|
||||
&motorPos, &motorVmax, &motorVelocity, &motorAccel,
|
||||
&acoDelay, &counts_to_eu, &deadband_counts);
|
||||
|
||||
// The acoDelay is given in milliseconds -> Convert to seconds, rounded up
|
||||
setOffsetMovTimeout(std::ceil(acoDelay / 1000.0));
|
||||
@@ -182,7 +205,7 @@ asynStatus turboPmacAxis::init() {
|
||||
// here to mm/s^2.
|
||||
motorAccel = motorAccel * 1000;
|
||||
|
||||
if (nvals != 6) {
|
||||
if (nvals != 8) {
|
||||
return pC_->couldNotParseResponse(command, response, axisNo_,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
@@ -206,6 +229,26 @@ asynStatus turboPmacAxis::init() {
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
Check if the new target position is within the range current position +/-
|
||||
deadband. If that is the case, no movement command should be sent. This
|
||||
functionality is implemented within the motor record itself, we just need to
|
||||
populate the field SPDP (see record PushSPDB2Field in db/turboPmac.db)
|
||||
|
||||
First, the deadband is read out (Ixx65, see Turbo PMAC User Manual, p.
|
||||
160). This value then needs to be converted into counts (by dividing it by
|
||||
16). After words, the deadband in counts then need to be converted into
|
||||
engineering units. For this, the scaling factor Qxx10 needs to be applied
|
||||
(see SINQ_2G_MCU_SW_manual_rev7, p. 17):
|
||||
[Qxx10] = engineering units (eu) / counts
|
||||
deadband_eu = Qxx10 * Ixx65 / 16
|
||||
|
||||
The values of Qxx10 and Ixx65 are read out during initialization and are
|
||||
assumed to not change during operation.
|
||||
*/
|
||||
setAxisParamChecked(this, motorPositionDeadband,
|
||||
counts_to_eu * deadband_counts / 16.0);
|
||||
|
||||
// Update the parameter library immediately
|
||||
status = callParamCallbacks();
|
||||
if (status != asynSuccess) {
|
||||
@@ -253,9 +296,6 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
|
||||
double lowLimit = 0.0;
|
||||
double limitsOffset = 0.0;
|
||||
|
||||
// Was the axis idle during the previous poll?
|
||||
int previousStatusDone = 1;
|
||||
|
||||
// =========================================================================
|
||||
|
||||
if (pTurboPmacA_->needInit) {
|
||||
@@ -332,8 +372,6 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
|
||||
return status;
|
||||
}
|
||||
|
||||
getAxisParamChecked(this, motorStatusDone, &previousStatusDone);
|
||||
|
||||
// Query the axis status
|
||||
snprintf(command, sizeof(command),
|
||||
"P%2.2d00 Q%2.2d10 P%2.2d01 Q%2.2d13 Q%2.2d14", axisNo_, axisNo_,
|
||||
@@ -369,9 +407,12 @@ asynStatus turboPmacAxis::doPoll(bool *moving) {
|
||||
// Store the axis status
|
||||
pTurboPmacA_->axisStatus = axStatus;
|
||||
|
||||
// Update the enablement PV
|
||||
setAxisParamChecked(this, motorEnableRBV,
|
||||
(axStatus != -3 && axStatus != -5));
|
||||
// Update the enablement PV, if we are not in the middle of a enabling /
|
||||
// disabling procedure.
|
||||
if (!(pTurboPmacA_->enableDisable)) {
|
||||
setAxisParamChecked(this, motorEnableRBV,
|
||||
(axStatus != -3 && axStatus != -5));
|
||||
}
|
||||
|
||||
// Create the unique callsite identifier manually so it can be used later in
|
||||
// the shouldBePrinted calls.
|
||||
@@ -546,11 +587,6 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage,
|
||||
int sizeUserMessage) {
|
||||
asynStatus status = asynError;
|
||||
|
||||
// Create the unique callsite identifier manually so it can be used later in
|
||||
// the shouldBePrinted calls.
|
||||
msgPrintControlKey keyError = msgPrintControlKey(
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
||||
|
||||
switch (error) {
|
||||
case 0:
|
||||
status = asynSuccess;
|
||||
@@ -559,8 +595,9 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage,
|
||||
case 1:
|
||||
// EPICS should already prevent this issue in the first place,
|
||||
// since it contains the user limits
|
||||
if (pC_->getMsgPrintControl().shouldBePrinted(keyError, true,
|
||||
pC_->pasynUser())) {
|
||||
if (pC_->getMsgPrintControl().shouldBePrinted(
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, true,
|
||||
pC_->pasynUser())) {
|
||||
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nTarget "
|
||||
"position would exceed user limits.%s\n",
|
||||
@@ -572,8 +609,9 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage,
|
||||
break;
|
||||
case 5:
|
||||
// Command not possible
|
||||
if (pC_->getMsgPrintControl().shouldBePrinted(keyError, true,
|
||||
pC_->pasynUser())) {
|
||||
if (pC_->getMsgPrintControl().shouldBePrinted(
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, true,
|
||||
pC_->pasynUser())) {
|
||||
asynPrint(
|
||||
pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nAxis is "
|
||||
@@ -587,8 +625,9 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage,
|
||||
"moving. Please call the support.");
|
||||
break;
|
||||
case 8:
|
||||
if (pC_->getMsgPrintControl().shouldBePrinted(keyError, true,
|
||||
pC_->pasynUser())) {
|
||||
if (pC_->getMsgPrintControl().shouldBePrinted(
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, true,
|
||||
pC_->pasynUser())) {
|
||||
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nAir cushion "
|
||||
"feedback stopped during movement (P%2.2d01 = %d).%s\n",
|
||||
@@ -602,8 +641,9 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage,
|
||||
setAxisParamChecked(this, motorMessageText, userMessage);
|
||||
break;
|
||||
case 9:
|
||||
if (pC_->getMsgPrintControl().shouldBePrinted(keyError, true,
|
||||
pC_->pasynUser())) {
|
||||
if (pC_->getMsgPrintControl().shouldBePrinted(
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, true,
|
||||
pC_->pasynUser())) {
|
||||
asynPrint(
|
||||
pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nNo air cushion "
|
||||
@@ -626,8 +666,9 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage,
|
||||
which is not properly homed or if a bug occured.
|
||||
*/
|
||||
|
||||
if (pC_->getMsgPrintControl().shouldBePrinted(keyError, true,
|
||||
pC_->pasynUser())) {
|
||||
if (pC_->getMsgPrintControl().shouldBePrinted(
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, true,
|
||||
pC_->pasynUser())) {
|
||||
asynPrint(
|
||||
pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nAxis hit the "
|
||||
@@ -646,8 +687,9 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage,
|
||||
case 11:
|
||||
// Following error
|
||||
|
||||
if (pC_->getMsgPrintControl().shouldBePrinted(keyError, true,
|
||||
pC_->pasynUser())) {
|
||||
if (pC_->getMsgPrintControl().shouldBePrinted(
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, true,
|
||||
pC_->pasynUser())) {
|
||||
asynPrint(
|
||||
pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nMaximum allowed "
|
||||
@@ -664,8 +706,9 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage,
|
||||
break;
|
||||
|
||||
case 12:
|
||||
if (pC_->getMsgPrintControl().shouldBePrinted(keyError, true,
|
||||
pC_->pasynUser())) {
|
||||
if (pC_->getMsgPrintControl().shouldBePrinted(
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, true,
|
||||
pC_->pasynUser())) {
|
||||
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nSecurity "
|
||||
"input is triggered (P%2.2d01 = %d).%s\n",
|
||||
@@ -683,8 +726,9 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage,
|
||||
case 13:
|
||||
// Driver hardware error triggered
|
||||
|
||||
if (pC_->getMsgPrintControl().shouldBePrinted(keyError, true,
|
||||
pC_->pasynUser())) {
|
||||
if (pC_->getMsgPrintControl().shouldBePrinted(
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, true,
|
||||
pC_->pasynUser())) {
|
||||
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nDriver "
|
||||
"hardware error triggered.%s\n",
|
||||
@@ -700,8 +744,9 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage,
|
||||
case 14:
|
||||
// EPICS should already prevent this issue in the first place,
|
||||
// since it contains the user limits
|
||||
if (pC_->getMsgPrintControl().shouldBePrinted(keyError, true,
|
||||
pC_->pasynUser())) {
|
||||
if (pC_->getMsgPrintControl().shouldBePrinted(
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, true,
|
||||
pC_->pasynUser())) {
|
||||
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nMove "
|
||||
"command exceeds hardware limits (P%2.2d01 = %d).%s\n",
|
||||
@@ -716,8 +761,9 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage,
|
||||
break;
|
||||
default:
|
||||
|
||||
if (pC_->getMsgPrintControl().shouldBePrinted(keyError, true,
|
||||
pC_->pasynUser())) {
|
||||
if (pC_->getMsgPrintControl().shouldBePrinted(
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, true,
|
||||
pC_->pasynUser())) {
|
||||
asynPrint(
|
||||
pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nUnknown error "
|
||||
@@ -728,10 +774,6 @@ asynStatus turboPmacAxis::handleError(int error, char *userMessage,
|
||||
setAxisParamChecked(this, motorMessageText, userMessage);
|
||||
break;
|
||||
}
|
||||
|
||||
if (status == asynSuccess) {
|
||||
pC_->getMsgPrintControl().resetCount(keyError, pC_->pasynUser());
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -744,7 +786,7 @@ asynStatus turboPmacAxis::doMove(double position, int relative,
|
||||
|
||||
char command[pC_->MAXBUF_] = {0};
|
||||
char response[pC_->MAXBUF_] = {0};
|
||||
double motorCoordinatesPosition = 0.0;
|
||||
double motorTargetPosition = 0.0;
|
||||
double motorRecResolution = 0.0;
|
||||
double motorVelocity = 0.0;
|
||||
int enabled = 0;
|
||||
@@ -765,13 +807,14 @@ asynStatus turboPmacAxis::doMove(double position, int relative,
|
||||
}
|
||||
|
||||
// Convert from EPICS to user / motor units
|
||||
motorCoordinatesPosition = position * motorRecResolution;
|
||||
motorTargetPosition = position * motorRecResolution;
|
||||
motorVelocity = maxVelocity * motorRecResolution;
|
||||
|
||||
asynPrint(pC_->pasynUser(), ASYN_TRACE_FLOW,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nStart of axis to "
|
||||
"position %lf.\n",
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, position);
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||
motorTargetPosition);
|
||||
|
||||
// Check if the speed is allowed to be changed
|
||||
getAxisParamChecked(this, motorCanSetSpeed, &motorCanSetSpeed);
|
||||
@@ -796,11 +839,11 @@ asynStatus turboPmacAxis::doMove(double position, int relative,
|
||||
if (relative) {
|
||||
snprintf(&command[writeOffset], sizeof(command) - writeOffset,
|
||||
"P%2.2d23=0 Q%2.2d02=%lf M%2.2d=2", axisNo_, axisNo_,
|
||||
motorCoordinatesPosition, axisNo_);
|
||||
motorTargetPosition, axisNo_);
|
||||
} else {
|
||||
snprintf(&command[writeOffset], sizeof(command) - writeOffset,
|
||||
"P%2.2d23=0 Q%2.2d01=%lf M%2.2d=1", axisNo_, axisNo_,
|
||||
motorCoordinatesPosition, axisNo_);
|
||||
motorTargetPosition, axisNo_);
|
||||
}
|
||||
|
||||
// We don't expect an answer
|
||||
@@ -812,7 +855,7 @@ asynStatus turboPmacAxis::doMove(double position, int relative,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nStarting movement to "
|
||||
"target position %lf failed.\n",
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||
motorCoordinatesPosition);
|
||||
motorTargetPosition);
|
||||
setAxisParamChecked(this, motorStatusProblem, true);
|
||||
return status;
|
||||
}
|
||||
@@ -833,7 +876,6 @@ asynStatus turboPmacAxis::doMove(double position, int relative,
|
||||
|
||||
asynStatus turboPmacAxis::stop(double acceleration) {
|
||||
|
||||
// Status of read-write-operations of ASCII commands to the controller
|
||||
asynStatus status = asynSuccess;
|
||||
|
||||
char command[pC_->MAXBUF_] = {0};
|
||||
@@ -857,6 +899,18 @@ asynStatus turboPmacAxis::stop(double acceleration) {
|
||||
// if we're currently inside it.
|
||||
pTurboPmacA_->waitForHandshake = false;
|
||||
|
||||
/*
|
||||
Stopping the motor results in a movement and further move commands have to
|
||||
wait until the stopping movement is done. Therefore, we need to wait until
|
||||
the poller "sees" the changed state (otherwise, we risk issuing move
|
||||
commands while the motor is stopping). To ensure that at least one poll is
|
||||
done, this thread (which also runs move commands) is paused for twice the
|
||||
idle poll period.
|
||||
*/
|
||||
unsigned int idlePollMicros =
|
||||
(unsigned int)ceil(pC_->idlePollPeriod() * 1e6);
|
||||
usleep(2 * idlePollMicros);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -886,14 +940,8 @@ asynStatus turboPmacAxis::doReset() {
|
||||
// if we're currently inside it.
|
||||
pTurboPmacA_->waitForHandshake = false;
|
||||
|
||||
// Disable the axis, if it is not in a moving state
|
||||
int axStat = pTurboPmacA_->axisStatus;
|
||||
if (axStat == 0 || axStat == -6) {
|
||||
snprintf(command, sizeof(command), "M%2.2d14=0", axisNo_);
|
||||
status = pC_->writeRead(axisNo_, command, response, 0);
|
||||
}
|
||||
|
||||
return status;
|
||||
// Disable the axis
|
||||
return enable(false);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1052,7 +1100,7 @@ asynStatus turboPmacAxis::rereadEncoder() {
|
||||
|
||||
asynStatus turboPmacAxis::enable(bool on) {
|
||||
|
||||
int timeout_enable_disable = 2;
|
||||
int timeout_enable_disable = 5;
|
||||
char command[pC_->MAXBUF_] = {0};
|
||||
char response[pC_->MAXBUF_] = {0};
|
||||
int nvals = 0;
|
||||
@@ -1080,13 +1128,16 @@ asynStatus turboPmacAxis::enable(bool on) {
|
||||
axStatus == 5 || axStatus == 6 || axStatus == 7 || axStatus == 8 ||
|
||||
axStatus == 9 || axStatus == 10 || axStatus == 11 || axStatus == 12 ||
|
||||
axStatus == 13 || axStatus == 15 || axStatus == 16) {
|
||||
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nAxis is not "
|
||||
"idle and can therefore not be enabled / disabled.\n",
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
||||
|
||||
asynPrint(
|
||||
pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||
"Controller \"%s\", axis %d => %s, line %d\nAxis is not "
|
||||
"idle (status %d) and can therefore not be enabled / disabled.\n",
|
||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, axStatus);
|
||||
|
||||
setAxisParamChecked(this, motorMessageText,
|
||||
"Axis cannot be disabled while it is moving.");
|
||||
pTurboPmacA_->enableDisable = false;
|
||||
return asynError;
|
||||
}
|
||||
|
||||
@@ -1109,7 +1160,10 @@ asynStatus turboPmacAxis::enable(bool on) {
|
||||
}
|
||||
}
|
||||
|
||||
// Enable / disable the axis if it is not moving
|
||||
// Now the actual enabling / disabling starts
|
||||
pTurboPmacA_->enableDisable = true;
|
||||
|
||||
// Enable / disable the axis
|
||||
snprintf(command, sizeof(command), "M%2.2d14=%d", axisNo_, on);
|
||||
asynPrint(pC_->pasynUser(), ASYN_TRACE_FLOW,
|
||||
"Controller \"%s\", axis %d => %s, line %d\n%s axis\n",
|
||||
@@ -1127,10 +1181,14 @@ asynStatus turboPmacAxis::enable(bool on) {
|
||||
int startTime = time(NULL);
|
||||
while (time(NULL) < startTime + timeout_enable_disable) {
|
||||
|
||||
// Wait a bit between status updates from the controller.
|
||||
usleep(10000);
|
||||
|
||||
// Read the axis status
|
||||
usleep(100000);
|
||||
status = pC_->writeRead(axisNo_, command, response, 1);
|
||||
if (status != asynSuccess) {
|
||||
// Enabling / disabling procedure failed
|
||||
pTurboPmacA_->enableDisable = false;
|
||||
return status;
|
||||
}
|
||||
nvals = sscanf(response, "%d", &pTurboPmacA_->axisStatus);
|
||||
@@ -1140,9 +1198,13 @@ asynStatus turboPmacAxis::enable(bool on) {
|
||||
}
|
||||
|
||||
if ((pTurboPmacA_->axisStatus != -3) == on) {
|
||||
usleep(500000);
|
||||
|
||||
bool moving = false;
|
||||
// Perform a poll to update the parameter library
|
||||
poll(&moving);
|
||||
forcedPoll(&moving);
|
||||
|
||||
// Enabling / disabling procedure is completed (successfully)
|
||||
pTurboPmacA_->enableDisable = false;
|
||||
return asynSuccess;
|
||||
}
|
||||
}
|
||||
@@ -1159,6 +1221,9 @@ asynStatus turboPmacAxis::enable(bool on) {
|
||||
snprintf(command, sizeof(command), "Failed to %s within %d seconds",
|
||||
on ? "enable" : "disable", timeout_enable_disable);
|
||||
setAxisParamChecked(this, motorMessageText, command);
|
||||
|
||||
// Enabling / disabling procedure failed
|
||||
pTurboPmacA_->enableDisable = false;
|
||||
return asynError;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
#include "turboPmacController.h"
|
||||
#include <memory>
|
||||
|
||||
struct turboPmacAxisImpl;
|
||||
struct HIDDEN turboPmacAxisImpl;
|
||||
|
||||
class turboPmacAxis : public sinqAxis {
|
||||
class HIDDEN turboPmacAxis : public sinqAxis {
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new turboPmacAxis
|
||||
|
||||
@@ -41,13 +41,13 @@ struct turboPmacControllerImpl {
|
||||
// User for writing int32 values to the port driver.
|
||||
asynUser *pasynInt32SyncIOipPort;
|
||||
|
||||
// Indices of additional PVs
|
||||
// Indices of additional ParamLib entries
|
||||
int rereadEncoderPosition;
|
||||
int readConfig;
|
||||
int flushHardware;
|
||||
int limFromHardware;
|
||||
};
|
||||
#define NUM_turboPmac_DRIVER_PARAMS 3
|
||||
#define NUM_turboPmac_DRIVER_PARAMS 5
|
||||
|
||||
turboPmacController::turboPmacController(const char *portName,
|
||||
const char *ipPortConfigName,
|
||||
@@ -207,7 +207,6 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
|
||||
// Definition of local variables.
|
||||
asynStatus status = asynSuccess;
|
||||
asynStatus timeoutStatus = asynSuccess;
|
||||
// char fullCommand[MAXBUF_] = {0};
|
||||
char drvMessageText[MAXBUF_] = {0};
|
||||
char modResponse[MAXBUF_] = {0};
|
||||
int motorStatusProblem = 0;
|
||||
@@ -255,6 +254,22 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
|
||||
pasynOctetSyncIOipPort(), command, commandLength, response, MAXBUF_,
|
||||
pTurboPmacC_->comTimeout, &nbytesOut, &nbytesIn, &eomReason);
|
||||
|
||||
/*
|
||||
If sth. is written to the controller, it needs some time to process the
|
||||
command. However, the controller returns the acknowledgment via
|
||||
pasynOctetSyncIO->writeRead immediately, signalling to the driver that it is
|
||||
ready to receive the next command. In practice, this can result in commands
|
||||
getting discarded on the driver side or in bringing the driver in undefined
|
||||
states (e.g. stuck in status 1).
|
||||
|
||||
To prevent this, we wait for 20 ms after a write command to give the
|
||||
controller enough time to process everything. A write command can be
|
||||
identified by looking for the equal sign.
|
||||
*/
|
||||
if (strchr(command, '=')) {
|
||||
usleep(20000);
|
||||
}
|
||||
|
||||
msgPrintControlKey comKey =
|
||||
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||
|
||||
|
||||
@@ -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 turboPmacAxis;
|
||||
class HIDDEN turboPmacAxis;
|
||||
|
||||
struct turboPmacControllerImpl;
|
||||
struct HIDDEN turboPmacControllerImpl;
|
||||
|
||||
class turboPmacController : public sinqController {
|
||||
class HIDDEN turboPmacController : public sinqController {
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new turboPmacController object. This function is meant
|
||||
@@ -93,7 +93,8 @@ class turboPmacController : public sinqController {
|
||||
* @return asynStatus
|
||||
*/
|
||||
asynStatus writeRead(int axisNo, const char *command, char *response,
|
||||
int numExpectedResponses);
|
||||
int numExpectedResponses)
|
||||
__attribute__((visibility("hidden")));
|
||||
|
||||
/**
|
||||
* @brief Specialized version of sinqController::couldNotParseResponse
|
||||
|
||||
Reference in New Issue
Block a user