Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1ee483f8e9 | |||
| 002b5d2616 | |||
| ce80426790 | |||
| 72f3965881 | |||
| d41e7bf054 | |||
| 30bfa1cac5 | |||
| 235816fd20 | |||
| bd0966d2c9 | |||
| 9d5d90574a | |||
| 6effc5e906 | |||
| bc5de11b16 | |||
| aa488627f9 | |||
| ccaee6c5d1 | |||
| 323b030581 | |||
| b206012df2 | |||
| 21ec7e8467 | |||
| 398bc8241a | |||
| 8ca684604d | |||
| 72fe2b3681 | |||
| 5911e62029 | |||
| 682024091f | |||
| 335de72bc5 | |||
| 8e5055d6b8 | |||
| 1cab6e14ff | |||
| 1e8a6495b8 | |||
| 6b91ab6d51 | |||
| f423002d23 | |||
| 79ec79fac1 | |||
| 1703542770 | |||
| c7d1dc4930 | |||
| 6fd3848f13 | |||
| 56f08f3c76 | |||
| 168bfae983 | |||
| 0e29750d13 | |||
| ba5b921aca | |||
| 1b810fb353 | |||
| 4bc3388bc6 | |||
| c759156058 | |||
| eca513f3a0 | |||
| 26175290bf |
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
|
||||
@@ -1,6 +1,6 @@
|
||||
# turboPmac
|
||||
|
||||
## <span style="color:red">Please read the documentation of sinqMotor first: https://git.psi.ch/sinq-epics-modules/sinqmotor</span>
|
||||
## <span style="color:red">Please read the documentation of sinqMotor first: https://gitea.psi.ch/lin-epics-modules/sinqMotor</span>
|
||||
|
||||
## Overview
|
||||
|
||||
@@ -8,7 +8,7 @@ This is a driver for the Turbo PMAC motion controller with the SINQ communicatio
|
||||
|
||||
## User guide
|
||||
|
||||
This driver is a standard sinqMotor-derived which however uses a special low level IP Port driver (`pmacAsynIPPortConfigure`) instead of the standard `drvAsynIPPortConfigure`. For the general configuration, please see https://git.psi.ch/sinq-epics-modules/sinqmotor/-/blob/main/README.md.
|
||||
This driver is a standard sinqMotor-derived which however uses a special low level IP Port driver (`pmacAsynIPPortConfigure`) instead of the standard `drvAsynIPPortConfigure`. For the general configuration, please see https://gitea.psi.ch/lin-epics-modules/sinqMotor/src/branch/main/README.md.
|
||||
|
||||
The folder "utils" contains utility scripts for working with pmac motor controllers. To read their manual, run the scripts without any arguments.
|
||||
- writeRead.py: Allows sending commands to and receiving commands from a pmac controller over an ethernet connection.
|
||||
@@ -67,8 +67,8 @@ dbLoadRecords("$(turboPmac_DB)/asynRecord.db","P=$(INSTR)$(DRIVER_PORT),PORT=$(I
|
||||
|
||||
### Versioning
|
||||
|
||||
Please see the documentation for the module sinqMotor: https://git.psi.ch/sinq-epics-modules/sinqmotor/-/blob/main/README.md.
|
||||
Please see the documentation for the module sinqMotor: https://gitea.psi.ch/lin-epics-modules/sinqMotor/src/branch/main/README.md.
|
||||
|
||||
### How to build it
|
||||
|
||||
This driver can be compiled and installed by running `make install` from the same directory where the Makefile is located. However, since it uses the git submodule sinqMotor, make sure that the correct version of the submodule repository is checked out AND the change is commited (`git status` shows no non-committed changes). Please see the section "Usage as static dependency" in https://git.psi.ch/sinq-epics-modules/sinqmotor/-/blob/main/README.md for more details.
|
||||
This driver can be compiled and installed by running `make install` from the same directory where the Makefile is located. However, since it uses the git submodule sinqMotor, make sure that the correct version of the submodule repository is checked out AND the change is commited (`git status` shows no non-committed changes). Please see the section "Usage as static dependency" in https://gitea.psi.ch/lin-epics-modules/sinqMotor/src/branch/main/README.md for more details.
|
||||
|
||||
@@ -31,3 +31,14 @@ record(longout, "$(INSTR)FlushHardware") {
|
||||
field(PINI, "NO")
|
||||
field(VAL, "1")
|
||||
}
|
||||
|
||||
# If this PV is set to 1 (default), the position limits are read out from the
|
||||
# controller. Otherwise, the limits given in the substitution file (DHLM and
|
||||
# DLLM) are used.
|
||||
# This record is coupled to the parameter library via limFromHardware -> LIM_FROM_HARDWARE.
|
||||
record(longout, "$(INSTR)$(M):LimFromHardware") {
|
||||
field(DTYP, "asynInt32")
|
||||
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) LIM_FROM_HARDWARE")
|
||||
field(PINI, "YES")
|
||||
field(VAL, "$(LIMFROMHARDWARE=1)")
|
||||
}
|
||||
Submodule sinqMotor updated: c2eca33ce8...7a0de4e9d9
@@ -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
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,16 +1,12 @@
|
||||
#ifndef turboPmacAXIS_H
|
||||
#define turboPmacAXIS_H
|
||||
#include "sinqAxis.h"
|
||||
#include "sinqController.h"
|
||||
#include "turboPmacController.h"
|
||||
#include <memory>
|
||||
|
||||
struct turboPmacAxisImpl;
|
||||
struct HIDDEN turboPmacAxisImpl;
|
||||
|
||||
// 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 turboPmacController;
|
||||
|
||||
class turboPmacAxis : public sinqAxis {
|
||||
class HIDDEN turboPmacAxis : public sinqAxis {
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new turboPmacAxis
|
||||
@@ -24,6 +20,7 @@ class turboPmacAxis : public sinqAxis {
|
||||
/**
|
||||
* @brief Destroy the turboPmacAxis
|
||||
*
|
||||
* This destructor is necessary in order to use the PIMPL idiom.
|
||||
*/
|
||||
virtual ~turboPmacAxis();
|
||||
|
||||
@@ -141,6 +138,11 @@ class turboPmacAxis : public sinqAxis {
|
||||
*/
|
||||
void setNeedInit(bool needInit);
|
||||
|
||||
/**
|
||||
* @brief Return a pointer to the axis controller
|
||||
*/
|
||||
virtual turboPmacController *pController() override { return pC_; };
|
||||
|
||||
private:
|
||||
turboPmacController *pC_;
|
||||
std::unique_ptr<turboPmacAxisImpl> pTurboPmacA_;
|
||||
|
||||
@@ -41,10 +41,11 @@ 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
|
||||
|
||||
@@ -114,6 +115,17 @@ turboPmacController::turboPmacController(const char *portName,
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
status = createParam("LIM_FROM_HARDWARE", asynParamInt32,
|
||||
&pTurboPmacC_->limFromHardware);
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
Define the end-of-string of a message coming from the device to EPICS.
|
||||
It is not necessary to append a terminator to outgoing messages, since
|
||||
@@ -167,6 +179,8 @@ turboPmacController::turboPmacController(const char *portName,
|
||||
}
|
||||
}
|
||||
|
||||
turboPmacController::~turboPmacController() {}
|
||||
|
||||
/*
|
||||
Access one of the axes of the controller via the axis adress stored in asynUser.
|
||||
If the axis does not exist or is not a Axis, a nullptr is returned and an
|
||||
@@ -192,9 +206,7 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
|
||||
|
||||
// Definition of local variables.
|
||||
asynStatus status = asynSuccess;
|
||||
asynStatus paramLibStatus = asynSuccess;
|
||||
asynStatus timeoutStatus = asynSuccess;
|
||||
// char fullCommand[MAXBUF_] = {0};
|
||||
char drvMessageText[MAXBUF_] = {0};
|
||||
char modResponse[MAXBUF_] = {0};
|
||||
int motorStatusProblem = 0;
|
||||
@@ -242,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__);
|
||||
|
||||
@@ -414,41 +442,18 @@ asynStatus turboPmacController::writeRead(int axisNo, const char *command,
|
||||
|
||||
// Log the overall status (communication successfull or not)
|
||||
if (status == asynSuccess) {
|
||||
paramLibStatus = axis->setIntegerParam(this->motorStatusCommsError_, 0);
|
||||
setAxisParamChecked(axis, motorStatusCommsError, false);
|
||||
} else {
|
||||
// Check if the axis already is in an error communication mode. If
|
||||
// it is not, upstream the error. This is done to avoid "flooding"
|
||||
// the user with different error messages if more than one error
|
||||
// ocurred before an error-free communication
|
||||
paramLibStatus =
|
||||
getIntegerParam(axisNo, motorStatusProblem_, &motorStatusProblem);
|
||||
if (paramLibStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(paramLibStatus, "motorStatusProblem",
|
||||
axisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
getAxisParamChecked(axis, motorStatusProblem, &motorStatusProblem);
|
||||
|
||||
if (motorStatusProblem == 0) {
|
||||
paramLibStatus =
|
||||
axis->setStringParam(motorMessageText(), drvMessageText);
|
||||
if (paramLibStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(paramLibStatus, "motorMessageText",
|
||||
axisNo, __PRETTY_FUNCTION__,
|
||||
__LINE__);
|
||||
}
|
||||
|
||||
paramLibStatus = axis->setIntegerParam(motorStatusProblem_, 1);
|
||||
if (paramLibStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(paramLibStatus,
|
||||
"motorStatusProblem", axisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
paramLibStatus = axis->setIntegerParam(motorStatusProblem_, 1);
|
||||
if (paramLibStatus != asynSuccess) {
|
||||
return paramLibAccessFailed(paramLibStatus,
|
||||
"motorStatusCommsError", axisNo,
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
setAxisParamChecked(axis, motorMessageText, drvMessageText);
|
||||
setAxisParamChecked(axis, motorStatusProblem, true);
|
||||
setAxisParamChecked(axis, motorStatusCommsError, true);
|
||||
}
|
||||
}
|
||||
return status;
|
||||
@@ -506,6 +511,9 @@ int turboPmacController::rereadEncoderPosition() {
|
||||
}
|
||||
int turboPmacController::readConfig() { return pTurboPmacC_->readConfig; }
|
||||
int turboPmacController::flushHardware() { return pTurboPmacC_->flushHardware; }
|
||||
int turboPmacController::limFromHardware() {
|
||||
return pTurboPmacC_->limFromHardware;
|
||||
}
|
||||
|
||||
asynUser *turboPmacController::pasynInt32SyncIOipPort() {
|
||||
return pTurboPmacC_->pasynInt32SyncIOipPort;
|
||||
|
||||
@@ -10,12 +10,16 @@
|
||||
#define turboPmacController_H
|
||||
#include "sinqAxis.h"
|
||||
#include "sinqController.h"
|
||||
#include "turboPmacAxis.h"
|
||||
#include <memory>
|
||||
|
||||
struct turboPmacControllerImpl;
|
||||
// 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 HIDDEN turboPmacAxis;
|
||||
|
||||
class turboPmacController : public sinqController {
|
||||
struct HIDDEN turboPmacControllerImpl;
|
||||
|
||||
class HIDDEN turboPmacController : public sinqController {
|
||||
public:
|
||||
/**
|
||||
* @brief Construct a new turboPmacController object. This function is meant
|
||||
@@ -36,6 +40,13 @@ class turboPmacController : public sinqController {
|
||||
double idlePollPeriod, double comTimeout,
|
||||
int numExtraParams = 0);
|
||||
|
||||
/**
|
||||
* @brief Destroy the controller. Its implementation is empty, however the
|
||||
* destructor needs to be provided for handling turboPmacControllerImpl.
|
||||
*
|
||||
*/
|
||||
virtual ~turboPmacController();
|
||||
|
||||
/**
|
||||
* @brief Get the axis object
|
||||
*
|
||||
@@ -82,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
|
||||
@@ -122,6 +134,7 @@ class turboPmacController : public sinqController {
|
||||
int rereadEncoderPosition();
|
||||
int readConfig();
|
||||
int flushHardware();
|
||||
int limFromHardware();
|
||||
|
||||
asynUser *pasynInt32SyncIOipPort();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user