17 Commits
1.1.0 ... 1.3.1

Author SHA1 Message Date
754fc16cd3 Updated to turboPmac 1.6.1
Some checks failed
Test And Build / Lint (push) Successful in 4s
Test And Build / Build (push) Failing after 7s
2026-02-03 13:47:10 +01:00
a7cb1cd05f Readded correct version of turboPmac
Some checks failed
Test And Build / Lint (push) Successful in 3s
Test And Build / Build (push) Failing after 7s
2026-01-23 13:28:38 +01:00
f9d5d1aaee Completely removed turboPmac temporarily 2026-01-23 13:27:47 +01:00
ef81f38017 Added correct repo for turboPMAC 2026-01-23 11:47:48 +01:00
6ee554f9e5 Remove turboPmac submodule 2026-01-23 11:46:45 +01:00
7bd3adbfc3 Remove turboPmac submodule 2026-01-23 11:46:12 +01:00
bff7ad79df Fully remove turboPmac submodule 2026-01-23 11:44:46 +01:00
70029b12b2 Temporarily removed turboPmac module 2026-01-23 11:42:59 +01:00
ac5ab3855e Updated turboPmac version and added constructor for standard axis 2026-01-23 11:38:18 +01:00
2c9de618ec Made code compile with compiler flags
Some checks failed
Test And Build / Lint (push) Successful in 4s
Test And Build / Build (push) Failing after 7s
2025-12-23 14:00:08 +01:00
b834dc3f8d Updated turboPmac version 2025-12-23 13:51:18 +01:00
ee6235e74a Removed C++ only flag from USR_CFLAGS and updated turboPmac version
Some checks failed
Test And Build / Lint (push) Successful in 3s
Test And Build / Build (push) Failing after 9s
2025-08-22 15:30:33 +02:00
48c068826c Updated sinqMotor to fix bug in forcedPoll regarding watchdog
Some checks failed
Test And Build / Lint (push) Successful in 4s
Test And Build / Build (push) Failing after 10s
2025-08-14 17:25:35 +02:00
c494fc88a5 Updated to turboPmac 1.4 and hid symbols
Some checks failed
Test And Build / Lint (push) Successful in 3s
Test And Build / Build (push) Failing after 9s
2025-08-12 09:28:06 +02:00
e0fa9ef3a9 also check header files
Some checks failed
Test And Build / Lint (push) Successful in 3s
Test And Build / Build (push) Failing after 10s
2025-07-04 14:37:43 +02:00
dc6d5c40b3 need to build sinqmotor first
Some checks failed
Test And Build / Lint (push) Successful in 4s
Test And Build / Build (push) Failing after 10s
2025-07-04 14:23:21 +02:00
56288b1db8 adds gitea action
Some checks failed
Test And Build / Lint (push) Successful in 3s
Test And Build / Build (push) Failing after 3s
2025-07-04 14:21:39 +02:00
14 changed files with 194 additions and 87 deletions

View File

@@ -0,0 +1,30 @@
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 src/*.h
Build:
runs-on: linepics
steps:
- name: checkout repo
uses: actions/checkout@v4
with:
submodules: 'true'
- run: |
pushd turboPmac
sed -i 's/ARCH_FILTER=.*/ARCH_FILTER=linux%/' Makefile
echo -e "\nIGNORE_SUBMODULES += sinqmotor" >> Makefile
make install
popd
- run: |
sed -i 's/ARCH_FILTER=.*/ARCH_FILTER=linux%/' Makefile
echo -e "\nIGNORE_SUBMODULES += turboPmac" >> Makefile
make install

View File

@@ -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/seleneLift/$(ls -U /ioc/modules/seleneLift/ | head -1)" "./seleneLift-${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}"
artifacts:
name: "seleneLift-${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}"
paths:
- "seleneLift-${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}/*"
expire_in: 1 week
when: always
tags:
- sinq

View File

