Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
828e9bc59c | |||
f26d1bb612 | |||
bed245b010 | |||
ca7bede4b7 | |||
d3307db987 | |||
591509bd43 | |||
5854d2c9d0 | |||
f134a61649 |
@ -24,16 +24,6 @@ formatting:
|
|||||||
tags:
|
tags:
|
||||||
- sinq
|
- 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:
|
build_module:
|
||||||
stage: build
|
stage: build
|
||||||
script:
|
script:
|
||||||
|
2
Makefile
2
Makefile
@ -10,10 +10,12 @@ ARCH_FILTER=RHEL%
|
|||||||
asynMotor_VERSION=7.2.2
|
asynMotor_VERSION=7.2.2
|
||||||
|
|
||||||
# Source files to build
|
# Source files to build
|
||||||
|
SOURCES += src/msgPrintControl.cpp
|
||||||
SOURCES += src/sinqAxis.cpp
|
SOURCES += src/sinqAxis.cpp
|
||||||
SOURCES += src/sinqController.cpp
|
SOURCES += src/sinqController.cpp
|
||||||
|
|
||||||
# Headers which allow using this library in concrete driver implementations
|
# Headers which allow using this library in concrete driver implementations
|
||||||
|
HEADERS += src/msgPrintControl.h
|
||||||
HEADERS += src/sinqAxis.h
|
HEADERS += src/sinqAxis.h
|
||||||
HEADERS += src/sinqController.h
|
HEADERS += src/sinqController.h
|
||||||
|
|
||||||
|
60
README.md
60
README.md
@ -42,34 +42,41 @@ epicsEnvSet("INSTR","SQ:SINQTEST:")
|
|||||||
iocInit()
|
iocInit()
|
||||||
```
|
```
|
||||||
The first line is a so-called shebang which instructs Linux to execute the file with the executable located at the given path - the IOC shell in this case. The controller script "mcu1.cmd" looks like this:
|
The first line is a so-called shebang which instructs Linux to execute the file with the executable located at the given path - the IOC shell in this case. The controller script "mcu1.cmd" looks like this:
|
||||||
|
The script for controller 1 ("mcu1.cmd") for a Turbo PMAC (see https://git.psi.ch/sinq-epics-modules/turboPmac) has the following structure. The scripts for other controller types can be found in the README.md of their respective repositories.
|
||||||
|
|
||||||
```
|
```
|
||||||
# Define some needed parameters (they can be safely overwritten in e.g. mcu2.cmd)
|
# Define the name of the controller and the corresponding port
|
||||||
epicsEnvSet("NAME","mcu1")
|
epicsEnvSet("NAME","mcu1")
|
||||||
epicsEnvSet("ASYN_PORT","p$(NAME)")
|
epicsEnvSet("ASYN_PORT","p$(NAME)")
|
||||||
|
|
||||||
# Define the IP adress of the controller
|
# 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
|
||||||
drvAsynIPPortConfigure("$(ASYN_PORT)","172.28.101.24:1025")
|
drvAsynIPPortConfigure("$(ASYN_PORT)","172.28.101.24:1025")
|
||||||
|
|
||||||
# Create the controller object in EPICS. The function "pmacv3Controller" is
|
# Create the controller object with the defined name and connect it to the socket via the port name.
|
||||||
# provided by loading the shared library turboPmac.
|
# The other parameters are as follows:
|
||||||
pmacv3Controller("$(NAME)","$(ASYN_PORT)",8,0.05,1,0.05);
|
# 8: Maximum number of axes
|
||||||
|
# 0.05: Busy poll period in seconds
|
||||||
|
# 1: Idle poll period in seconds
|
||||||
|
# 1: Socket communication timeout in seconds
|
||||||
|
turboPmacController("$(NAME)", "$(ASYN_PORT)", 8, 0.05, 1, 1);
|
||||||
|
|
||||||
# Create four axes objects on slots 1, 2, 3 and 5 of the controller.
|
# Define some axes for the specified MCU at the given slot (1, 2 and 5). No slot may be used twice!
|
||||||
pmacv3Axis("$(NAME)",1);
|
turboPmacAxis("$(NAME)",1);
|
||||||
pmacv3Axis("$(NAME)",2);
|
turboPmacAxis("$(NAME)",2);
|
||||||
pmacv3Axis("$(NAME)",3);
|
turboPmacAxis("$(NAME)",5);
|
||||||
pmacv3Axis("$(NAME)",5);
|
|
||||||
|
|
||||||
# Create some general PVs of an asynRecord, substituting the macro P by concatenating INSTR and NAME and PORT by ASYN_PORT.
|
# Set the number of subsequent timeouts
|
||||||
dbLoadRecords("$(sinqMotor_DB)/asynRecord.db","P=$(INSTR)$(NAME),PORT=$(ASYN_PORT)")
|
setMaxSubsequentTimeouts("$(NAME)", 20);
|
||||||
|
|
||||||
# Create PVs provided by the sinqMotor database template. This template is parametrized by the substitution file "mcu1.substitutions" (see below)
|
# Configure the timeout frequency watchdog:
|
||||||
|
setThresholdComTimeout("$(NAME)", 100, 1);
|
||||||
|
|
||||||
|
# Parametrize the EPICS record database with the substitution file named after the MCU.
|
||||||
epicsEnvSet("SINQDBPATH","$(sinqMotor_DB)/sinqMotor.db")
|
epicsEnvSet("SINQDBPATH","$(sinqMotor_DB)/sinqMotor.db")
|
||||||
dbLoadTemplate("$(TOP)/mcu1.substitutions", "INSTR=$(INSTR)$(NAME):,CONTROLLER=$(NAME)")
|
dbLoadTemplate("$(TOP)/$(NAME).substitutions", "INSTR=$(INSTR)$(NAME):,CONTROLLER=$(NAME)")
|
||||||
|
epicsEnvSet("SINQDBPATH","$(turboPmac_DB)/turboPmac.db")
|
||||||
# Create PVs specific for pmacv3. Again, we load a database template and parametrize it with the substitution file "mcu1.substitutions"
|
dbLoadTemplate("$(TOP)/$(NAME).substitutions", "INSTR=$(INSTR)$(NAME):,CONTROLLER=$(NAME)")
|
||||||
epicsEnvSet("SINQDBPATH","$(pmacv3_DB)/pmacv3.db")
|
dbLoadRecords("$(sinqMotor_DB)/asynRecord.db","P=$(INSTR)$(NAME),PORT=$(ASYN_PORT)")
|
||||||
dbLoadTemplate("$(TOP)/mcu1.substitutions", "INSTR=$(INSTR)$(NAME):,CONTROLLER=$(NAME)")
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Substitution file
|
### Substitution file
|
||||||
@ -164,7 +171,10 @@ sinqMotor offers a variety of additional methods for children classes to standar
|
|||||||
- `setMaxSubsequentTimeouts`: Set the limit for the number of subsequent timeouts before the user is informed.
|
- `setMaxSubsequentTimeouts`: Set the limit for the number of subsequent timeouts before the user is informed.
|
||||||
|
|
||||||
#### sinqAxis.h
|
#### sinqAxis.h
|
||||||
- `enable`: This function is called if the "Enable" PV from db/sinqMotor.db is set. This is an empty function which should be overwritten by concrete driver implementations.
|
- `enable`: This function is called if the `$(INSTR)$(M):Enable` PV from db/sinqMotor.db is set.
|
||||||
|
This is an empty function which should be overwritten by concrete driver implementations.
|
||||||
|
- `reset`: This function is called when the `$(INSTR)$(M):Reset` PV from db/sinqMotor.db is set.
|
||||||
|
This is an empty function which should be overwritten by concrete driver implementations.
|
||||||
- `move`: This function sets the absolute target position in the parameter library and then calls `doMove`.
|
- `move`: This function sets the absolute target position in the parameter library and then calls `doMove`.
|
||||||
- `doMove`: This is an empty function which should be overwritten by concrete driver implementations.
|
- `doMove`: This is an empty function which should be overwritten by concrete driver implementations.
|
||||||
- `home`: This function sets the internal status flags for the homing process and then calls doHome.
|
- `home`: This function sets the internal status flags for the homing process and then calls doHome.
|
||||||
@ -180,7 +190,6 @@ sinqMotor offers a variety of additional methods for children classes to standar
|
|||||||
- Reset `motorStatusProblem_`, `motorStatusCommsError_` and `motorMessageText_` if `doPoll` returned `asynSuccess`
|
- Reset `motorStatusProblem_`, `motorStatusCommsError_` and `motorMessageText_` if `doPoll` returned `asynSuccess`
|
||||||
- Run `callParamCallbacks`
|
- Run `callParamCallbacks`
|
||||||
- Return the status of `doPoll`
|
- Return the status of `doPoll`
|
||||||
- `doPoll`: This is an empty function which should be overwritten by concrete driver implementations.
|
|
||||||
- `setVeloFields`: Populates the motor record fields VELO (actual velocity), VBAS (minimum allowed velocity) and VMAX (maximum allowed velocity) from the driver.
|
- `setVeloFields`: Populates the motor record fields VELO (actual velocity), VBAS (minimum allowed velocity) and VMAX (maximum allowed velocity) from the driver.
|
||||||
- `setAcclField`: Populates the motor record field ACCL from the driver.
|
- `setAcclField`: Populates the motor record field ACCL from the driver.
|
||||||
- `startMovTimeoutWatchdog`: Starts a watchdog for the movement time. This watchdog compares the actual time spent in a movement operation with an expected time, which is calculated based on the distance of the current and the target position.
|
- `startMovTimeoutWatchdog`: Starts a watchdog for the movement time. This watchdog compares the actual time spent in a movement operation with an expected time, which is calculated based on the distance of the current and the target position.
|
||||||
@ -189,6 +198,9 @@ sinqMotor offers a variety of additional methods for children classes to standar
|
|||||||
- `setOffsetMovTimeout`: Set a linear offset for the expected movement time. This function is also available in the IOC shell.
|
- `setOffsetMovTimeout`: Set a linear offset for the expected movement time. This function is also available in the IOC shell.
|
||||||
- `setScaleMovTimeout`: Set a scaling factor for the expected movement time. This function is also available in the IOC shell.
|
- `setScaleMovTimeout`: Set a scaling factor for the expected movement time. This function is also available in the IOC shell.
|
||||||
|
|
||||||
|
#### msgPrintControl.h
|
||||||
|
In addition to the two extension classes this library also includes a mechanism which prevents excessive repetitions of the same error message to the IOC shell via the classes `msgPrintControl` and `msgPrintControlKey`. A detailed description of the mechanism can be found in the docstring of `msgPrintControl`. The implementation of the `poll` function of `sinqAxis` also contains an example how to use it. Using this feature in derived drivers is entirely optional.
|
||||||
|
|
||||||
### Versioning
|
### Versioning
|
||||||
|
|
||||||
The versioning is done via git tags. Git tags are recognized by the PSI build system: If you tag a version as 1.0, it will be built into the directory /ioc/modules/sinqMotor/1.0. The tag is directly coupled to a commit so that it is always clear which source code was used to build which binary.
|
The versioning is done via git tags. Git tags are recognized by the PSI build system: If you tag a version as 1.0, it will be built into the directory /ioc/modules/sinqMotor/1.0. The tag is directly coupled to a commit so that it is always clear which source code was used to build which binary.
|
||||||
@ -197,6 +209,12 @@ All existing tags can be listed with `git tag` in the sinqMotor directory. Detai
|
|||||||
|
|
||||||
### How to build it
|
### How to build it
|
||||||
|
|
||||||
The makefile in the top directory includes all necessary steps for compiling a shared library together with the header files into `/ioc/modules` (using the PSI EPICS build system). Therefore it is sufficient to clone this repository to a suitable location (`git clone https://git.psi.ch/sinq-epics-modules/sinqmotor/-/tree/main`). Afterwards, switch to the directory (`cd sinqmotor`) and run `make install`.
|
This library is based on the PSI version of the EPICS motor record, which can be found here: `https://git.psi.ch/epics_driver_modules/motorBase`. We use a branch with a bugfix which is currently not merged into master due to resistance of the PSI userbase: `https://git.psi.ch/epics_driver_modules/motorBase/-/tree/pick_fix-lockup-VAL-HOMF-VAL`. This library can be build with the following steps, assuming GCC and make are available:
|
||||||
|
- `git clone https://git.psi.ch/epics_driver_modules/motorBase/-/tree/pick_fix-lockup-VAL-HOMF-VAL`
|
||||||
|
- `cd motorBase`
|
||||||
|
- `git tag 7.2.2`. The latest version on master is currently 7.2.1, hence we increment the bugfix version counter by one
|
||||||
|
- `make install`
|
||||||
|
|
||||||
|
To build sinqMotor itself, the makefile in the top directory includes all necessary steps for compiling a shared library together with the header files into `/ioc/modules` (using the PSI EPICS build system). Therefore it is sufficient to clone this repository to a suitable location (`git clone https://git.psi.ch/sinq-epics-modules/sinqmotor/-/tree/main`). Afterwards, switch to the directory (`cd sinqmotor`) and run `make install`.
|
||||||
|
|
||||||
To use the library when writing a concrete motor driver, include it in the makefile of your application / library the same way as other libraries such as e.g. `asynMotor` by adding `REQUIRED+=sinqMotor` to your Makefile. The version can be specified with `sinqMotor_VERSION=x.x.x.`
|
To use the library when writing a concrete motor driver, include it in the makefile of your application / library the same way as other libraries such as e.g. `asynMotor` by adding `REQUIRED+=sinqMotor` to your Makefile. The version can be specified with `sinqMotor_VERSION=x.x.x.`
|
||||||
|
@ -41,11 +41,29 @@ record(motor,"$(INSTR)$(M)")
|
|||||||
field(RMOD,"3") # Retry mode 3 ("In-Position"): This suppresses any retries from the motor record.
|
field(RMOD,"3") # Retry mode 3 ("In-Position"): This suppresses any retries from the motor record.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# This PV reads out the 10th bit of the MSTA field of the motor record, which
|
||||||
|
# is the "motorStatusProblem_" bit. The 10th bit is adressed by 0x0200. If the
|
||||||
|
# bit is 0, the .VAL field is 0 as well. If the bit is 1, we need to divide by
|
||||||
|
# 512 (=2^9) in order to set the .VAL field to 1 (and not to 512).
|
||||||
|
record(calc, "$(INSTR)$(M):StatusProblem")
|
||||||
|
{
|
||||||
|
field(INPA, "$(INSTR)$(M).MSTA CP")
|
||||||
|
field(CALC, "(A&0x200)/512")
|
||||||
|
}
|
||||||
|
|
||||||
|
# Call the reset function of the corresponding sinqAxis
|
||||||
|
# This record is coupled to the parameter library via motorReset_ -> MOTOR_RESET.
|
||||||
|
record(longout, "$(INSTR)$(M):Reset") {
|
||||||
|
field(DTYP, "asynInt32")
|
||||||
|
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) MOTOR_RESET")
|
||||||
|
field(PINI, "NO")
|
||||||
|
}
|
||||||
|
|
||||||
# This PV allows force-stopping the motor record from within the driver by setting
|
# This PV allows force-stopping the motor record from within the driver by setting
|
||||||
# the motorForceStop_ value in the parameter library to 1. It should be reset to 0 by the driver afterwards.
|
# the motorForceStop_ value in the parameter library to 1. It should be reset to 0 by the driver afterwards.
|
||||||
# The implementation strategy is taken from https://epics.anl.gov/tech-talk/2022/msg00464.php.
|
# The implementation strategy is taken from https://epics.anl.gov/tech-talk/2022/msg00464.php.
|
||||||
# This record is coupled to the parameter library via motorForceStop_ -> MOTOR_FORCE_STOP.
|
# This record is coupled to the parameter library via motorForceStop_ -> MOTOR_FORCE_STOP.
|
||||||
record(longin, "$(INSTR)$(M):STOP_RBV")
|
record(longin, "$(INSTR)$(M):StopRBV")
|
||||||
{
|
{
|
||||||
field(DTYP, "asynInt32")
|
field(DTYP, "asynInt32")
|
||||||
field(INP, "@asyn($(CONTROLLER),$(AXIS)) MOTOR_FORCE_STOP")
|
field(INP, "@asyn($(CONTROLLER),$(AXIS)) MOTOR_FORCE_STOP")
|
||||||
@ -53,7 +71,7 @@ record(longin, "$(INSTR)$(M):STOP_RBV")
|
|||||||
field(FLNK, "$(INSTR)$(M):Stop2Field")
|
field(FLNK, "$(INSTR)$(M):Stop2Field")
|
||||||
}
|
}
|
||||||
record(longout, "$(INSTR)$(M):Stop2Field") {
|
record(longout, "$(INSTR)$(M):Stop2Field") {
|
||||||
field(DOL, "$(INSTR)$(M):STOP_RBV CP")
|
field(DOL, "$(INSTR)$(M):StopRBV CP")
|
||||||
field(OUT, "$(INSTR)$(M).STOP")
|
field(OUT, "$(INSTR)$(M).STOP")
|
||||||
field(OMSL, "closed_loop")
|
field(OMSL, "closed_loop")
|
||||||
}
|
}
|
||||||
|
114
src/msgPrintControl.cpp
Normal file
114
src/msgPrintControl.cpp
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
#include "msgPrintControl.h"
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
msgPrintControlKey::msgPrintControlKey(char *controller, int axisNo,
|
||||||
|
const char *functionName, int line) {
|
||||||
|
controller_ = controller;
|
||||||
|
axisNo_ = axisNo;
|
||||||
|
line_ = line;
|
||||||
|
functionName_ = functionName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void msgPrintControlKey::format(char *buffer, size_t bufferSize) {
|
||||||
|
snprintf(buffer, bufferSize, "controller %s, axis %d, function %s, line %d",
|
||||||
|
controller_.c_str(), axisNo_, functionName_, line_);
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
|
||||||
|
msgPrintControl::msgPrintControl(size_t maxRepetitions) {
|
||||||
|
maxRepetitions_ = maxRepetitions;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool msgPrintControl::shouldBePrinted(msgPrintControlKey &key, bool wantToPrint,
|
||||||
|
asynUser *pasynUser) {
|
||||||
|
|
||||||
|
// Reset the suffix
|
||||||
|
suffix_[0] = 0;
|
||||||
|
|
||||||
|
if (wantToPrint) {
|
||||||
|
/*
|
||||||
|
We want to print the message associated with key -> Check if the number
|
||||||
|
of allowed repetitions is exceeded. If true, inform the user that
|
||||||
|
further output is suppressed.
|
||||||
|
*/
|
||||||
|
if (map_.find(key) != map_.end()) {
|
||||||
|
size_t repetitions = map_[key];
|
||||||
|
if (repetitions < maxRepetitions_) {
|
||||||
|
// Number of allowed repetitions not exceeded -> Printing the
|
||||||
|
// message is ok.
|
||||||
|
map_[key] = repetitions + 1;
|
||||||
|
return true;
|
||||||
|
} else if (repetitions == maxRepetitions_) {
|
||||||
|
// Reached number of allowed repetitions -> Printing the message
|
||||||
|
// is ok, but further trys are rejected.
|
||||||
|
char formattedKey[100] = {0};
|
||||||
|
key.format(formattedKey, sizeof(formattedKey));
|
||||||
|
snprintf(suffix_, sizeof(suffix_),
|
||||||
|
" Further repetition of this error message (key "
|
||||||
|
"\"%s\") is suppressed.",
|
||||||
|
formattedKey);
|
||||||
|
map_[key] = repetitions + 1;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// Exceeded number of allowed repetitions -> Do not print the
|
||||||
|
// message
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Message is not yet in map -> create an entry so it is watched in
|
||||||
|
// the future.
|
||||||
|
map_[key] = 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
We do not want to print the message associated with key -> If the key is
|
||||||
|
part of the map, set the counter back to zero.
|
||||||
|
*/
|
||||||
|
if (map_.find(key) != map_.end()) {
|
||||||
|
if (map_[key] != 0) {
|
||||||
|
if (pasynUser != nullptr) {
|
||||||
|
char formattedKey[100] = {0};
|
||||||
|
key.format(formattedKey, sizeof(formattedKey));
|
||||||
|
asynPrint(
|
||||||
|
pasynUser, ASYN_TRACE_ERROR,
|
||||||
|
"Controller \"%s\", axis %d => %s, line %d\nError "
|
||||||
|
"associated with key \"%s\" has been resolved.\n",
|
||||||
|
key.controller_.c_str(), key.axisNo_, key.functionName_,
|
||||||
|
key.line_, formattedKey);
|
||||||
|
}
|
||||||
|
map_[key] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool msgPrintControl::shouldBePrinted(char *portName, int axisNo,
|
||||||
|
const char *functionName, int line,
|
||||||
|
bool wantToPrint, asynUser *pasynUser) {
|
||||||
|
msgPrintControlKey key =
|
||||||
|
msgPrintControlKey(portName, axisNo, functionName, __LINE__);
|
||||||
|
return shouldBePrinted(key, wantToPrint, pasynUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
void msgPrintControl::resetCount(msgPrintControlKey &key, asynUser *pasynUser) {
|
||||||
|
if (map_.find(key) != map_.end()) {
|
||||||
|
if (map_[key] != 0) {
|
||||||
|
if (pasynUser != nullptr) {
|
||||||
|
char formattedKey[100] = {0};
|
||||||
|
key.format(formattedKey, sizeof(formattedKey));
|
||||||
|
asynPrint(pasynUser, ASYN_TRACE_ERROR,
|
||||||
|
"Controller \"%s\", axis %d => %s, line %d\nError "
|
||||||
|
"associated with key \"%s\" has been resolved.\n",
|
||||||
|
key.controller_.c_str(), key.axisNo_,
|
||||||
|
key.functionName_, key.line_, formattedKey);
|
||||||
|
}
|
||||||
|
map_[key] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *msgPrintControl::getSuffix() { return suffix_; }
|
145
src/msgPrintControl.h
Normal file
145
src/msgPrintControl.h
Normal file
@ -0,0 +1,145 @@
|
|||||||
|
#ifndef msgPrintControl_H
|
||||||
|
#define msgPrintControl_H
|
||||||
|
|
||||||
|
#include <asynDriver.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Class to identify a message print location. See the docstring of
|
||||||
|
* `msgPrintControl` on how to use this key.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class msgPrintControlKey {
|
||||||
|
public:
|
||||||
|
std::string controller_;
|
||||||
|
// -1 is a non-axis specific message
|
||||||
|
int axisNo_;
|
||||||
|
const char *functionName_;
|
||||||
|
int line_;
|
||||||
|
|
||||||
|
msgPrintControlKey(char *controller_, int axisNo, const char *fileName,
|
||||||
|
int line);
|
||||||
|
|
||||||
|
bool operator==(const msgPrintControlKey &other) const {
|
||||||
|
return axisNo_ == other.axisNo_ && line_ == other.line_ &&
|
||||||
|
strcmp(functionName_, other.functionName_) == 0 &&
|
||||||
|
controller_ == other.controller_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void format(char *buffer, size_t bufferSize);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Implementation of the hash functionality for msgPrintControlKey
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
namespace std {
|
||||||
|
template <> struct hash<msgPrintControlKey> {
|
||||||
|
size_t operator()(const msgPrintControlKey &obj) const {
|
||||||
|
// Combine the hashes of the members (x and y)
|
||||||
|
size_t h1 = std::hash<std::string>{}(obj.controller_);
|
||||||
|
size_t h2 = hash<int>{}(obj.axisNo_);
|
||||||
|
size_t h3 = std::hash<const char *>{}(obj.functionName_);
|
||||||
|
size_t h4 = hash<int>{}(obj.line_);
|
||||||
|
// Combine the hashes (simple XOR and shifting technique)
|
||||||
|
return h1 ^ (h2 << 1) ^ (h3 << 2) ^ (h4 << 3);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace std
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Class to control the number of repetitions of error messages
|
||||||
|
*
|
||||||
|
* This class is used to prevent excessive repetitions of identical error
|
||||||
|
* messages. For example, if the communication between a controller and an
|
||||||
|
* axis fails, a corresponding error message is created in each poll. This
|
||||||
|
* could "flood" the IOC shell with noise. To prevent this, this class keeps
|
||||||
|
* track of the number of subsequent error message repetition. Each message is
|
||||||
|
* uniquely identified by "msgPrintControlKey". The function shouldBePrinted
|
||||||
|
* can be used in order to see if a message should be printed or not:
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
* const char* controller = "MCU" // Name of the controller
|
||||||
|
* int axisNo = 0; // Number of the axis
|
||||||
|
* bool wantToPrint = evaluateConditions(...); *
|
||||||
|
* if (msgPrintControl.shouldBePrinted(controller, axisNo, __PRETTY_FUNCTION__,
|
||||||
|
* __LINE__, wantToPrint)) { asynPrint(...)
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
class msgPrintControl {
|
||||||
|
public:
|
||||||
|
msgPrintControl(size_t maxRepetitions);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if the error message associated with "key" has been printed
|
||||||
|
* more than "maxRepetitions_" times in a row. If yes, returns false,
|
||||||
|
* otherwise true. Counter is reset if wantToPrint is false.
|
||||||
|
*
|
||||||
|
* If the conditions for printing a message are met, "wantToPrint" must be
|
||||||
|
* set to true. The function then checks if "maxRepetitions_" has been
|
||||||
|
* exceeded. If yes, the function returns no, indicating that the message
|
||||||
|
* should not be printed. If no, the number of repetitions stored in the map
|
||||||
|
* is incremented and the function returns true, indicating that the message
|
||||||
|
* should be printed.
|
||||||
|
*
|
||||||
|
* If the conditions for printing a message are not met, "wantToPrint" must
|
||||||
|
* be set to false. This resets the map entry.
|
||||||
|
*
|
||||||
|
* @param key Key associated with the message, used to
|
||||||
|
* identify individual messages
|
||||||
|
* @param wantToPrint If the message associated with key should be
|
||||||
|
* printed, this value should be true, otherwise false.
|
||||||
|
* @param pasynUser If the problem has been resolved (wantToPrint =
|
||||||
|
* false), a corresponding status message is printed using the given
|
||||||
|
* asynUser. If this pointer is a nullptr, no message is printed.
|
||||||
|
* @return bool If true, the message should be printed, if
|
||||||
|
* false, it should not.
|
||||||
|
*/
|
||||||
|
bool shouldBePrinted(msgPrintControlKey &key, bool wantToPrint,
|
||||||
|
asynUser *pasynUser);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Like `shouldBePrinted(msgPrintControlKey key, bool wantToPrint)`,
|
||||||
|
* but constructs the key from the first four arguments.
|
||||||
|
*
|
||||||
|
* @param controller_
|
||||||
|
* @param axisNo
|
||||||
|
* @param fileName
|
||||||
|
* @param line
|
||||||
|
* @param wantToPrint
|
||||||
|
* @param pasynUser
|
||||||
|
*/
|
||||||
|
bool shouldBePrinted(char *controller, int axisNo, const char *functionName,
|
||||||
|
int line, bool wantToPrint, asynUser *pasynUser);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Reset the error message count incremented in shouldBePrinted for
|
||||||
|
* the given key
|
||||||
|
*
|
||||||
|
* @param key Key associated with the message, used to
|
||||||
|
* identify individual messages
|
||||||
|
* @param pasynUser If the problem has been resolved (wantToPrint =
|
||||||
|
* false), a corresponding status message is printed using the given
|
||||||
|
* asynUser. If this pointer is a nullptr, no message is printed.
|
||||||
|
*/
|
||||||
|
void resetCount(msgPrintControlKey &key, asynUser *pasynUser);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Maximum number of times a message is printed before it is
|
||||||
|
* suppressed.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
size_t maxRepetitions_;
|
||||||
|
|
||||||
|
char *getSuffix();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unordered_map<msgPrintControlKey, size_t> map_;
|
||||||
|
char suffix_[300] = {0};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
143
src/sinqAxis.cpp
143
src/sinqAxis.cpp
@ -10,17 +10,28 @@ sinqAxis::sinqAxis(class sinqController *pC, int axisNo)
|
|||||||
: asynMotorAxis((asynMotorController *)pC, axisNo), pC_(pC) {
|
: asynMotorAxis((asynMotorController *)pC, axisNo), pC_(pC) {
|
||||||
asynStatus status = asynSuccess;
|
asynStatus status = asynSuccess;
|
||||||
|
|
||||||
initial_poll_ = true;
|
|
||||||
watchdogMovActive_ = false;
|
watchdogMovActive_ = false;
|
||||||
init_poll_counter_ = 0;
|
|
||||||
scaleMovTimeout_ = 2.0;
|
scaleMovTimeout_ = 2.0;
|
||||||
offsetMovTimeout_ = 30;
|
offsetMovTimeout_ = 30;
|
||||||
targetPosition_ = 0.0;
|
targetPosition_ = 0.0;
|
||||||
|
|
||||||
|
// This check is also done in asynMotorAxis, but there the IOC continues
|
||||||
|
// running even though the configuration is incorrect. When failing this
|
||||||
|
// check, the IOC is stopped, since this is definitely a configuration
|
||||||
|
// problem.
|
||||||
|
if ((axisNo < 0) || (axisNo >= pC->numAxes())) {
|
||||||
|
asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR,
|
||||||
|
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
|
||||||
|
"(axis index %d is not in range 0 to %d)\n. Terminating IOC",
|
||||||
|
pC->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, axisNo,
|
||||||
|
pC->numAxes() - 1);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
// Motor is assumed to be enabled
|
// Motor is assumed to be enabled
|
||||||
status = setIntegerParam(pC_->motorEnableRBV_, 1);
|
status = setIntegerParam(pC_->motorEnableRBV(), 1);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
|
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
|
||||||
"(setting a parameter value failed "
|
"(setting a parameter value failed "
|
||||||
"with %s)\n. Terminating IOC",
|
"with %s)\n. Terminating IOC",
|
||||||
@ -30,9 +41,9 @@ sinqAxis::sinqAxis(class sinqController *pC, int axisNo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// By default, motors cannot be disabled
|
// By default, motors cannot be disabled
|
||||||
status = setIntegerParam(pC_->motorCanDisable_, 0);
|
status = setIntegerParam(pC_->motorCanDisable(), 0);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
|
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
|
||||||
"(setting a parameter value failed "
|
"(setting a parameter value failed "
|
||||||
"with %s)\n. Terminating IOC",
|
"with %s)\n. Terminating IOC",
|
||||||
@ -42,9 +53,9 @@ sinqAxis::sinqAxis(class sinqController *pC, int axisNo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Provide a default value for the motor position.
|
// Provide a default value for the motor position.
|
||||||
status = setDoubleParam(pC_->motorPosition_, 0.0);
|
status = setDoubleParam(pC_->motorPosition(), 0.0);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
|
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
|
||||||
"(setting a parameter value failed "
|
"(setting a parameter value failed "
|
||||||
"with %s)\n. Terminating IOC",
|
"with %s)\n. Terminating IOC",
|
||||||
@ -54,9 +65,9 @@ sinqAxis::sinqAxis(class sinqController *pC, int axisNo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We assume that the motor has no status problems initially
|
// We assume that the motor has no status problems initially
|
||||||
status = setIntegerParam(pC_->motorStatusProblem_, 0);
|
status = setIntegerParam(pC_->motorStatusProblem(), 0);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
|
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
|
||||||
"(setting a parameter value failed "
|
"(setting a parameter value failed "
|
||||||
"with %s)\n. Terminating IOC",
|
"with %s)\n. Terminating IOC",
|
||||||
@ -66,9 +77,9 @@ sinqAxis::sinqAxis(class sinqController *pC, int axisNo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set the homing-related flags
|
// Set the homing-related flags
|
||||||
status = setIntegerParam(pC_->motorStatusHome_, 0);
|
status = setIntegerParam(pC_->motorStatusHome(), 0);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
|
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
|
||||||
"(setting a parameter value failed "
|
"(setting a parameter value failed "
|
||||||
"with %s)\n. Terminating IOC",
|
"with %s)\n. Terminating IOC",
|
||||||
@ -76,9 +87,9 @@ sinqAxis::sinqAxis(class sinqController *pC, int axisNo)
|
|||||||
pC_->stringifyAsynStatus(status));
|
pC_->stringifyAsynStatus(status));
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
status = setIntegerParam(pC_->motorStatusHomed_, 0);
|
status = setIntegerParam(pC_->motorStatusHomed(), 0);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
|
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
|
||||||
"(setting a parameter value failed "
|
"(setting a parameter value failed "
|
||||||
"with %s)\n. Terminating IOC",
|
"with %s)\n. Terminating IOC",
|
||||||
@ -86,9 +97,9 @@ sinqAxis::sinqAxis(class sinqController *pC, int axisNo)
|
|||||||
pC_->stringifyAsynStatus(status));
|
pC_->stringifyAsynStatus(status));
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
status = setIntegerParam(pC_->motorStatusAtHome_, 0);
|
status = setIntegerParam(pC_->motorStatusAtHome(), 0);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
|
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
|
||||||
"(setting a parameter value failed "
|
"(setting a parameter value failed "
|
||||||
"with %s)\n. Terminating IOC",
|
"with %s)\n. Terminating IOC",
|
||||||
@ -112,17 +123,17 @@ asynStatus sinqAxis::poll(bool *moving) {
|
|||||||
|
|
||||||
The motorStatusProblem_ field changes the motor record fields SEVR and STAT.
|
The motorStatusProblem_ field changes the motor record fields SEVR and STAT.
|
||||||
*/
|
*/
|
||||||
pl_status = setIntegerParam(pC_->motorStatusProblem_, false);
|
pl_status = setIntegerParam(pC_->motorStatusProblem(), false);
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_", axisNo_,
|
pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_", axisNo_,
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
__PRETTY_FUNCTION__, __LINE__);
|
||||||
}
|
}
|
||||||
pl_status = setIntegerParam(pC_->motorStatusCommsError_, false);
|
pl_status = setIntegerParam(pC_->motorStatusCommsError(), false);
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
pC_->paramLibAccessFailed(pl_status, "motorStatusCommsError_", axisNo_,
|
pC_->paramLibAccessFailed(pl_status, "motorStatusCommsError_", axisNo_,
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
__PRETTY_FUNCTION__, __LINE__);
|
||||||
}
|
}
|
||||||
pl_status = setStringParam(pC_->motorMessageText_, "");
|
pl_status = setStringParam(pC_->motorMessageText(), "");
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
@ -138,20 +149,20 @@ asynStatus sinqAxis::poll(bool *moving) {
|
|||||||
// The poll did not succeed: Something went wrong and the motor has a status
|
// The poll did not succeed: Something went wrong and the motor has a status
|
||||||
// problem.
|
// problem.
|
||||||
if (poll_status != asynSuccess) {
|
if (poll_status != asynSuccess) {
|
||||||
pl_status = setIntegerParam(pC_->motorStatusProblem_, true);
|
pl_status = setIntegerParam(pC_->motorStatusProblem(), true);
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_", axisNo_,
|
pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_", axisNo_,
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
__PRETTY_FUNCTION__, __LINE__);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pl_status = pC_->getIntegerParam(axisNo_, pC_->motorStatusHomed_, &homed);
|
pl_status = pC_->getIntegerParam(axisNo_, pC_->motorStatusHomed(), &homed);
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorStatusHomed_",
|
return pC_->paramLibAccessFailed(pl_status, "motorStatusHomed_",
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
__LINE__);
|
__LINE__);
|
||||||
}
|
}
|
||||||
pl_status = pC_->getIntegerParam(axisNo_, pC_->motorStatusHome_, &homing);
|
pl_status = pC_->getIntegerParam(axisNo_, pC_->motorStatusHome(), &homing);
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorStatusHome_", axisNo_,
|
return pC_->paramLibAccessFailed(pl_status, "motorStatusHome_", axisNo_,
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
__PRETTY_FUNCTION__, __LINE__);
|
||||||
@ -160,19 +171,19 @@ asynStatus sinqAxis::poll(bool *moving) {
|
|||||||
if (homing == 1 && !(*moving)) {
|
if (homing == 1 && !(*moving)) {
|
||||||
|
|
||||||
// Set the homing-related flags
|
// Set the homing-related flags
|
||||||
pl_status = setIntegerParam(pC_->motorStatusHome_, 0);
|
pl_status = setIntegerParam(pC_->motorStatusHome(), 0);
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorStatusHome_",
|
return pC_->paramLibAccessFailed(pl_status, "motorStatusHome_",
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
__LINE__);
|
__LINE__);
|
||||||
}
|
}
|
||||||
pl_status = setIntegerParam(pC_->motorStatusHomed_, 1);
|
pl_status = setIntegerParam(pC_->motorStatusHomed(), 1);
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorStatusHomed_",
|
return pC_->paramLibAccessFailed(pl_status, "motorStatusHomed_",
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
__LINE__);
|
__LINE__);
|
||||||
}
|
}
|
||||||
pl_status = setIntegerParam(pC_->motorStatusAtHome_, 1);
|
pl_status = setIntegerParam(pC_->motorStatusAtHome(), 1);
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorStatusAtHome_",
|
return pC_->paramLibAccessFailed(pl_status, "motorStatusAtHome_",
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
@ -188,14 +199,18 @@ asynStatus sinqAxis::poll(bool *moving) {
|
|||||||
// According to the function documentation of asynMotorAxis::poll, this
|
// According to the function documentation of asynMotorAxis::poll, this
|
||||||
// function should be called at the end of a poll implementation.
|
// function should be called at the end of a poll implementation.
|
||||||
pl_status = callParamCallbacks();
|
pl_status = callParamCallbacks();
|
||||||
if (pl_status != asynSuccess) {
|
bool wantToPrint = pl_status != asynSuccess;
|
||||||
// If we can't communicate with the parameter library, it doesn't make
|
if (pC_->getMsgPrintControl().shouldBePrinted(
|
||||||
// sense to try and upstream this to the user -> Just log the error
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, wantToPrint,
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
pC_->asynUserSelf())) {
|
||||||
|
asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line "
|
"Controller \"%s\", axis %d => %s, line "
|
||||||
"%d:\ncallParamCallbacks failed with %s.\n",
|
"%d:\ncallParamCallbacks failed with %s.%s\n",
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
pC_->stringifyAsynStatus(poll_status));
|
pC_->stringifyAsynStatus(poll_status),
|
||||||
|
pC_->getMsgPrintControl().getSuffix());
|
||||||
|
}
|
||||||
|
if (wantToPrint) {
|
||||||
poll_status = pl_status;
|
poll_status = pl_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,19 +229,19 @@ asynStatus sinqAxis::move(double position, int relative, double minVelocity,
|
|||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
// When a new move is done, the motor is not homed anymore
|
// When a new move is done, the motor is not homed anymore
|
||||||
pl_status = setIntegerParam(pC_->motorStatusHomed_, 0);
|
pl_status = setIntegerParam(pC_->motorStatusHomed(), 0);
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorStatusHomed_",
|
return pC_->paramLibAccessFailed(pl_status, "motorStatusHomed_",
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
__LINE__);
|
__LINE__);
|
||||||
}
|
}
|
||||||
pl_status = setIntegerParam(pC_->motorStatusAtHome_, 0);
|
pl_status = setIntegerParam(pC_->motorStatusAtHome(), 0);
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorStatusAtHome_",
|
return pC_->paramLibAccessFailed(pl_status, "motorStatusAtHome_",
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
__LINE__);
|
__LINE__);
|
||||||
}
|
}
|
||||||
pl_status = pC_->getDoubleParam(axisNo_, pC_->motorRecResolution_,
|
pl_status = pC_->getDoubleParam(axisNo_, pC_->motorRecResolution(),
|
||||||
&motorRecResolution);
|
&motorRecResolution);
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorRecResolution_",
|
return pC_->paramLibAccessFailed(pl_status, "motorRecResolution_",
|
||||||
@ -254,7 +269,7 @@ asynStatus sinqAxis::home(double minVelocity, double maxVelocity,
|
|||||||
|
|
||||||
if (status == asynSuccess) {
|
if (status == asynSuccess) {
|
||||||
|
|
||||||
status = setStringParam(pC_->motorMessageText_, "Homing");
|
status = setStringParam(pC_->motorMessageText(), "Homing");
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(status, "motorMessageText_",
|
return pC_->paramLibAccessFailed(status, "motorMessageText_",
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
@ -262,19 +277,19 @@ asynStatus sinqAxis::home(double minVelocity, double maxVelocity,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set the homing-related flags
|
// Set the homing-related flags
|
||||||
status = setIntegerParam(pC_->motorStatusHome_, 1);
|
status = setIntegerParam(pC_->motorStatusHome(), 1);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(status, "motorStatusHome_",
|
return pC_->paramLibAccessFailed(status, "motorStatusHome_",
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
__LINE__);
|
__LINE__);
|
||||||
}
|
}
|
||||||
status = setIntegerParam(pC_->motorStatusHomed_, 0);
|
status = setIntegerParam(pC_->motorStatusHomed(), 0);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(status, "motorStatusHomed_",
|
return pC_->paramLibAccessFailed(status, "motorStatusHomed_",
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
__LINE__);
|
__LINE__);
|
||||||
}
|
}
|
||||||
status = setIntegerParam(pC_->motorStatusAtHome_, 0);
|
status = setIntegerParam(pC_->motorStatusAtHome(), 0);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(status, "motorStatusAtHome_",
|
return pC_->paramLibAccessFailed(status, "motorStatusAtHome_",
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
@ -286,7 +301,7 @@ asynStatus sinqAxis::home(double minVelocity, double maxVelocity,
|
|||||||
|
|
||||||
} else if (status == asynError) {
|
} else if (status == asynError) {
|
||||||
// asynError means that we tried to home an absolute encoder
|
// asynError means that we tried to home an absolute encoder
|
||||||
status = setStringParam(pC_->motorMessageText_,
|
status = setStringParam(pC_->motorMessageText(),
|
||||||
"Can't home a motor with absolute encoder");
|
"Can't home a motor with absolute encoder");
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(status, "motorMessageText_",
|
return pC_->paramLibAccessFailed(status, "motorMessageText_",
|
||||||
@ -307,6 +322,8 @@ asynStatus sinqAxis::doHome(double minVelocity, double maxVelocity,
|
|||||||
return asynSuccess;
|
return asynSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
asynStatus sinqAxis::reset() { return asynSuccess; }
|
||||||
|
|
||||||
asynStatus sinqAxis::enable(bool on) { return asynSuccess; }
|
asynStatus sinqAxis::enable(bool on) { return asynSuccess; }
|
||||||
|
|
||||||
asynStatus sinqAxis::setVeloFields(double velo, double vbas, double vmax) {
|
asynStatus sinqAxis::setVeloFields(double velo, double vbas, double vmax) {
|
||||||
@ -315,7 +332,7 @@ asynStatus sinqAxis::setVeloFields(double velo, double vbas, double vmax) {
|
|||||||
|
|
||||||
// Can the speed of the motor be varied?
|
// Can the speed of the motor be varied?
|
||||||
status =
|
status =
|
||||||
pC_->getIntegerParam(axisNo_, pC_->motorCanSetSpeed_, &variableSpeed);
|
pC_->getIntegerParam(axisNo_, pC_->motorCanSetSpeed(), &variableSpeed);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(status, "motorCanSetSpeed_", axisNo_,
|
return pC_->paramLibAccessFailed(status, "motorCanSetSpeed_", axisNo_,
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
__PRETTY_FUNCTION__, __LINE__);
|
||||||
@ -324,7 +341,7 @@ asynStatus sinqAxis::setVeloFields(double velo, double vbas, double vmax) {
|
|||||||
|
|
||||||
// Check the inputs and create corresponding error messages
|
// Check the inputs and create corresponding error messages
|
||||||
if (vbas > vmax) {
|
if (vbas > vmax) {
|
||||||
asynPrint(pC_->lowLevelPortUser_, ASYN_TRACE_ERROR,
|
asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nLower speed "
|
"Controller \"%s\", axis %d => %s, line %d:\nLower speed "
|
||||||
"limit vbas=%lf must not be smaller than upper limit "
|
"limit vbas=%lf must not be smaller than upper limit "
|
||||||
"vmax=%lf.\n",
|
"vmax=%lf.\n",
|
||||||
@ -332,7 +349,7 @@ asynStatus sinqAxis::setVeloFields(double velo, double vbas, double vmax) {
|
|||||||
vbas, vmax);
|
vbas, vmax);
|
||||||
|
|
||||||
status = setStringParam(
|
status = setStringParam(
|
||||||
pC_->motorMessageText_,
|
pC_->motorMessageText(),
|
||||||
"Lower speed limit must not be smaller than upper speed limit");
|
"Lower speed limit must not be smaller than upper speed limit");
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(status, "motorMessageText_",
|
return pC_->paramLibAccessFailed(status, "motorMessageText_",
|
||||||
@ -342,14 +359,14 @@ asynStatus sinqAxis::setVeloFields(double velo, double vbas, double vmax) {
|
|||||||
return asynError;
|
return asynError;
|
||||||
}
|
}
|
||||||
if (velo < vbas || velo > vmax) {
|
if (velo < vbas || velo > vmax) {
|
||||||
asynPrint(pC_->lowLevelPortUser_, ASYN_TRACE_ERROR,
|
asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nActual "
|
"Controller \"%s\", axis %d => %s, line %d:\nActual "
|
||||||
"speed velo=%lf must be between lower limit vbas=%lf and "
|
"speed velo=%lf must be between lower limit vbas=%lf and "
|
||||||
"upper limit vmax=%lf.\n",
|
"upper limit vmax=%lf.\n",
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
velo, vbas, vmax);
|
velo, vbas, vmax);
|
||||||
|
|
||||||
status = setStringParam(pC_->motorMessageText_,
|
status = setStringParam(pC_->motorMessageText(),
|
||||||
"Speed is not inside limits");
|
"Speed is not inside limits");
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(status, "motorMessageText_",
|
return pC_->paramLibAccessFailed(status, "motorMessageText_",
|
||||||
@ -359,21 +376,21 @@ asynStatus sinqAxis::setVeloFields(double velo, double vbas, double vmax) {
|
|||||||
return asynError;
|
return asynError;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = pC_->setDoubleParam(axisNo_, pC_->motorVbasFromDriver_, vbas);
|
status = pC_->setDoubleParam(axisNo_, pC_->motorVbasFromDriver(), vbas);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(status, "motorVbasFromDriver_",
|
return pC_->paramLibAccessFailed(status, "motorVbasFromDriver_",
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
__LINE__);
|
__LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
status = pC_->setDoubleParam(axisNo_, pC_->motorVeloFromDriver_, velo);
|
status = pC_->setDoubleParam(axisNo_, pC_->motorVeloFromDriver(), velo);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(status, "motorVeloFromDriver_",
|
return pC_->paramLibAccessFailed(status, "motorVeloFromDriver_",
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
__LINE__);
|
__LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
status = pC_->setDoubleParam(axisNo_, pC_->motorVmaxFromDriver_, vmax);
|
status = pC_->setDoubleParam(axisNo_, pC_->motorVmaxFromDriver(), vmax);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(status, "motorVmaxFromDriver_",
|
return pC_->paramLibAccessFailed(status, "motorVmaxFromDriver_",
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
@ -381,21 +398,21 @@ asynStatus sinqAxis::setVeloFields(double velo, double vbas, double vmax) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Set minimum and maximum speed equal to the set speed
|
// Set minimum and maximum speed equal to the set speed
|
||||||
status = pC_->setDoubleParam(axisNo_, pC_->motorVbasFromDriver_, velo);
|
status = pC_->setDoubleParam(axisNo_, pC_->motorVbasFromDriver(), velo);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(status, "motorVbasFromDriver_",
|
return pC_->paramLibAccessFailed(status, "motorVbasFromDriver_",
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
__LINE__);
|
__LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
status = pC_->setDoubleParam(axisNo_, pC_->motorVeloFromDriver_, velo);
|
status = pC_->setDoubleParam(axisNo_, pC_->motorVeloFromDriver(), velo);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(status, "motorVeloFromDriver_",
|
return pC_->paramLibAccessFailed(status, "motorVeloFromDriver_",
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
__LINE__);
|
__LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
status = pC_->setDoubleParam(axisNo_, pC_->motorVmaxFromDriver_, velo);
|
status = pC_->setDoubleParam(axisNo_, pC_->motorVmaxFromDriver(), velo);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(status, "motorVmaxFromDriver_",
|
return pC_->paramLibAccessFailed(status, "motorVmaxFromDriver_",
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
@ -411,7 +428,7 @@ asynStatus sinqAxis::setAcclField(double accl) {
|
|||||||
return asynError;
|
return asynError;
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus status = setDoubleParam(pC_->motorAcclFromDriver_, accl);
|
asynStatus status = setDoubleParam(pC_->motorAcclFromDriver(), accl);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(status, "motorAcclFromDriver_",
|
return pC_->paramLibAccessFailed(status, "motorAcclFromDriver_",
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
axisNo_, __PRETTY_FUNCTION__,
|
||||||
@ -421,14 +438,14 @@ asynStatus sinqAxis::setAcclField(double accl) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
asynStatus sinqAxis::setWatchdogEnabled(bool enable) {
|
asynStatus sinqAxis::setWatchdogEnabled(bool enable) {
|
||||||
return setIntegerParam(pC_->motorEnableMovWatchdog_, enable);
|
return setIntegerParam(pC_->motorEnableMovWatchdog(), enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus sinqAxis::startMovTimeoutWatchdog() {
|
asynStatus sinqAxis::startMovTimeoutWatchdog() {
|
||||||
asynStatus pl_status;
|
asynStatus pl_status;
|
||||||
int enableMovWatchdog = 0;
|
int enableMovWatchdog = 0;
|
||||||
|
|
||||||
pl_status = pC_->getIntegerParam(axisNo_, pC_->motorEnableMovWatchdog_,
|
pl_status = pC_->getIntegerParam(axisNo_, pC_->motorEnableMovWatchdog(),
|
||||||
&enableMovWatchdog);
|
&enableMovWatchdog);
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorEnableMovWatchdog_",
|
return pC_->paramLibAccessFailed(pl_status, "motorEnableMovWatchdog_",
|
||||||
@ -456,7 +473,7 @@ asynStatus sinqAxis::startMovTimeoutWatchdog() {
|
|||||||
to save the read result to the member variable earlier), since the
|
to save the read result to the member variable earlier), since the
|
||||||
parameter library is updated at a later stage!
|
parameter library is updated at a later stage!
|
||||||
*/
|
*/
|
||||||
pl_status = pC_->getDoubleParam(axisNo_, pC_->motorRecResolution_,
|
pl_status = pC_->getDoubleParam(axisNo_, pC_->motorRecResolution(),
|
||||||
&motorRecResolution);
|
&motorRecResolution);
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorRecResolution_",
|
return pC_->paramLibAccessFailed(pl_status, "motorRecResolution_",
|
||||||
@ -464,7 +481,7 @@ asynStatus sinqAxis::startMovTimeoutWatchdog() {
|
|||||||
__LINE__);
|
__LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
pl_status = pC_->getDoubleParam(axisNo_, pC_->motorPosition_,
|
pl_status = pC_->getDoubleParam(axisNo_, pC_->motorPosition(),
|
||||||
&motorPositionRec);
|
&motorPositionRec);
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorPosition",
|
return pC_->paramLibAccessFailed(pl_status, "motorPosition",
|
||||||
@ -488,7 +505,7 @@ asynStatus sinqAxis::startMovTimeoutWatchdog() {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Read the velocity
|
// Read the velocity
|
||||||
pl_status = pC_->getDoubleParam(axisNo_, pC_->motorVelocity_,
|
pl_status = pC_->getDoubleParam(axisNo_, pC_->motorVelocity(),
|
||||||
&motorVelocityRec);
|
&motorVelocityRec);
|
||||||
|
|
||||||
// Only calculate timeContSpeed if the motorVelocity has been populated
|
// Only calculate timeContSpeed if the motorVelocity has been populated
|
||||||
@ -504,7 +521,7 @@ asynStatus sinqAxis::startMovTimeoutWatchdog() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pl_status =
|
pl_status =
|
||||||
pC_->getDoubleParam(axisNo_, pC_->motorAccel_, &motorAccelRec);
|
pC_->getDoubleParam(axisNo_, pC_->motorAccel(), &motorAccelRec);
|
||||||
if (pl_status == asynSuccess && motorVelocityRec > 0.0 &&
|
if (pl_status == asynSuccess && motorVelocityRec > 0.0 &&
|
||||||
motorAccelRec > 0.0) {
|
motorAccelRec > 0.0) {
|
||||||
|
|
||||||
@ -529,7 +546,7 @@ asynStatus sinqAxis::checkMovTimeoutWatchdog(bool moving) {
|
|||||||
asynStatus pl_status;
|
asynStatus pl_status;
|
||||||
int enableMovWatchdog = 0;
|
int enableMovWatchdog = 0;
|
||||||
|
|
||||||
pl_status = pC_->getIntegerParam(axisNo_, pC_->motorEnableMovWatchdog_,
|
pl_status = pC_->getIntegerParam(axisNo_, pC_->motorEnableMovWatchdog(),
|
||||||
&enableMovWatchdog);
|
&enableMovWatchdog);
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorEnableMovWatchdog_",
|
return pC_->paramLibAccessFailed(pl_status, "motorEnableMovWatchdog_",
|
||||||
@ -546,14 +563,14 @@ asynStatus sinqAxis::checkMovTimeoutWatchdog(bool moving) {
|
|||||||
// Check if the expected time of arrival has been exceeded.
|
// Check if the expected time of arrival has been exceeded.
|
||||||
if (expectedArrivalTime_ < time(NULL)) {
|
if (expectedArrivalTime_ < time(NULL)) {
|
||||||
// Check the watchdog
|
// Check the watchdog
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nExceeded "
|
"Controller \"%s\", axis %d => %s, line %d:\nExceeded "
|
||||||
"expected arrival time %ld (current time is %ld).\n",
|
"expected arrival time %ld (current time is %ld).\n",
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
expectedArrivalTime_, time(NULL));
|
expectedArrivalTime_, time(NULL));
|
||||||
|
|
||||||
pl_status = setStringParam(
|
pl_status = setStringParam(
|
||||||
pC_->motorMessageText_,
|
pC_->motorMessageText(),
|
||||||
"Exceeded expected arrival time. Check if the axis is blocked.");
|
"Exceeded expected arrival time. Check if the axis is blocked.");
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
||||||
@ -561,7 +578,7 @@ asynStatus sinqAxis::checkMovTimeoutWatchdog(bool moving) {
|
|||||||
__LINE__);
|
__LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
pl_status = setIntegerParam(pC_->motorStatusProblem_, true);
|
pl_status = setIntegerParam(pC_->motorStatusProblem(), true);
|
||||||
if (pl_status != asynSuccess) {
|
if (pl_status != asynSuccess) {
|
||||||
pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_", axisNo_,
|
pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_", axisNo_,
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
__PRETTY_FUNCTION__, __LINE__);
|
||||||
@ -695,9 +712,9 @@ asynStatus setScaleMovTimeout(const char *portName, int axisNo,
|
|||||||
sinqAxis *axis = dynamic_cast<sinqAxis *>(asynAxis);
|
sinqAxis *axis = dynamic_cast<sinqAxis *>(asynAxis);
|
||||||
if (axis == nullptr) {
|
if (axis == nullptr) {
|
||||||
errlogPrintf("Controller \"%s\" => %s, line %d:\nAxis %d does not "
|
errlogPrintf("Controller \"%s\" => %s, line %d:\nAxis %d does not "
|
||||||
"exist or is not an "
|
"exist or is not an instance of sinqAxis.",
|
||||||
"instance of sinqAxis.",
|
|
||||||
portName, __PRETTY_FUNCTION__, __LINE__, axisNo);
|
portName, __PRETTY_FUNCTION__, __LINE__, axisNo);
|
||||||
|
return asynError;
|
||||||
}
|
}
|
||||||
|
|
||||||
return axis->setScaleMovTimeout(scaleMovTimeout);
|
return axis->setScaleMovTimeout(scaleMovTimeout);
|
||||||
|
@ -4,8 +4,8 @@ This class extends asynMotorAxis by some features used in SINQ.
|
|||||||
Stefan Mathis, November 2024
|
Stefan Mathis, November 2024
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __SINQDRIVER
|
#ifndef sinqAxis_H
|
||||||
#define __SINQDRIVER
|
#define sinqAxis_H
|
||||||
#include "asynMotorAxis.h"
|
#include "asynMotorAxis.h"
|
||||||
|
|
||||||
class epicsShareClass sinqAxis : public asynMotorAxis {
|
class epicsShareClass sinqAxis : public asynMotorAxis {
|
||||||
@ -160,10 +160,23 @@ class epicsShareClass sinqAxis : public asynMotorAxis {
|
|||||||
virtual asynStatus doHome(double minVelocity, double maxVelocity,
|
virtual asynStatus doHome(double minVelocity, double maxVelocity,
|
||||||
double acceleration, int forwards);
|
double acceleration, int forwards);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This function is called when the PV "$(INSTR)$(M):Reset" is set to
|
||||||
|
* any value. This method should be implemented by a child class of
|
||||||
|
* sinqAxis.
|
||||||
|
*
|
||||||
|
* @return asynStatus
|
||||||
|
*/
|
||||||
|
virtual asynStatus reset();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function enables / disables an axis. It should be implemented
|
* @brief This function enables / disables an axis. It should be implemented
|
||||||
* by a child class of sinqAxis.
|
* by a child class of sinqAxis.
|
||||||
*
|
*
|
||||||
|
* The concrete implementation should (but doesn't need to) follow the
|
||||||
|
* convetion that a value of 0 disables the axis and any other value enables
|
||||||
|
* it.
|
||||||
|
*
|
||||||
* @param on
|
* @param on
|
||||||
* @return asynStatus
|
* @return asynStatus
|
||||||
*/
|
*/
|
||||||
@ -291,12 +304,14 @@ class epicsShareClass sinqAxis : public asynMotorAxis {
|
|||||||
return asynSuccess;
|
return asynSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend class sinqController;
|
/**
|
||||||
|
* @brief Return the axis number of this axis
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
int axisNo() { return axisNo_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool initial_poll_;
|
|
||||||
int init_poll_counter_;
|
|
||||||
|
|
||||||
// Internal variables used in the movement timeout watchdog
|
// Internal variables used in the movement timeout watchdog
|
||||||
time_t expectedArrivalTime_;
|
time_t expectedArrivalTime_;
|
||||||
time_t offsetMovTimeout_;
|
time_t offsetMovTimeout_;
|
||||||
|
@ -47,15 +47,11 @@ sinqController::sinqController(const char *portName,
|
|||||||
0, // No additional callback interfaces beyond those in base class
|
0, // No additional callback interfaces beyond those in base class
|
||||||
ASYN_CANBLOCK | ASYN_MULTIDEVICE,
|
ASYN_CANBLOCK | ASYN_MULTIDEVICE,
|
||||||
1, // autoconnect
|
1, // autoconnect
|
||||||
0,
|
0, 0), // Default priority and stack size
|
||||||
0) // Default priority and stack size
|
msgPrintControl_(4) {
|
||||||
{
|
|
||||||
|
|
||||||
// Initialization of local variables
|
|
||||||
asynStatus status = asynSuccess;
|
asynStatus status = asynSuccess;
|
||||||
|
ipPortUser_ = nullptr;
|
||||||
// Initialization of all member variables
|
|
||||||
lowLevelPortUser_ = nullptr;
|
|
||||||
|
|
||||||
// Initial values for the average timeout mechanism, can be overwritten
|
// Initial values for the average timeout mechanism, can be overwritten
|
||||||
// later by a FFI function
|
// later by a FFI function
|
||||||
@ -78,8 +74,8 @@ sinqController::sinqController(const char *portName,
|
|||||||
We try to connect to the port via the port name provided by the constructor.
|
We try to connect to the port via the port name provided by the constructor.
|
||||||
If this fails, the function is terminated via exit.
|
If this fails, the function is terminated via exit.
|
||||||
*/
|
*/
|
||||||
pasynOctetSyncIO->connect(ipPortConfigName, 0, &lowLevelPortUser_, NULL);
|
pasynOctetSyncIO->connect(ipPortConfigName, 0, &ipPortUser_, NULL);
|
||||||
if (status != asynSuccess || lowLevelPortUser_ == nullptr) {
|
if (status != asynSuccess || ipPortUser_ == nullptr) {
|
||||||
errlogPrintf("Controller \"%s\" => %s, line %d:\nFATAL ERROR (cannot "
|
errlogPrintf("Controller \"%s\" => %s, line %d:\nFATAL ERROR (cannot "
|
||||||
"connect to MCU controller).\n"
|
"connect to MCU controller).\n"
|
||||||
"Terminating IOC",
|
"Terminating IOC",
|
||||||
@ -113,6 +109,16 @@ sinqController::sinqController(const char *portName,
|
|||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status = createParam("MOTOR_RESET", asynParamInt32, &motorReset_);
|
||||||
|
if (status != asynSuccess) {
|
||||||
|
asynPrint(this->pasynUserSelf, 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);
|
||||||
|
}
|
||||||
|
|
||||||
status = createParam("MOTOR_ENABLE_RBV", asynParamInt32, &motorEnableRBV_);
|
status = createParam("MOTOR_ENABLE_RBV", asynParamInt32, &motorEnableRBV_);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
@ -268,12 +274,22 @@ sinqController::sinqController(const char *portName,
|
|||||||
}
|
}
|
||||||
|
|
||||||
sinqController::~sinqController(void) {
|
sinqController::~sinqController(void) {
|
||||||
/*
|
|
||||||
Cleanup of the memory allocated in the asynMotorController constructor
|
// Free all axes
|
||||||
*/
|
for (int axisNo = 0; axisNo < numAxes_; axisNo++) {
|
||||||
|
if (pAxes_[axisNo] != nullptr) {
|
||||||
|
delete pAxes_[axisNo];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup of the array allocated in the asynMotorController constructor
|
||||||
free(this->pAxes_);
|
free(this->pAxes_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
msgPrintControl &sinqController::getMsgPrintControl() {
|
||||||
|
return msgPrintControl_;
|
||||||
|
}
|
||||||
|
|
||||||
asynStatus sinqController::writeInt32(asynUser *pasynUser, epicsInt32 value) {
|
asynStatus sinqController::writeInt32(asynUser *pasynUser, epicsInt32 value) {
|
||||||
int function = pasynUser->reason;
|
int function = pasynUser->reason;
|
||||||
|
|
||||||
@ -281,17 +297,22 @@ asynStatus sinqController::writeInt32(asynUser *pasynUser, epicsInt32 value) {
|
|||||||
|
|
||||||
asynMotorAxis *asynAxis = getAxis(pasynUser);
|
asynMotorAxis *asynAxis = getAxis(pasynUser);
|
||||||
sinqAxis *axis = dynamic_cast<sinqAxis *>(asynAxis);
|
sinqAxis *axis = dynamic_cast<sinqAxis *>(asynAxis);
|
||||||
|
|
||||||
if (axis == nullptr) {
|
if (axis == nullptr) {
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nAxis is not an "
|
"Controller \"%s\", axis %d => %s, line %d:\nAxis is not an "
|
||||||
"instance of sinqAxis",
|
"instance of sinqAxis",
|
||||||
portName, axis->axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
portName, axis->axisNo(), __PRETTY_FUNCTION__, __LINE__);
|
||||||
return asynError;
|
return asynError;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle custom PVs
|
// Handle custom PVs
|
||||||
if (function == motorEnable_) {
|
if (function == motorEnable_) {
|
||||||
return axis->enable(value != 0);
|
return axis->enable(value != 0);
|
||||||
|
} else if (function == motorReset_) {
|
||||||
|
return axis->reset();
|
||||||
|
} else if (function == motorForceStop_) {
|
||||||
|
return axis->stop(0.0);
|
||||||
} else {
|
} else {
|
||||||
return asynMotorController::writeInt32(pasynUser, value);
|
return asynMotorController::writeInt32(pasynUser, value);
|
||||||
}
|
}
|
||||||
@ -299,21 +320,22 @@ asynStatus sinqController::writeInt32(asynUser *pasynUser, epicsInt32 value) {
|
|||||||
|
|
||||||
asynStatus sinqController::readInt32(asynUser *pasynUser, epicsInt32 *value) {
|
asynStatus sinqController::readInt32(asynUser *pasynUser, epicsInt32 *value) {
|
||||||
|
|
||||||
// Casting into a sinqAxis is necessary to get access to the field axisNo_
|
// Casting into a sinqAxis is necessary to get access to the field axisNo()
|
||||||
asynMotorAxis *asynAxis = getAxis(pasynUser);
|
asynMotorAxis *asynAxis = getAxis(pasynUser);
|
||||||
sinqAxis *axis = dynamic_cast<sinqAxis *>(asynAxis);
|
sinqAxis *axis = dynamic_cast<sinqAxis *>(asynAxis);
|
||||||
|
|
||||||
if (axis == nullptr) {
|
if (axis == nullptr) {
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nAxis is not an "
|
"Controller \"%s\", axis %d => %s, line %d:\nAxis is not an "
|
||||||
"instance of sinqAxis",
|
"instance of sinqAxis.\n",
|
||||||
portName, axis->axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
portName, axis->axisNo(), __PRETTY_FUNCTION__, __LINE__);
|
||||||
return asynError;
|
return asynError;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pasynUser->reason == motorEnableRBV_) {
|
if (pasynUser->reason == motorEnableRBV_) {
|
||||||
return getIntegerParam(axis->axisNo_, motorEnableRBV_, value);
|
return getIntegerParam(axis->axisNo(), motorEnableRBV_, value);
|
||||||
} else if (pasynUser->reason == motorCanDisable_) {
|
} else if (pasynUser->reason == motorCanDisable_) {
|
||||||
return getIntegerParam(axis->axisNo_, motorCanDisable_, value);
|
return getIntegerParam(axis->axisNo(), motorCanDisable_, value);
|
||||||
} else {
|
} else {
|
||||||
return asynMotorController::readInt32(pasynUser, value);
|
return asynMotorController::readInt32(pasynUser, value);
|
||||||
}
|
}
|
||||||
@ -323,13 +345,13 @@ asynStatus sinqController::errMsgCouldNotParseResponse(const char *command,
|
|||||||
const char *response,
|
const char *response,
|
||||||
int axisNo,
|
int axisNo,
|
||||||
const char *functionName,
|
const char *functionName,
|
||||||
int lineNumber) {
|
int line) {
|
||||||
asynStatus pl_status = asynSuccess;
|
asynStatus pl_status = asynSuccess;
|
||||||
|
|
||||||
asynPrint(lowLevelPortUser_, ASYN_TRACE_ERROR,
|
asynPrint(ipPortUser_, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nCould not interpret "
|
"Controller \"%s\", axis %d => %s, line %d:\nCould not interpret "
|
||||||
"response \"%s\" for command \"%s\".\n",
|
"response \"%s\" for command \"%s\".\n",
|
||||||
portName, axisNo, functionName, lineNumber, response, command);
|
portName, axisNo, functionName, line, response, command);
|
||||||
|
|
||||||
pl_status = setStringParam(
|
pl_status = setStringParam(
|
||||||
motorMessageText_,
|
motorMessageText_,
|
||||||
@ -352,16 +374,17 @@ asynStatus sinqController::paramLibAccessFailed(asynStatus status,
|
|||||||
const char *parameter,
|
const char *parameter,
|
||||||
int axisNo,
|
int axisNo,
|
||||||
const char *functionName,
|
const char *functionName,
|
||||||
int lineNumber) {
|
int line) {
|
||||||
|
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
// Log the error message and try to propagate it. If propagating fails,
|
asynPrint(ipPortUser_, ASYN_TRACE_ERROR,
|
||||||
// there is nothing we can do here anyway.
|
|
||||||
asynPrint(lowLevelPortUser_, ASYN_TRACE_ERROR,
|
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\n Accessing the "
|
"Controller \"%s\", axis %d => %s, line %d:\n Accessing the "
|
||||||
"parameter library failed for parameter %s with error %s.\n",
|
"parameter library failed for parameter %s with error %s.\n",
|
||||||
portName, axisNo, functionName, lineNumber, parameter,
|
portName, axisNo, functionName, line, parameter,
|
||||||
stringifyAsynStatus(status));
|
stringifyAsynStatus(status));
|
||||||
|
|
||||||
|
// Log the error message and try to propagate it. If propagating fails,
|
||||||
|
// there is nothing we can do here anyway.
|
||||||
setStringParam(motorMessageText_,
|
setStringParam(motorMessageText_,
|
||||||
"Accessing paramLib failed. Please call the support.");
|
"Accessing paramLib failed. Please call the support.");
|
||||||
}
|
}
|
||||||
@ -391,18 +414,24 @@ asynStatus sinqController::checkComTimeoutWatchdog(int axisNo,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if the maximum allowed number of events has been exceeded
|
// Check if the maximum allowed number of events has been exceeded
|
||||||
if (timeoutEvents_.size() > maxNumberTimeouts_) {
|
bool wantToPrint = timeoutEvents_.size() > maxNumberTimeouts_;
|
||||||
|
|
||||||
snprintf(motorMessage, motorMessageSize,
|
|
||||||
"More than %ld communication timeouts in %ld seconds. Please "
|
|
||||||
"call the support.",
|
|
||||||
maxNumberTimeouts_, comTimeoutWindow_);
|
|
||||||
|
|
||||||
|
if (msgPrintControl_.shouldBePrinted(portName, axisNo, __PRETTY_FUNCTION__,
|
||||||
|
__LINE__, wantToPrint,
|
||||||
|
pasynUserSelf)) {
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nMore than %ld "
|
"Controller \"%s\", axis %d => %s, line %d:\nMore than %ld "
|
||||||
"communication timeouts in %ld "
|
"communication timeouts in %ld "
|
||||||
"seconds\n",
|
"seconds.%s\n",
|
||||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
maxNumberTimeouts_, comTimeoutWindow_,
|
||||||
|
msgPrintControl_.getSuffix());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wantToPrint) {
|
||||||
|
snprintf(motorMessage, motorMessageSize,
|
||||||
|
"More than %ld communication timeouts in %ld seconds. Please "
|
||||||
|
"call the support.",
|
||||||
maxNumberTimeouts_, comTimeoutWindow_);
|
maxNumberTimeouts_, comTimeoutWindow_);
|
||||||
|
|
||||||
paramLibStatus = setIntegerParam(motorStatusCommsError_, 1);
|
paramLibStatus = setIntegerParam(motorStatusCommsError_, 1);
|
||||||
@ -423,12 +452,12 @@ asynStatus sinqController::checkComTimeoutWatchdog(sinqAxis *axis) {
|
|||||||
char motorMessage[200] = {0};
|
char motorMessage[200] = {0};
|
||||||
|
|
||||||
asynStatus status =
|
asynStatus status =
|
||||||
checkComTimeoutWatchdog(axis->axisNo_, motorMessage, 200);
|
checkComTimeoutWatchdog(axis->axisNo(), motorMessage, 200);
|
||||||
if (status == asynError) {
|
if (status == asynError) {
|
||||||
status = axis->setStringParam(motorMessageText_, motorMessage);
|
status = axis->setStringParam(motorMessageText_, motorMessage);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return paramLibAccessFailed(status, "motorMessageText_",
|
return paramLibAccessFailed(status, "motorMessageText_",
|
||||||
axis->axisNo_, __PRETTY_FUNCTION__,
|
axis->axisNo(), __PRETTY_FUNCTION__,
|
||||||
__LINE__);
|
__LINE__);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -475,13 +504,13 @@ asynStatus sinqController::checkMaxSubsequentTimeouts(int timeoutNo,
|
|||||||
|
|
||||||
char motorMessage[200] = {0};
|
char motorMessage[200] = {0};
|
||||||
|
|
||||||
asynStatus status =
|
asynStatus status = checkMaxSubsequentTimeouts(axis->axisNo(), timeoutNo,
|
||||||
checkMaxSubsequentTimeouts(axis->axisNo_, timeoutNo, motorMessage, 200);
|
motorMessage, 200);
|
||||||
if (status == asynError) {
|
if (status == asynError) {
|
||||||
status = axis->setStringParam(motorMessageText_, motorMessage);
|
status = axis->setStringParam(motorMessageText_, motorMessage);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
return paramLibAccessFailed(status, "motorMessageText_",
|
return paramLibAccessFailed(status, "motorMessageText_",
|
||||||
axis->axisNo_, __PRETTY_FUNCTION__,
|
axis->axisNo(), __PRETTY_FUNCTION__,
|
||||||
__LINE__);
|
__LINE__);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -617,9 +646,9 @@ asynStatus setMaxSubsequentTimeouts(const char *portName,
|
|||||||
if (ptr == nullptr) {
|
if (ptr == nullptr) {
|
||||||
/*
|
/*
|
||||||
We can't use asynPrint here since this macro would require us
|
We can't use asynPrint here since this macro would require us
|
||||||
to get a lowLevelPortUser_ from a pointer to an asynPortDriver.
|
to get a ipPortUser_ from a pointer to an asynPortDriver.
|
||||||
However, the given pointer is a nullptr and therefore doesn't
|
However, the given pointer is a nullptr and therefore doesn't
|
||||||
have a lowLevelPortUser_! printf is an EPICS alternative which
|
have a ipPortUser_! printf is an EPICS alternative which
|
||||||
works w/o that, but doesn't offer the comfort provided
|
works w/o that, but doesn't offer the comfort provided
|
||||||
by the asynTrace-facility
|
by the asynTrace-facility
|
||||||
*/
|
*/
|
||||||
|
@ -5,11 +5,13 @@ README.md for details.
|
|||||||
Stefan Mathis, November 2024
|
Stefan Mathis, November 2024
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __sinqController
|
#ifndef sinqController_H
|
||||||
#define __sinqController
|
#define sinqController_H
|
||||||
#include "asynMotorController.h"
|
#include "asynMotorController.h"
|
||||||
|
#include "msgPrintControl.h"
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <initHooks.h>
|
#include <initHooks.h>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
#define motorMessageIsFromDriverString "MOTOR_MESSAGE_DRIVER"
|
#define motorMessageIsFromDriverString "MOTOR_MESSAGE_DRIVER"
|
||||||
#define motorMessageTextString "MOTOR_MESSAGE_TEXT"
|
#define motorMessageTextString "MOTOR_MESSAGE_TEXT"
|
||||||
@ -88,13 +90,13 @@ class epicsShareClass sinqController : public asynMotorController {
|
|||||||
error messages.
|
error messages.
|
||||||
* @param functionName Name of the caller function. It is recommended
|
* @param functionName Name of the caller function. It is recommended
|
||||||
to use a macro, e.g. __func__ or __PRETTY_FUNCTION__.
|
to use a macro, e.g. __func__ or __PRETTY_FUNCTION__.
|
||||||
* @param lineNumber Source code line where this function is
|
* @param line Source code line where this function is
|
||||||
called. It is recommended to use a macro, e.g. __LINE__.
|
called. It is recommended to use a macro, e.g. __LINE__.
|
||||||
* @return asynStatus Returns input status.
|
* @return asynStatus Returns input status.
|
||||||
*/
|
*/
|
||||||
asynStatus paramLibAccessFailed(asynStatus status, const char *parameter,
|
asynStatus paramLibAccessFailed(asynStatus status, const char *parameter,
|
||||||
int axisNo, const char *functionName,
|
int axisNo, const char *functionName,
|
||||||
int lineNumber);
|
int line);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Error handling in case parsing a command response failed.
|
* @brief Error handling in case parsing a command response failed.
|
||||||
@ -109,14 +111,13 @@ class epicsShareClass sinqController : public asynMotorController {
|
|||||||
* @param axisNo_ Axis where the problem occurred
|
* @param axisNo_ Axis where the problem occurred
|
||||||
* @param functionName Name of the caller function. It is recommended
|
* @param functionName Name of the caller function. It is recommended
|
||||||
to use a macro, e.g. __func__ or __PRETTY_FUNCTION__.
|
to use a macro, e.g. __func__ or __PRETTY_FUNCTION__.
|
||||||
* @param lineNumber Source code line where this function is
|
* @param line Source code line where this function is
|
||||||
called. It is recommended to use a macro, e.g. __LINE__.
|
called. It is recommended to use a macro, e.g. __LINE__.
|
||||||
* @return asynStatus Returns asynError.
|
* @return asynStatus Returns asynError.
|
||||||
*/
|
*/
|
||||||
asynStatus errMsgCouldNotParseResponse(const char *command,
|
asynStatus errMsgCouldNotParseResponse(const char *command,
|
||||||
const char *response, int axisNo,
|
const char *response, int axisNo,
|
||||||
const char *functionName,
|
const char *functionName, int line);
|
||||||
int lineNumber);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Convert an asynStatus into a descriptive string.
|
* @brief Convert an asynStatus into a descriptive string.
|
||||||
@ -213,13 +214,99 @@ class epicsShareClass sinqController : public asynMotorController {
|
|||||||
return asynSuccess;
|
return asynSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend class sinqAxis;
|
/**
|
||||||
|
* @brief Get a reference to the map used to control the maximum number of
|
||||||
|
* message repetitions. See the documentation of printRepetitionWatchdog in
|
||||||
|
* msgPrintControl.h for details.
|
||||||
|
*/
|
||||||
|
msgPrintControl &getMsgPrintControl();
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
// Public getters for protected members
|
||||||
|
|
||||||
|
// Accessors for double parameters
|
||||||
|
int motorMoveRel() { return motorMoveRel_; }
|
||||||
|
int motorMoveAbs() { return motorMoveAbs_; }
|
||||||
|
int motorMoveVel() { return motorMoveVel_; }
|
||||||
|
int motorHome() { return motorHome_; }
|
||||||
|
int motorStop() { return motorStop_; }
|
||||||
|
int motorVelocity() { return motorVelocity_; }
|
||||||
|
int motorVelBase() { return motorVelBase_; }
|
||||||
|
int motorAccel() { return motorAccel_; }
|
||||||
|
int motorPosition() { return motorPosition_; }
|
||||||
|
int motorEncoderPosition() { return motorEncoderPosition_; }
|
||||||
|
int motorDeferMoves() { return motorDeferMoves_; }
|
||||||
|
int motorMoveToHome() { return motorMoveToHome_; }
|
||||||
|
int motorResolution() { return motorResolution_; }
|
||||||
|
int motorEncoderRatio() { return motorEncoderRatio_; }
|
||||||
|
int motorPGain() { return motorPGain_; }
|
||||||
|
int motorIGain() { return motorIGain_; }
|
||||||
|
int motorDGain() { return motorDGain_; }
|
||||||
|
int motorHighLimit() { return motorHighLimit_; }
|
||||||
|
int motorLowLimit() { return motorLowLimit_; }
|
||||||
|
int motorClosedLoop() { return motorClosedLoop_; }
|
||||||
|
int motorPowerAutoOnOff() { return motorPowerAutoOnOff_; }
|
||||||
|
int motorPowerOnDelay() { return motorPowerOnDelay_; }
|
||||||
|
int motorPowerOffDelay() { return motorPowerOffDelay_; }
|
||||||
|
int motorPowerOffFraction() { return motorPowerOffFraction_; }
|
||||||
|
int motorPostMoveDelay() { return motorPostMoveDelay_; }
|
||||||
|
int motorStatus() { return motorStatus_; }
|
||||||
|
int motorUpdateStatus() { return motorUpdateStatus_; }
|
||||||
|
|
||||||
|
// Accessors for sztatus bits (integers)
|
||||||
|
int motorStatusDirection() { return motorStatusDirection_; }
|
||||||
|
int motorStatusDone() { return motorStatusDone_; }
|
||||||
|
int motorStatusHighLimit() { return motorStatusHighLimit_; }
|
||||||
|
int motorStatusAtHome() { return motorStatusAtHome_; }
|
||||||
|
int motorStatusSlip() { return motorStatusSlip_; }
|
||||||
|
int motorStatusPowerOn() { return motorStatusPowerOn_; }
|
||||||
|
int motorStatusFollowingError() { return motorStatusFollowingError_; }
|
||||||
|
int motorStatusHome() { return motorStatusHome_; }
|
||||||
|
int motorStatusHasEncoder() { return motorStatusHasEncoder_; }
|
||||||
|
int motorStatusProblem() { return motorStatusProblem_; }
|
||||||
|
int motorStatusMoving() { return motorStatusMoving_; }
|
||||||
|
int motorStatusGainSupport() { return motorStatusGainSupport_; }
|
||||||
|
int motorStatusCommsError() { return motorStatusCommsError_; }
|
||||||
|
int motorStatusLowLimit() { return motorStatusLowLimit_; }
|
||||||
|
int motorStatusHomed() { return motorStatusHomed_; }
|
||||||
|
|
||||||
|
// Parameters for passing additional motor record information to the driver
|
||||||
|
int motorRecResolution() { return motorRecResolution_; }
|
||||||
|
int motorRecDirection() { return motorRecDirection_; }
|
||||||
|
int motorRecOffset() { return motorRecOffset_; }
|
||||||
|
|
||||||
|
// Accessors for additional PVs defined in sinqController
|
||||||
|
int motorMessageText() { return motorMessageText_; }
|
||||||
|
int motorReset() { return motorReset_; }
|
||||||
|
int motorEnable() { return motorEnable_; }
|
||||||
|
int motorEnableRBV() { return motorEnableRBV_; }
|
||||||
|
int motorCanDisable() { return motorCanDisable_; }
|
||||||
|
int motorEnableMovWatchdog() { return motorEnableMovWatchdog_; }
|
||||||
|
int motorCanSetSpeed() { return motorCanSetSpeed_; }
|
||||||
|
int motorLimitsOffset() { return motorLimitsOffset_; }
|
||||||
|
int motorForceStop() { return motorForceStop_; }
|
||||||
|
int motorVeloFromDriver() { return motorVeloFromDriver_; }
|
||||||
|
int motorVbasFromDriver() { return motorVbasFromDriver_; }
|
||||||
|
int motorVmaxFromDriver() { return motorVmaxFromDriver_; }
|
||||||
|
int motorAcclFromDriver() { return motorAcclFromDriver_; }
|
||||||
|
int motorHighLimitFromDriver() { return motorHighLimitFromDriver_; }
|
||||||
|
int motorLowLimitFromDriver() { return motorLowLimitFromDriver_; }
|
||||||
|
int encoderType() { return encoderType_; }
|
||||||
|
|
||||||
|
// Additional members
|
||||||
|
int numAxes() { return numAxes_; }
|
||||||
|
asynUser *asynUserSelf() { return pasynUserSelf; }
|
||||||
|
asynUser *ipPortUser() { return ipPortUser_; }
|
||||||
|
|
||||||
|
// =========================================================================
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
asynUser *lowLevelPortUser_;
|
// Pointer to the port user which is specified by the char array
|
||||||
|
// ipPortConfigName in the constructor
|
||||||
|
asynUser *ipPortUser_;
|
||||||
double movingPollPeriod_;
|
double movingPollPeriod_;
|
||||||
double idlePollPeriod_;
|
double idlePollPeriod_;
|
||||||
|
msgPrintControl msgPrintControl_;
|
||||||
|
|
||||||
// Internal variables used in the communication timeout frequency watchdog
|
// Internal variables used in the communication timeout frequency watchdog
|
||||||
time_t comTimeoutWindow_; // Size of the time window
|
time_t comTimeoutWindow_; // Size of the time window
|
||||||
@ -235,6 +322,7 @@ class epicsShareClass sinqController : public asynMotorController {
|
|||||||
|
|
||||||
#define FIRST_SINQMOTOR_PARAM motorMessageText_
|
#define FIRST_SINQMOTOR_PARAM motorMessageText_
|
||||||
int motorMessageText_;
|
int motorMessageText_;
|
||||||
|
int motorReset_;
|
||||||
int motorEnable_;
|
int motorEnable_;
|
||||||
int motorEnableRBV_;
|
int motorEnableRBV_;
|
||||||
int motorCanDisable_;
|
int motorCanDisable_;
|
||||||
|
Reference in New Issue
Block a user