Updated turboPmac version and added constructor for standard axis
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
registrar(seleneVirtualAxesRegister)
|
||||
registrar(seleneOffsetAxisRegister)
|
||||
registrar(seleneStandardAxisRegister)
|
||||
registrar(seleneGuideControllerRegister)
|
||||
@@ -161,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"
|
||||
|
||||
Submodule turboPmac updated: 62ccf046fd...66db8ce408
Reference in New Issue
Block a user