@@ -42,4 +42,5 @@ DBDS += turboPmac/sinqMotor/src/sinqMotor.dbd
DBDS += turboPmac/src/turboPmac.dbd
DBDS += src/seleneGuide.dbd
USR_CFLAGS += -Wall -Wextra -Weffc++ -Wunused-result -Wextra -Werror # -Wpedantic // Does not work because EPICS macros trigger warnings
USR_CFLAGS += -Wall -Wextra -Wunused-result -Wextra -Werror # -Wpedantic // Does not work because EPICS macros trigger warnings
USR_CXXFLAGS += -Wall -Wextra -Wunused-result -Wextra -Werror

View File

@@ -44,7 +44,7 @@ Two additional PVs are provided in `db/seleneGuide.db`:
### Usage in IOC shell
seleneGuide exports the following IOC shell functions:
- `seleneGuideController`: Create a new controller object. This object is essentially a `turboPmacController` object from the standard [Turbo PMAC driver](https://git.psi.ch/sinq-epics-modules/turboPmac), but it supports the additional motor PVs for absolute position and normalization. This means that it can be used with "normal" `turboPmacAxis` as well.
- `seleneGuideController`: Create a new controller object. This object is essentially a `turboPmacController` object from the standard [Turbo PMAC driver](https://git.psi.ch/sinq-epics-modules/turboPmac), but it supports the additional motor PVs for absolute position and normalization. This means that it can be used to control a "standard" TurboPMAC axis as well. To ensure compatibility between controller and axis, it is recommended to use the wrapper `seleneStandardAxis` instead of the `turboPmacAxis` provided by the basic TurboPMAC driver (because otherwise the versions of the `seleneGuide` and the `turboPmac` drivers are not independent from each other).
- `seleneOffsetAxis`: Create a new offset axis object with the specified x- and z-offset from an arbitrary origin in mm.
- `seleneVirtualAxes`: Create the virtual lift and the angle axes.
@@ -78,8 +78,9 @@ seleneOffsetAxis("$(NAME)",5, 5933.99477, 0.0);
seleneOffsetAxis("$(NAME)",6, 7463.87259, 0.0);
# These are two "normal" PMAC axes which work the same way they would with a turboPmacController.
turboPmacAxis("$(NAME)",7);
turboPmacAxis("$(NAME)",8);
# Using the wrapper seleneStandardAxis ensures compatibility to the seleneGuideController.
seleneStandardAxis("$(NAME)",7);
seleneStandardAxis("$(NAME)",8);
# This function call creates the lift and the angle axes.
# The arguments on position 2 to 7 are the axis indices of the offset axes

View File

@@ -50,8 +50,15 @@ asynStatus seleneAngleAxis::stop(double acceleration) {
}
asynStatus seleneAngleAxis::doMove(double position, int relative,
double min_velocity, double max_velocity,
double minVelocity, double maxVelocity,
double acceleration) {
// Suppress unused variable warnings
(void)relative;
(void)minVelocity;
(void)maxVelocity;
(void)acceleration;
double motorRecResolution = 0.0;
getAxisParamChecked(this, motorRecResolution, &motorRecResolution);

View File

@@ -6,14 +6,14 @@
// Forward declaration of the seleneLiftAxis class to resolve the cyclic
// dependency between the seleneLiftAxis and the seleneAngleAxis .h-file.
// See https://en.cppreference.com/w/cpp/language/class.
class seleneLiftAxis;
class HIDDEN seleneLiftAxis;
/**
* @brief Virtual axis for setting the angle of the Selene guide
*
* Please see README.md for a detailed explanation.
*/
class seleneAngleAxis : public turboPmacAxis {
class HIDDEN seleneAngleAxis : public turboPmacAxis {
public:
/**
* @brief Construct a new seleneAngleAxis.
@@ -48,12 +48,12 @@ class seleneAngleAxis : public turboPmacAxis {
*
* @param position
* @param relative
* @param min_velocity
* @param minVelocity
* @param maxOffset_velocity
* @param acceleration
* @return asynStatus
*/
asynStatus doMove(double position, int relative, double min_velocity,
asynStatus doMove(double position, int relative, double minVelocity,
double maxOffset_velocity, double acceleration);
/**

View File

@@ -1,3 +1,4 @@
registrar(seleneVirtualAxesRegister)
registrar(seleneOffsetAxisRegister)
registrar(seleneStandardAxisRegister)
registrar(seleneGuideControllerRegister)

View File

@@ -23,7 +23,8 @@ seleneGuideController::seleneGuideController(
const char *portName, const char *ipPortConfigName, int numAxes,
double movingPollPeriod, double idlePollPeriod, double comTimeout)
: turboPmacController(portName, ipPortConfigName, numAxes, movingPollPeriod,
idlePollPeriod, NUM_seleneGuide_DRIVER_PARAMS)
idlePollPeriod, comTimeout,
NUM_seleneGuide_DRIVER_PARAMS)
{
@@ -145,7 +146,8 @@ static const iocshArg *const CreateControllerArgs[] = {
&CreateControllerArg0, &CreateControllerArg1, &CreateControllerArg2,
&CreateControllerArg3, &CreateControllerArg4, &CreateControllerArg5};
static const iocshFuncDef configSeleneGuideCreateController = {
"seleneGuideController", 6, CreateControllerArgs};
"seleneGuideController", 6, CreateControllerArgs,
"Create a new instance of a Selene controller."};
static void configSeleneGuideCreateControllerCallFunc(const iocshArgBuf *args) {
seleneGuideCreateController(args[0].sval, args[1].sval, args[2].ival,
args[3].dval, args[4].dval, args[5].dval);
@@ -159,4 +161,97 @@ static void seleneGuideControllerRegister(void) {
}
epicsExportRegistrar(seleneGuideControllerRegister);
/*
C wrapper for a "standard" TurboPMAC axis constructor. This function is
identical to "turboPmacCreateAxis" in the standard TurboPMAC driver. However, it
is recommended to use this constructor to make sure the version of the axis
matches that of the controller. The controller is read from the portName.
*/
asynStatus seleneStandardCreateAxis(const char *portName, int axis) {
/*
findAsynPortDriver is a asyn library FFI function which uses the C ABI.
Therefore it returns a void pointer instead of e.g. a pointer to a
superclass of the controller such as asynPortDriver. Type-safe upcasting
via dynamic_cast is therefore not possible directly. However, we do know
that the void pointer is either a pointer to asynPortDriver (if a driver
with the specified name exists) or a nullptr. Therefore, we first do a
nullptr check, then a cast to asynPortDriver and lastly a (typesafe)
dynamic_upcast to Controller
https://stackoverflow.com/questions/70906749/is-there-a-safe-way-to-cast-void-to-class-pointer-in-c
*/
void *ptr = findAsynPortDriver(portName);
if (ptr == nullptr) {
/*
We can't use asynPrint here since this macro would require us
to get an asynUser from a pointer to an asynPortDriver.
However, the given pointer is a nullptr and therefore doesn't
have an asynUser! printf is an EPICS alternative which
works w/o that, but doesn't offer the comfort provided
by the asynTrace-facility
*/
errlogPrintf("Controller \"%s\" => %s, line %d\nPort not found.",
portName, __PRETTY_FUNCTION__, __LINE__);
return asynError;
}
// Unsafe cast of the pointer to an asynPortDriver
asynPortDriver *apd = (asynPortDriver *)(ptr);
// Safe downcast
seleneGuideController *pC = dynamic_cast<seleneGuideController *>(apd);
if (pC == nullptr) {
errlogPrintf("Controller \"%s\" => %s, line %d\nController "
"is not a seleneGuideController.",
portName, __PRETTY_FUNCTION__, __LINE__);
return asynError;
}
// Prevent manipulation of the controller from other threads while we
// create the new axis.
pC->lock();
/*
We create a new instance of the axis, using the "new" keyword to
allocate it on the heap while avoiding RAII.
https://github.com/epics-modules/motor/blob/master/motorApp/MotorSrc/asynMotorController.cpp
https://github.com/epics-modules/asyn/blob/master/asyn/asynPortDriver/asynPortDriver.cpp
The created object is registered in EPICS in its constructor and can
safely be "leaked" here.
*/
#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
#pragma GCC diagnostic ignored "-Wunused-variable"
turboPmacAxis *pAxis = new turboPmacAxis(pC, axis);
// Allow manipulation of the controller again
pC->unlock();
return asynSuccess;
}
/*
Same procedure as for the CreateController function, but for the axis
itself.
*/
static const iocshArg CreateAxisArg0 = {"Controller name (e.g. mcu1)",
iocshArgString};
static const iocshArg CreateAxisArg1 = {"Axis number", iocshArgInt};
static const iocshArg *const CreateAxisArgs[] = {&CreateAxisArg0,
&CreateAxisArg1};
static const iocshFuncDef configSeleneStandardCreateAxis = {
"seleneStandardAxis", 2, CreateAxisArgs,
"Create an instance of a standard turboPmac axis for the selene "
"controller. The first argument is the controller this axis should be "
"attached to, the second argument is the axis number."};
static void configSeleneStandardCreateAxisCallFunc(const iocshArgBuf *args) {
seleneStandardCreateAxis(args[0].sval, args[1].ival);
}
// This function is made known to EPICS in turboPmac.dbd and is called by
// EPICS in order to register both functions in the IOC shell
static void seleneStandardAxisRegister(void) {
iocshRegister(&configSeleneStandardCreateAxis,
configSeleneStandardCreateAxisCallFunc);
}
epicsExportRegistrar(seleneStandardAxisRegister);
} // extern "C"

View File

@@ -13,11 +13,11 @@
// Forward declaration of the axis classes to resolve the cyclic
// dependency between the seleneLiftAxis and the seleneAngleAxis .h-file.
// See https://en.cppreference.com/w/cpp/language/class.
class seleneAngleAxis;
class seleneLiftAxis;
class seleneOffsetAxis;
class HIDDEN seleneAngleAxis;
class HIDDEN seleneLiftAxis;
class HIDDEN seleneOffsetAxis;
class seleneGuideController : public turboPmacController {
class HIDDEN seleneGuideController : public turboPmacController {
public:
/**

View File

@@ -381,8 +381,15 @@ asynStatus seleneLiftAxis::doPoll(bool *moving) {
}
asynStatus seleneLiftAxis::doMove(double position, int relative,
double min_velocity, double max_velocity,
double minVelocity, double maxVelocity,
double acceleration) {
// Suppress unused variable warnings
(void)relative;
(void)minVelocity;
(void)maxVelocity;
(void)acceleration;
double motorRecResolution = 0.0;
getAxisParamChecked(this, motorRecResolution, &motorRecResolution);
setTargetPosition(position * motorRecResolution);
@@ -440,6 +447,9 @@ asynStatus seleneLiftAxis::stop(double acceleration) {
// =========================================================================
// Suppress unused variable warnings
(void)acceleration;
// Stop all axes
status = pC_->writeRead(axisNo_, "P150=8", response, 0);
@@ -466,6 +476,10 @@ asynStatus seleneLiftAxis::doReset() {
}
asynStatus seleneLiftAxis::enable(bool on) {
// Suppress unused variable warnings
(void)on;
setAxisParamChecked(this, motorMessageText,
"Axis cannot be enabled / disabled");
return asynSuccess;
@@ -479,6 +493,12 @@ asynStatus seleneLiftAxis::readEncoderType() {
asynStatus seleneLiftAxis::doHome(double minVelocity, double maxVelocity,
double acceleration, int forwards) {
// Suppress unused variable warnings
(void)minVelocity;
(void)maxVelocity;
(void)acceleration;
(void)forwards;
char response[pC_->MAXBUF_] = {0};
// No answer expected
@@ -636,8 +656,9 @@ static const iocshArg *const CreateAxisArgs[] = {
&CreateAxisArg3, &CreateAxisArg4, &CreateAxisArg5,
&CreateAxisArg6, &CreateAxisArg7, &CreateAxisArg8,
};
static const iocshFuncDef configSeleneVirtualCreateAxes = {"seleneVirtualAxes",
9, CreateAxisArgs};
static const iocshFuncDef configSeleneVirtualCreateAxes = {
"seleneVirtualAxes", 9, CreateAxisArgs,
"Creates instances of Selene axes."};
static void configSeleneVirtualCreateAxesCallFunc(const iocshArgBuf *args) {
seleneVirtualCreateAxes(args[0].sval, args[1].ival, args[2].ival,
args[3].ival, args[4].ival, args[5].ival,

View File

@@ -11,7 +11,7 @@
*
* Please see README.md for a detailed explanation.
*/
class seleneLiftAxis : public turboPmacAxis {
class HIDDEN seleneLiftAxis : public turboPmacAxis {
public:
static const int numAxes_ = 6;
@@ -65,12 +65,12 @@ class seleneLiftAxis : public turboPmacAxis {
*
* @param position
* @param relative
* @param min_velocity
* @param minVelocity
* @param maxOffset_velocity
* @param acceleration
* @return asynStatus
*/
asynStatus doMove(double position, int relative, double min_velocity,
asynStatus doMove(double position, int relative, double minVelocity,
double maxOffset_velocity, double acceleration);
/**

View File

@@ -283,10 +283,15 @@ seleneOffsetAxis::setPositionsFromEncoderPosition(double encoderPosition) {
}
asynStatus seleneOffsetAxis::doMove(double position, int relative,
double min_velocity,
double maxOffset_velocity,
double minVelocity, double maxVelocity,
double acceleration) {
// Suppress unused variable warnings
(void)relative;
(void)minVelocity;
(void)maxVelocity;
(void)acceleration;
double motorRecResolution = 0.0;
getAxisParamChecked(this, motorRecResolution, &motorRecResolution);
@@ -299,6 +304,9 @@ asynStatus seleneOffsetAxis::doMove(double position, int relative,
}
asynStatus seleneOffsetAxis::enable(bool on) {
// Suppress unused variable warnings
(void)on;
setAxisParamChecked(this, motorMessageText,
"Axis cannot be enabled / disabled");
return asynSuccess;
@@ -384,7 +392,8 @@ static const iocshArg *const CreateAxisArgs[] = {
&CreateAxisArg3,
};
static const iocshFuncDef configSeleneOffsetAxisCreateAxis = {
"seleneOffsetAxis", 4, CreateAxisArgs};
"seleneOffsetAxis", 4, CreateAxisArgs,
"Creates a new instance of a Selene offset axis."};
static void configSeleneOffsetAxisCreateAxisCallFunc(const iocshArgBuf *args) {
seleneOffsetAxisCreateAxis(args[0].sval, args[1].ival, args[2].dval,
args[3].dval);

View File

@@ -7,14 +7,14 @@
// Forward declaration of the seleneLiftAxis class to resolve the cyclic
// dependency between the seleneLiftAxis and the seleneAngleAxis .h-file.
// See https://en.cppreference.com/w/cpp/language/class.
class seleneLiftAxis;
class HIDDEN seleneLiftAxis;
/**
* @brief Virtual axis for setting the offset of a motor of the Selene guide
*
* Please see README.md for a detailed explanation.
*/
class seleneOffsetAxis : public turboPmacAxis {
class HIDDEN seleneOffsetAxis : public turboPmacAxis {
public:
/**
* @brief Construct a new selene Offset Axis object
@@ -51,12 +51,12 @@ class seleneOffsetAxis : public turboPmacAxis {
*
* @param position
* @param relative
* @param min_velocity
* @param minVelocity
* @param maxOffset_velocity
* @param acceleration
* @return asynStatus
*/
asynStatus doMove(double position, int relative, double min_velocity,
asynStatus doMove(double position, int relative, double minVelocity,
double maxOffset_velocity, double acceleration);
/**