Compare commits
5 Commits
07cad131a4
...
C804_drive
Author | SHA1 | Date | |
---|---|---|---|
9ca5af4507 | |||
4272ed2f50 | |||
87b7bece94 | |||
36b6e8b991 | |||
001b712900 |
236
.clang-format
236
.clang-format
@ -1,236 +0,0 @@
|
|||||||
---
|
|
||||||
Language: Cpp
|
|
||||||
# BasedOnStyle: LLVM
|
|
||||||
AccessModifierOffset: -2
|
|
||||||
AlignAfterOpenBracket: Align
|
|
||||||
AlignArrayOfStructures: None
|
|
||||||
AlignConsecutiveAssignments:
|
|
||||||
Enabled: false
|
|
||||||
AcrossEmptyLines: false
|
|
||||||
AcrossComments: false
|
|
||||||
AlignCompound: false
|
|
||||||
PadOperators: true
|
|
||||||
AlignConsecutiveBitFields:
|
|
||||||
Enabled: false
|
|
||||||
AcrossEmptyLines: false
|
|
||||||
AcrossComments: false
|
|
||||||
AlignCompound: false
|
|
||||||
PadOperators: false
|
|
||||||
AlignConsecutiveDeclarations:
|
|
||||||
Enabled: false
|
|
||||||
AcrossEmptyLines: false
|
|
||||||
AcrossComments: false
|
|
||||||
AlignCompound: false
|
|
||||||
PadOperators: false
|
|
||||||
AlignConsecutiveMacros:
|
|
||||||
Enabled: false
|
|
||||||
AcrossEmptyLines: false
|
|
||||||
AcrossComments: false
|
|
||||||
AlignCompound: false
|
|
||||||
PadOperators: false
|
|
||||||
AlignConsecutiveShortCaseStatements:
|
|
||||||
Enabled: false
|
|
||||||
AcrossEmptyLines: false
|
|
||||||
AcrossComments: false
|
|
||||||
AlignCaseColons: false
|
|
||||||
AlignEscapedNewlines: Right
|
|
||||||
AlignOperands: Align
|
|
||||||
AlignTrailingComments:
|
|
||||||
Kind: Always
|
|
||||||
OverEmptyLines: 0
|
|
||||||
AllowAllArgumentsOnNextLine: true
|
|
||||||
AllowAllParametersOfDeclarationOnNextLine: true
|
|
||||||
AllowShortBlocksOnASingleLine: Never
|
|
||||||
AllowShortCaseLabelsOnASingleLine: false
|
|
||||||
AllowShortEnumsOnASingleLine: true
|
|
||||||
AllowShortFunctionsOnASingleLine: All
|
|
||||||
AllowShortIfStatementsOnASingleLine: Never
|
|
||||||
AllowShortLambdasOnASingleLine: All
|
|
||||||
AllowShortLoopsOnASingleLine: false
|
|
||||||
AlwaysBreakAfterDefinitionReturnType: None
|
|
||||||
AlwaysBreakAfterReturnType: None
|
|
||||||
AlwaysBreakBeforeMultilineStrings: false
|
|
||||||
AlwaysBreakTemplateDeclarations: MultiLine
|
|
||||||
AttributeMacros:
|
|
||||||
- __capability
|
|
||||||
BinPackArguments: true
|
|
||||||
BinPackParameters: true
|
|
||||||
BitFieldColonSpacing: Both
|
|
||||||
BraceWrapping:
|
|
||||||
AfterCaseLabel: false
|
|
||||||
AfterClass: false
|
|
||||||
AfterControlStatement: Never
|
|
||||||
AfterEnum: false
|
|
||||||
AfterExternBlock: false
|
|
||||||
AfterFunction: false
|
|
||||||
AfterNamespace: false
|
|
||||||
AfterObjCDeclaration: false
|
|
||||||
AfterStruct: false
|
|
||||||
AfterUnion: false
|
|
||||||
BeforeCatch: false
|
|
||||||
BeforeElse: false
|
|
||||||
BeforeLambdaBody: false
|
|
||||||
BeforeWhile: false
|
|
||||||
IndentBraces: false
|
|
||||||
SplitEmptyFunction: true
|
|
||||||
SplitEmptyRecord: true
|
|
||||||
SplitEmptyNamespace: true
|
|
||||||
BreakAfterAttributes: Never
|
|
||||||
BreakAfterJavaFieldAnnotations: false
|
|
||||||
BreakArrays: true
|
|
||||||
BreakBeforeBinaryOperators: None
|
|
||||||
BreakBeforeConceptDeclarations: Always
|
|
||||||
BreakBeforeBraces: Attach
|
|
||||||
BreakBeforeInlineASMColon: OnlyMultiline
|
|
||||||
BreakBeforeTernaryOperators: true
|
|
||||||
BreakConstructorInitializers: BeforeColon
|
|
||||||
BreakInheritanceList: BeforeColon
|
|
||||||
BreakStringLiterals: true
|
|
||||||
ColumnLimit: 80
|
|
||||||
CommentPragmas: '^ IWYU pragma:'
|
|
||||||
CompactNamespaces: false
|
|
||||||
ConstructorInitializerIndentWidth: 4
|
|
||||||
ContinuationIndentWidth: 4
|
|
||||||
Cpp11BracedListStyle: true
|
|
||||||
DerivePointerAlignment: false
|
|
||||||
DisableFormat: false
|
|
||||||
EmptyLineAfterAccessModifier: Never
|
|
||||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
|
||||||
ExperimentalAutoDetectBinPacking: false
|
|
||||||
FixNamespaceComments: true
|
|
||||||
ForEachMacros:
|
|
||||||
- foreach
|
|
||||||
- Q_FOREACH
|
|
||||||
- BOOST_FOREACH
|
|
||||||
IfMacros:
|
|
||||||
- KJ_IF_MAYBE
|
|
||||||
IncludeBlocks: Preserve
|
|
||||||
IncludeCategories:
|
|
||||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
|
||||||
Priority: 2
|
|
||||||
SortPriority: 0
|
|
||||||
CaseSensitive: false
|
|
||||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
|
||||||
Priority: 3
|
|
||||||
SortPriority: 0
|
|
||||||
CaseSensitive: false
|
|
||||||
- Regex: '.*'
|
|
||||||
Priority: 1
|
|
||||||
SortPriority: 0
|
|
||||||
CaseSensitive: false
|
|
||||||
IncludeIsMainRegex: '(Test)?$'
|
|
||||||
IncludeIsMainSourceRegex: ''
|
|
||||||
IndentAccessModifiers: false
|
|
||||||
IndentCaseBlocks: false
|
|
||||||
IndentCaseLabels: false
|
|
||||||
IndentExternBlock: AfterExternBlock
|
|
||||||
IndentGotoLabels: true
|
|
||||||
IndentPPDirectives: None
|
|
||||||
IndentRequiresClause: true
|
|
||||||
IndentWidth: 4
|
|
||||||
IndentWrappedFunctionNames: false
|
|
||||||
InsertBraces: false
|
|
||||||
InsertNewlineAtEOF: false
|
|
||||||
InsertTrailingCommas: None
|
|
||||||
IntegerLiteralSeparator:
|
|
||||||
Binary: 0
|
|
||||||
BinaryMinDigits: 0
|
|
||||||
Decimal: 0
|
|
||||||
DecimalMinDigits: 0
|
|
||||||
Hex: 0
|
|
||||||
HexMinDigits: 0
|
|
||||||
JavaScriptQuotes: Leave
|
|
||||||
JavaScriptWrapImports: true
|
|
||||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
|
||||||
KeepEmptyLinesAtEOF: false
|
|
||||||
LambdaBodyIndentation: Signature
|
|
||||||
LineEnding: DeriveLF
|
|
||||||
MacroBlockBegin: ''
|
|
||||||
MacroBlockEnd: ''
|
|
||||||
MaxEmptyLinesToKeep: 1
|
|
||||||
NamespaceIndentation: None
|
|
||||||
ObjCBinPackProtocolList: Auto
|
|
||||||
ObjCBlockIndentWidth: 2
|
|
||||||
ObjCBreakBeforeNestedBlockParam: true
|
|
||||||
ObjCSpaceAfterProperty: false
|
|
||||||
ObjCSpaceBeforeProtocolList: true
|
|
||||||
PackConstructorInitializers: BinPack
|
|
||||||
PenaltyBreakAssignment: 2
|
|
||||||
PenaltyBreakBeforeFirstCallParameter: 19
|
|
||||||
PenaltyBreakComment: 300
|
|
||||||
PenaltyBreakFirstLessLess: 120
|
|
||||||
PenaltyBreakOpenParenthesis: 0
|
|
||||||
PenaltyBreakString: 1000
|
|
||||||
PenaltyBreakTemplateDeclaration: 10
|
|
||||||
PenaltyExcessCharacter: 1000000
|
|
||||||
PenaltyIndentedWhitespace: 0
|
|
||||||
PenaltyReturnTypeOnItsOwnLine: 60
|
|
||||||
PointerAlignment: Right
|
|
||||||
PPIndentWidth: -1
|
|
||||||
QualifierAlignment: Leave
|
|
||||||
ReferenceAlignment: Pointer
|
|
||||||
ReflowComments: true
|
|
||||||
RemoveBracesLLVM: false
|
|
||||||
RemoveParentheses: Leave
|
|
||||||
RemoveSemicolon: false
|
|
||||||
RequiresClausePosition: OwnLine
|
|
||||||
RequiresExpressionIndentation: OuterScope
|
|
||||||
SeparateDefinitionBlocks: Leave
|
|
||||||
ShortNamespaceLines: 1
|
|
||||||
SortIncludes: CaseSensitive
|
|
||||||
SortJavaStaticImport: Before
|
|
||||||
SortUsingDeclarations: LexicographicNumeric
|
|
||||||
SpaceAfterCStyleCast: false
|
|
||||||
SpaceAfterLogicalNot: false
|
|
||||||
SpaceAfterTemplateKeyword: true
|
|
||||||
SpaceAroundPointerQualifiers: Default
|
|
||||||
SpaceBeforeAssignmentOperators: true
|
|
||||||
SpaceBeforeCaseColon: false
|
|
||||||
SpaceBeforeCpp11BracedList: false
|
|
||||||
SpaceBeforeCtorInitializerColon: true
|
|
||||||
SpaceBeforeInheritanceColon: true
|
|
||||||
SpaceBeforeJsonColon: false
|
|
||||||
SpaceBeforeParens: ControlStatements
|
|
||||||
SpaceBeforeParensOptions:
|
|
||||||
AfterControlStatements: true
|
|
||||||
AfterForeachMacros: true
|
|
||||||
AfterFunctionDefinitionName: false
|
|
||||||
AfterFunctionDeclarationName: false
|
|
||||||
AfterIfMacros: true
|
|
||||||
AfterOverloadedOperator: false
|
|
||||||
AfterRequiresInClause: false
|
|
||||||
AfterRequiresInExpression: false
|
|
||||||
BeforeNonEmptyParentheses: false
|
|
||||||
SpaceBeforeRangeBasedForLoopColon: true
|
|
||||||
SpaceBeforeSquareBrackets: false
|
|
||||||
SpaceInEmptyBlock: false
|
|
||||||
SpacesBeforeTrailingComments: 1
|
|
||||||
SpacesInAngles: Never
|
|
||||||
SpacesInContainerLiterals: true
|
|
||||||
SpacesInLineCommentPrefix:
|
|
||||||
Minimum: 1
|
|
||||||
Maximum: -1
|
|
||||||
SpacesInParens: Never
|
|
||||||
SpacesInParensOptions:
|
|
||||||
InCStyleCasts: false
|
|
||||||
InConditionalStatements: false
|
|
||||||
InEmptyParentheses: false
|
|
||||||
Other: false
|
|
||||||
SpacesInSquareBrackets: false
|
|
||||||
Standard: Latest
|
|
||||||
StatementAttributeLikeMacros:
|
|
||||||
- Q_EMIT
|
|
||||||
StatementMacros:
|
|
||||||
- Q_UNUSED
|
|
||||||
- QT_REQUIRE_VERSION
|
|
||||||
TabWidth: 4
|
|
||||||
UseTab: Never
|
|
||||||
VerilogBreakBetweenInstancePorts: true
|
|
||||||
WhitespaceSensitiveMacros:
|
|
||||||
- BOOST_PP_STRINGIZE
|
|
||||||
- CF_SWIFT_NAME
|
|
||||||
- NS_SWIFT_NAME
|
|
||||||
- PP_STRINGIZE
|
|
||||||
- STRINGIZE
|
|
||||||
...
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
|||||||
default:
|
|
||||||
image: docker.psi.ch:5000/wall_e/sinqepics:latest
|
|
||||||
|
|
||||||
stages:
|
|
||||||
- test
|
|
||||||
- build
|
|
||||||
|
|
||||||
cppcheck:
|
|
||||||
stage: test
|
|
||||||
script:
|
|
||||||
- cppcheck --std=c++17 --addon=cert --addon=misc --error-exitcode=1 sinqEPICSApp/
|
|
||||||
allow_failure: true # Long term this needs to be removed
|
|
||||||
artifacts:
|
|
||||||
expire_in: 1 week
|
|
||||||
tags:
|
|
||||||
- docker
|
|
||||||
|
|
||||||
formatting:
|
|
||||||
stage: test
|
|
||||||
script:
|
|
||||||
- clang-format --style=file --Werror --dry-run sinqEPICSApp/src/*.cpp sinqEPICSApp/src/*.c sinqEPICSApp/src/*.h
|
|
||||||
allow_failure: true # Long term this needs to be removed
|
|
||||||
artifacts:
|
|
||||||
expire_in: 1 week
|
|
||||||
tags:
|
|
||||||
- docker
|
|
||||||
|
|
||||||
# clangtidy:
|
|
||||||
# stage: test
|
|
||||||
# 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:
|
|
||||||
# # - docker
|
|
||||||
|
|
||||||
build_module:
|
|
||||||
stage: build
|
|
||||||
script:
|
|
||||||
- sed -i 's/ARCH_FILTER=.*/ARCH_FILTER=linux%/' Makefile.RHEL8
|
|
||||||
- make -f Makefile.RHEL8 install
|
|
||||||
- cp -rT "/ioc/modules/sinq/$(ls -U /ioc/modules/sinq/ | head -1)" "./sinq-${CI_COMMIT_SHORT_SHA}"
|
|
||||||
artifacts:
|
|
||||||
name: "sinq-${CI_COMMIT_SHORT_SHA}"
|
|
||||||
paths:
|
|
||||||
- "sinq-${CI_COMMIT_SHORT_SHA}/*"
|
|
||||||
expire_in: 1 week
|
|
||||||
when: always
|
|
||||||
tags:
|
|
||||||
- docker
|
|
@ -4,19 +4,21 @@ include /ioc/tools/driver.makefile
|
|||||||
MODULE=sinq
|
MODULE=sinq
|
||||||
BUILDCLASSES=Linux
|
BUILDCLASSES=Linux
|
||||||
EPICS_VERSIONS=7.0.7
|
EPICS_VERSIONS=7.0.7
|
||||||
ARCH_FILTER=RHEL8%
|
ARCH_FILTER=RHEL%
|
||||||
|
|
||||||
# additional module dependencies
|
# additional module dependencies
|
||||||
REQUIRED+=SynApps
|
REQUIRED+=SynApps
|
||||||
REQUIRED+=stream
|
REQUIRED+=stream
|
||||||
REQUIRED+=scaler
|
REQUIRED+=scaler
|
||||||
REQUIRED+=motorBase
|
REQUIRED+=asynMotor
|
||||||
|
|
||||||
|
# Release version
|
||||||
|
LIBVERSION=2024-dev
|
||||||
|
|
||||||
# DB files to include in the release
|
# DB files to include in the release
|
||||||
TEMPLATES += sinqEPICSApp/Db/dimetix.db
|
TEMPLATES += sinqEPICSApp/Db/dimetix.db
|
||||||
TEMPLATES += sinqEPICSApp/Db/slsvme.db
|
TEMPLATES += sinqEPICSApp/Db/slsvme.db
|
||||||
TEMPLATES += sinqEPICSApp/Db/spsamor.db
|
TEMPLATES += sinqEPICSApp/Db/spsamor.db
|
||||||
TEMPLATES += db/el734.db
|
|
||||||
|
|
||||||
# DBD files to include in the release
|
# DBD files to include in the release
|
||||||
DBDS += sinqEPICSApp/src/sinq.dbd
|
DBDS += sinqEPICSApp/src/sinq.dbd
|
||||||
@ -30,9 +32,9 @@ SOURCES += sinqEPICSApp/src/NanotecDriver.cpp
|
|||||||
SOURCES += sinqEPICSApp/src/stptok.cpp
|
SOURCES += sinqEPICSApp/src/stptok.cpp
|
||||||
SOURCES += sinqEPICSApp/src/PhytronDriver.cpp
|
SOURCES += sinqEPICSApp/src/PhytronDriver.cpp
|
||||||
SOURCES += sinqEPICSApp/src/EuroMoveDriver.cpp
|
SOURCES += sinqEPICSApp/src/EuroMoveDriver.cpp
|
||||||
# SOURCES += sinqEPICSApp/src/pmacAsynIPPort.c
|
SOURCES += sinqEPICSApp/src/pmacAsynIPPort.c
|
||||||
# SOURCES += sinqEPICSApp/src/pmacAxis.cpp
|
SOURCES += sinqEPICSApp/src/pmacAxis.cpp
|
||||||
# SOURCES += sinqEPICSApp/src/pmacController.cpp
|
SOURCES += sinqEPICSApp/src/pmacController.cpp
|
||||||
SOURCES += sinqEPICSApp/src/MasterMACSDriver.cpp
|
SOURCES += sinqEPICSApp/src/MasterMACSDriver.cpp
|
||||||
SOURCES += sinqEPICSApp/src/C804Axis.cpp
|
SOURCES += sinqEPICSApp/src/C804Axis.cpp
|
||||||
SOURCES += sinqEPICSApp/src/C804Controller.cpp
|
SOURCES += sinqEPICSApp/src/C804Controller.cpp
|
||||||
|
@ -38,12 +38,3 @@ Those political problems require a special development model:
|
|||||||
Take care of the sinqEPICsApp/src/sinq.dbd file. This is the one which differs mostly between
|
Take care of the sinqEPICsApp/src/sinq.dbd file. This is the one which differs mostly between
|
||||||
amorsim and master branches.
|
amorsim and master branches.
|
||||||
|
|
||||||
# Formatting
|
|
||||||
|
|
||||||
Formatting is done via the [`.clang-format`](./.clang-format) file checked into
|
|
||||||
the repository. One option to apply the formatting to a given file is via the
|
|
||||||
command below.
|
|
||||||
|
|
||||||
```
|
|
||||||
clang-format -i -style=file <file>
|
|
||||||
```
|
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
record(motor,"$(P)$(M)")
|
|
||||||
{
|
|
||||||
field(DESC,"$(DESC)")
|
|
||||||
field(DTYP,"$(DTYP)")
|
|
||||||
field(DIR,"$(DIR)")
|
|
||||||
field(VELO,"$(VELO)")
|
|
||||||
field(HVEL,"$(VELO)")
|
|
||||||
field(VBAS,"$(VELO)")
|
|
||||||
field(VMAX, "${VMAX}")
|
|
||||||
field(ACCL,"$(ACCL)")
|
|
||||||
field(BDST,"$(BDST)")
|
|
||||||
field(BVEL,"$(BVEL)")
|
|
||||||
field(BACC,"$(BACC)")
|
|
||||||
field(OUT,"@asyn($(PORT),$(ADDR))")
|
|
||||||
field(MRES,"$(MRES)")
|
|
||||||
field(PREC,"$(PREC)")
|
|
||||||
field(EGU,"$(EGU)")
|
|
||||||
field(DHLM,"$(DHLM)")
|
|
||||||
field(DLLM,"$(DLLM)")
|
|
||||||
field(INIT,"$(INIT)")
|
|
||||||
field(PINI, "NO")
|
|
||||||
field(TWV,"1")
|
|
||||||
field(RTRY,"0")
|
|
||||||
}
|
|
||||||
|
|
||||||
# The message text
|
|
||||||
record(waveform, "$(P)$(M)-MsgTxt") {
|
|
||||||
field(DTYP, "asynOctetRead")
|
|
||||||
field(INP, "@asyn($(PORT),$(N),1) MOTOR_MESSAGE_TEXT")
|
|
||||||
field(FTVL, "CHAR")
|
|
||||||
field(NELM, "80")
|
|
||||||
field(SCAN, "I/O Intr")
|
|
||||||
}
|
|
||||||
|
|
@ -50,5 +50,14 @@ record(longin, "$(P)$(M):Enable_RBV") {
|
|||||||
record(longout, "$(P)$(M):Reread_Encoder") {
|
record(longout, "$(P)$(M):Reread_Encoder") {
|
||||||
field(DTYP, "asynInt32")
|
field(DTYP, "asynInt32")
|
||||||
field(OUT, "@asyn($(PORT),$(N),1) REREAD_ENCODER_POSITION")
|
field(OUT, "@asyn($(PORT),$(N),1) REREAD_ENCODER_POSITION")
|
||||||
field(PINI, "NO")
|
field(PINI, "YES")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# reread encoder
|
||||||
|
record(longin, "$(P)$(M):Reread_Encoder_RBV") {
|
||||||
|
field(DTYP, "asynInt32")
|
||||||
|
field(INP, "@asyn($(PORT),$(N),1) REREAD_ENCODER_POSITION_RBV")
|
||||||
|
field(PINI, "NO")
|
||||||
|
field(SCAN, "1 second")
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
#include "C804Axis.h"
|
#include "C804Axis.h"
|
||||||
#include "C804Controller.h"
|
#include "C804Controller.h"
|
||||||
#include <cmath>
|
|
||||||
#include <errlog.h>
|
#include <errlog.h>
|
||||||
#include <limits>
|
|
||||||
#include <math.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <cmath>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
C804Axis::C804Axis(C804Controller *pC, int axisNo)
|
C804Axis::C804Axis(C804Controller *pC, int axisNo) : SINQAxis(pC, axisNo), pC_(pC)
|
||||||
: SINQAxis(pC, axisNo), pC_(pC) {
|
{
|
||||||
/*
|
/*
|
||||||
The superclass constructor SINQAxis calls in turn its superclass constructor
|
The superclass constructor SINQAxis calls in turn its superclass constructor
|
||||||
asynMotorAxis. In the latter, a pointer to the constructed object this is
|
asynMotorAxis. In the latter, a pointer to the constructed object this is
|
||||||
@ -16,14 +16,13 @@ C804Axis::C804Axis(C804Controller *pC, int axisNo)
|
|||||||
|
|
||||||
pC->pAxes_[axisNo] = this;
|
pC->pAxes_[axisNo] = this;
|
||||||
|
|
||||||
Therefore, the axes are managed by the controller pC. See C804Controller.cpp
|
Therefore, the axes are managed by the controller pC. See C804Controller.cpp for further explanation.
|
||||||
for further explanation. If axisNo is out of bounds, asynMotorAxis prints an
|
If axisNo is out of bounds, asynMotorAxis prints an error (see
|
||||||
error (see
|
https://github.com/epics-modules/motor/blob/master/motorApp/MotorSrc/asynMotorAxis.cpp, line 40).
|
||||||
https://github.com/epics-modules/motor/blob/master/motorApp/MotorSrc/asynMotorAxis.cpp,
|
However, we want the IOC creation to stop completely, since this is a configuration error.
|
||||||
line 40). However, we want the IOC creation to stop completely, since this
|
|
||||||
is a configuration error.
|
|
||||||
*/
|
*/
|
||||||
if (axisNo >= pC->numAxes_) {
|
if (axisNo >= pC->numAxes_)
|
||||||
|
{
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
last_position_steps_ = 0;
|
last_position_steps_ = 0;
|
||||||
@ -31,7 +30,8 @@ C804Axis::C804Axis(C804Controller *pC, int axisNo)
|
|||||||
last_poll_ = 0.0;
|
last_poll_ = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
C804Axis::~C804Axis(void) {
|
C804Axis::~C804Axis(void)
|
||||||
|
{
|
||||||
// Since the controller memory is managed somewhere else, we don't need to
|
// Since the controller memory is managed somewhere else, we don't need to
|
||||||
// clean up the pointer pC here.
|
// clean up the pointer pC here.
|
||||||
}
|
}
|
||||||
@ -39,44 +39,47 @@ C804Axis::~C804Axis(void) {
|
|||||||
/*
|
/*
|
||||||
The polling function informs us about the state of the axis, in particular if it
|
The polling function informs us about the state of the axis, in particular if it
|
||||||
is currently moving. It is called periodically, with the period defined by
|
is currently moving. It is called periodically, with the period defined by
|
||||||
the controller constructor arguments idlePollPeriod and movingPollPeriod
|
the controller constructor arguments idlePollPeriod and movingPollPeriod depending on
|
||||||
depending on the current axis state.
|
the current axis state.
|
||||||
*/
|
*/
|
||||||
asynStatus C804Axis::poll(bool *moving) {
|
asynStatus C804Axis::poll(bool *moving)
|
||||||
|
{
|
||||||
// Local variable declaration
|
// Local variable declaration
|
||||||
static const char *functionName = "C804Axis::poll";
|
static const char *functionName = "C804Axis::poll";
|
||||||
|
|
||||||
// The poll function is just a wrapper around poll_no_param_lib_update and
|
// The poll function is just a wrapper around poll_no_param_lib_update and handles mainly
|
||||||
// handles mainly the callParamCallbacks() function
|
// the callParamCallbacks() function
|
||||||
asynStatus status_poll = C804Axis::poll_no_param_lib_update(moving);
|
asynStatus status_poll = C804Axis::poll_no_param_lib_update(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.
|
||||||
asynStatus status_callback = callParamCallbacks();
|
asynStatus status_callback = callParamCallbacks();
|
||||||
if (status_callback != asynSuccess) {
|
if (status_callback != asynSuccess)
|
||||||
|
{
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"%s: Updating the parameter library failed for axis %d\n",
|
"%s: Updating the parameter library failed for axis %d\n", functionName, axisNo_);
|
||||||
functionName, axisNo_);
|
|
||||||
return status_callback;
|
return status_callback;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return status_poll;
|
return status_poll;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform the actual poll
|
// Perform the actual poll
|
||||||
asynStatus C804Axis::poll_no_param_lib_update(bool *moving) {
|
asynStatus C804Axis::poll_no_param_lib_update(bool *moving)
|
||||||
|
{
|
||||||
// Local variable declaration
|
// Local variable declaration
|
||||||
static const char *functionName = "C804Axis::poll";
|
static const char *functionName = "C804Axis::poll";
|
||||||
asynStatus status;
|
asynStatus status;
|
||||||
int axis_status = 0;
|
int axis_status = 0;
|
||||||
|
|
||||||
// The controller returns the position and velocity in encoder steps.
|
// The controller returns the position and velocity in encoder steps.
|
||||||
// This value needs to be converted in user units (engineering units EGU)
|
// This value needs to be converted in user units (engineering units EGU) via
|
||||||
// via the record field MRES of the motor record. This field has already
|
// the record field MRES of the motor record. This field has already been read
|
||||||
// been read by the constructor into the member variable
|
// by the constructor into the member variable motorRecResolution_.
|
||||||
// motorRecResolution_. To go from steps to user units, multiply with
|
// To go from steps to user units, multiply with motorRecResolution_
|
||||||
// motorRecResolution_ Example: If 10 steps correspond to 1 mm, MRES should
|
// Example: If 10 steps correspond to 1 mm, MRES should be 0.1.
|
||||||
// be 0.1.
|
|
||||||
int position_error_steps = 0;
|
int position_error_steps = 0;
|
||||||
int motor_position_steps = 0;
|
int motor_position_steps = 0;
|
||||||
int motor_velocity_steps = 0;
|
int motor_velocity_steps = 0;
|
||||||
@ -86,28 +89,28 @@ asynStatus C804Axis::poll_no_param_lib_update(bool *moving) {
|
|||||||
double motor_velocity = .0;
|
double motor_velocity = .0;
|
||||||
double programmed_motor_velocity = .0;
|
double programmed_motor_velocity = .0;
|
||||||
|
|
||||||
// The buffer sizes for command and response are defined in the controller
|
// The buffer sizes for command and response are defined in the controller (see the corresponding source code files)
|
||||||
// (see the corresponding source code files)
|
|
||||||
char command[pC_->C804_MAXBUF_], response[pC_->C804_MAXBUF_];
|
char command[pC_->C804_MAXBUF_], response[pC_->C804_MAXBUF_];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Cancel the poll if the last poll has "just" happened.
|
Cancel the poll if the last poll has "just" happened.
|
||||||
*/
|
*/
|
||||||
if (time(NULL) < last_poll_ + 0.5 * pC_->movingPollPeriod_) {
|
if (time(NULL) < last_poll_ + 0.5 * pC_->movingPollPeriod_)
|
||||||
|
{
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_WARNING,
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_WARNING,
|
||||||
"%s: Aborted poll since the last poll for axis %d happened a "
|
"%s: Aborted poll since the last poll for axis %d happened a short time ago\n", functionName, axisNo_);
|
||||||
"short time ago\n",
|
|
||||||
functionName, axisNo_);
|
|
||||||
return asynSuccess;
|
return asynSuccess;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
last_poll_ = time(NULL);
|
last_poll_ = time(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The parameter motorRecResolution_ is coupled to the field MRES of the motor
|
The parameter motorRecResolution_ is coupled to the field MRES of the motor
|
||||||
record in the following manner:
|
record in the following manner:
|
||||||
- In sinq_asyn_motor.db, the PV (motor_record_pv_name)MOTOR_REC_RESOLUTION
|
- In sinq_asyn_motor.db, the PV (motor_record_pv_name)MOTOR_REC_RESOLUTION is
|
||||||
is defined as a copy of the field (motor_record_pv_name).MRES:
|
defined as a copy of the field (motor_record_pv_name).MRES:
|
||||||
|
|
||||||
record(ao,"$(P)$(M):Resolution") {
|
record(ao,"$(P)$(M):Resolution") {
|
||||||
field(DESC, "$(M) resolution")
|
field(DESC, "$(M) resolution")
|
||||||
@ -118,33 +121,52 @@ asynStatus C804Axis::poll_no_param_lib_update(bool *moving) {
|
|||||||
field(PREC, "$(PREC)")
|
field(PREC, "$(PREC)")
|
||||||
}
|
}
|
||||||
|
|
||||||
- The PV name MOTOR_REC_RESOLUTION is coupled in asynMotorController.h to
|
- The PV name MOTOR_REC_RESOLUTION is coupled in asynMotorController.h to the constant motorRecResolutionString
|
||||||
the constant motorRecResolutionString
|
- ... which in turn is assigned to motorRecResolution_ in asynMotorController.cpp
|
||||||
- ... which in turn is assigned to motorRecResolution_ in
|
This way of making the field visible to the driver is described here: https://epics.anl.gov/tech-talk/2020/msg00378.php
|
||||||
asynMotorController.cpp This way of making the field visible to the driver
|
This is a one-way coupling, changes to the parameter library via setDoubleParam
|
||||||
is described here: https://epics.anl.gov/tech-talk/2020/msg00378.php This is
|
are NOT transferred to (motor_record_pv_name).MRES or to (motor_record_pv_name):Resolution.
|
||||||
a one-way coupling, changes to the parameter library via setDoubleParam are
|
|
||||||
NOT transferred to (motor_record_pv_name).MRES or to
|
|
||||||
(motor_record_pv_name):Resolution.
|
|
||||||
|
|
||||||
NOTE: This function must not be called in the constructor (e.g. in order to
|
NOTE: This function must not be called in the constructor (e.g. in order to
|
||||||
save the read result to the member variable earlier), since the parameter
|
save the read result to the member variable earlier), since the parameter library
|
||||||
library is updated at a later stage!
|
is updated at a later stage!
|
||||||
*/
|
*/
|
||||||
pC_->getDoubleParam(axisNo_, pC_->motorRecResolution_,
|
status = pC_->getDoubleParam(axisNo_, pC_->motorRecResolution_, &motorRecResolution_);
|
||||||
&motorRecResolution_);
|
|
||||||
|
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW, "Poll axis %d\n", axisNo_);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
We know that the motor resolution must not be zero. During the startup of
|
The poll function might be called at IOC startup before the parameter
|
||||||
the IOC, polls can happen before the record is fully initialized. In that
|
library has been fully initialized. In this case, calling getDoubleParam
|
||||||
case, all values are zero.
|
returns the error status 10 (asynParamUndefined). Returning an asynError
|
||||||
*/
|
from the poll method means that the poll is repeated. This is exactly what
|
||||||
if (motorRecResolution_ == 0) {
|
we want, because this means that the poll will be repeated until the
|
||||||
|
parameter library has been initialized.
|
||||||
|
|
||||||
|
asynStatus is defined as
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
asynSuccess,asynTimeout,asynOverflow,asynError,asynDisconnected,asynDisabled
|
||||||
|
}asynStatus;
|
||||||
|
|
||||||
|
in asynDriver.h (see https://github.com/epics-modules/asyn/blob/master/asyn/asynDriver/asynDriver.h),
|
||||||
|
Therefore, it should only have the values 0 to 5. However, the enum value
|
||||||
|
range is extended in paramErrors.h (https://github.com/epics-modules/asyn/blob/master/asyn/asynPortDriver/paramErrors.h)
|
||||||
|
*/
|
||||||
|
if (status == asynParamUndefined)
|
||||||
|
{
|
||||||
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW,
|
||||||
|
"%s: Parameter library is not yet initialized. Repeating poll on axis %d\n", functionName, axisNo_);
|
||||||
|
return asynError;
|
||||||
|
}
|
||||||
|
else if (status != asynSuccess)
|
||||||
|
{
|
||||||
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
|
"%s: Reading the motor resolution failed for axis %d\n (asynStatus = %d)", functionName, axisNo_, status);
|
||||||
return asynError;
|
return asynError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Assume that the axis does not have a status problem. If it does have a
|
Assume that the axis does not have a status problem. If it does have a
|
||||||
problem, this value will be overwritten further below. Setting this value
|
problem, this value will be overwritten further below. Setting this value
|
||||||
@ -154,11 +176,11 @@ asynStatus C804Axis::poll_no_param_lib_update(bool *moving) {
|
|||||||
*/
|
*/
|
||||||
setIntegerParam(pC_->motorStatusProblem_, false);
|
setIntegerParam(pC_->motorStatusProblem_, false);
|
||||||
|
|
||||||
// Read out the position error of the axis (delta of target position to
|
// Read out the position error of the axis (delta of target position to actual position)
|
||||||
// actual position)
|
|
||||||
snprintf(command, pC_->C804_MAXBUF_ - 1, "%dTE", axisNo_);
|
snprintf(command, pC_->C804_MAXBUF_ - 1, "%dTE", axisNo_);
|
||||||
status = pC_->lowLevelWriteRead(axisNo_, command, response, true);
|
status = pC_->lowLevelWriteRead(axisNo_, command, response, true);
|
||||||
if (status == asynSuccess) {
|
if (status == asynSuccess)
|
||||||
|
{
|
||||||
int parsed_axis;
|
int parsed_axis;
|
||||||
sscanf(response, "%2dE%10d", &parsed_axis, &position_error_steps);
|
sscanf(response, "%2dE%10d", &parsed_axis, &position_error_steps);
|
||||||
|
|
||||||
@ -166,12 +188,12 @@ asynStatus C804Axis::poll_no_param_lib_update(bool *moving) {
|
|||||||
position_error = double(position_error_steps) * motorRecResolution_;
|
position_error = double(position_error_steps) * motorRecResolution_;
|
||||||
|
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW,
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW,
|
||||||
"%s: Axis %d, response %s, position error %f\n", functionName,
|
"%s: Axis %d, response %s, position error %f\n", functionName, axisNo_, response, position_error);
|
||||||
axisNo_, response, position_error);
|
}
|
||||||
} else {
|
else
|
||||||
|
{
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"%s: Reading the position error failed for axis %d\n",
|
"%s: Reading the position error failed for axis %d\n", functionName, axisNo_);
|
||||||
functionName, axisNo_);
|
|
||||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||||
|
|
||||||
// Stop the evaluation prematurely
|
// Stop the evaluation prematurely
|
||||||
@ -180,9 +202,9 @@ asynStatus C804Axis::poll_no_param_lib_update(bool *moving) {
|
|||||||
|
|
||||||
// Read the current position.
|
// Read the current position.
|
||||||
snprintf(command, this->pC_->C804_MAXBUF_ - 1, "%dTP", this->axisNo_);
|
snprintf(command, this->pC_->C804_MAXBUF_ - 1, "%dTP", this->axisNo_);
|
||||||
status =
|
status = this->pC_->lowLevelWriteRead(this->axisNo_, command, response, true);
|
||||||
this->pC_->lowLevelWriteRead(this->axisNo_, command, response, true);
|
if (status == asynSuccess)
|
||||||
if (status == asynSuccess) {
|
{
|
||||||
int parsed_axis;
|
int parsed_axis;
|
||||||
sscanf(response, "%2dP%10d", &parsed_axis, &motor_position_steps);
|
sscanf(response, "%2dP%10d", &parsed_axis, &motor_position_steps);
|
||||||
|
|
||||||
@ -190,14 +212,14 @@ asynStatus C804Axis::poll_no_param_lib_update(bool *moving) {
|
|||||||
motor_position = double(motor_position_steps) * motorRecResolution_;
|
motor_position = double(motor_position_steps) * motorRecResolution_;
|
||||||
|
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW,
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW,
|
||||||
"%s: Axis %d, response %s, position %f\n", functionName,
|
"%s: Axis %d, response %s, position %f\n", functionName, axisNo_, response, motor_position);
|
||||||
axisNo_, response, motor_position);
|
|
||||||
setDoubleParam(pC_->motorPosition_, motor_position);
|
setDoubleParam(pC_->motorPosition_, motor_position);
|
||||||
setDoubleParam(pC_->motorEncoderPosition_, motor_position);
|
setDoubleParam(pC_->motorEncoderPosition_, motor_position);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"%s: Reading the position failed for axis %d\n", functionName,
|
"%s: Reading the position failed for axis %d\n", functionName, axisNo_);
|
||||||
axisNo_);
|
|
||||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
@ -205,9 +227,9 @@ asynStatus C804Axis::poll_no_param_lib_update(bool *moving) {
|
|||||||
|
|
||||||
// Read the current velocity
|
// Read the current velocity
|
||||||
snprintf(command, this->pC_->C804_MAXBUF_ - 1, "%dTV", this->axisNo_);
|
snprintf(command, this->pC_->C804_MAXBUF_ - 1, "%dTV", this->axisNo_);
|
||||||
status =
|
status = this->pC_->lowLevelWriteRead(this->axisNo_, command, response, true);
|
||||||
this->pC_->lowLevelWriteRead(this->axisNo_, command, response, true);
|
if (status == asynSuccess)
|
||||||
if (status == asynSuccess) {
|
{
|
||||||
int parsed_axis;
|
int parsed_axis;
|
||||||
sscanf(response, "%2dV%10d", &parsed_axis, &motor_velocity_steps);
|
sscanf(response, "%2dV%10d", &parsed_axis, &motor_velocity_steps);
|
||||||
|
|
||||||
@ -215,12 +237,12 @@ asynStatus C804Axis::poll_no_param_lib_update(bool *moving) {
|
|||||||
motor_velocity = double(motor_velocity_steps) * motorRecResolution_;
|
motor_velocity = double(motor_velocity_steps) * motorRecResolution_;
|
||||||
|
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW,
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW,
|
||||||
"%s: Axis %d, response %s, velocity %f\n", functionName,
|
"%s: Axis %d, response %s, velocity %f\n", functionName, axisNo_, response, motor_velocity);
|
||||||
axisNo_, response, motor_velocity);
|
}
|
||||||
} else {
|
else
|
||||||
|
{
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"%s: Reading the velocity failed for axis %d\n", functionName,
|
"%s: Reading the velocity failed for axis %d\n", functionName, axisNo_);
|
||||||
axisNo_);
|
|
||||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
@ -228,25 +250,23 @@ asynStatus C804Axis::poll_no_param_lib_update(bool *moving) {
|
|||||||
|
|
||||||
// Read the programmed velocity
|
// Read the programmed velocity
|
||||||
snprintf(command, this->pC_->C804_MAXBUF_ - 1, "%dTY", this->axisNo_);
|
snprintf(command, this->pC_->C804_MAXBUF_ - 1, "%dTY", this->axisNo_);
|
||||||
status =
|
status = this->pC_->lowLevelWriteRead(this->axisNo_, command, response, true);
|
||||||
this->pC_->lowLevelWriteRead(this->axisNo_, command, response, true);
|
if (status == asynSuccess)
|
||||||
if (status == asynSuccess) {
|
{
|
||||||
|
|
||||||
int parsed_axis;
|
int parsed_axis;
|
||||||
sscanf(response, "%2dY%10d", &parsed_axis,
|
sscanf(response, "%2dY%10d", &parsed_axis, &programmed_motor_velocity_steps);
|
||||||
&programmed_motor_velocity_steps);
|
|
||||||
|
|
||||||
// Scale from the encoder resultion to user units
|
// Scale from the encoder resultion to user units
|
||||||
programmed_motor_velocity =
|
programmed_motor_velocity = double(programmed_motor_velocity_steps) * motorRecResolution_;
|
||||||
double(programmed_motor_velocity_steps) * motorRecResolution_;
|
|
||||||
|
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW,
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW,
|
||||||
"%s: Axis %d, response %s, programmed velocity %f\n",
|
"%s: Axis %d, response %s, programmed velocity %f\n", functionName, axisNo_, response, programmed_motor_velocity);
|
||||||
functionName, axisNo_, response, programmed_motor_velocity);
|
}
|
||||||
} else {
|
else
|
||||||
|
{
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"%s: Reading the programmed velocity failed for axis %d\n",
|
"%s: Reading the programmed velocity failed for axis %d\n", functionName, axisNo_);
|
||||||
functionName, axisNo_);
|
|
||||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
@ -255,13 +275,15 @@ asynStatus C804Axis::poll_no_param_lib_update(bool *moving) {
|
|||||||
// Read the motor status
|
// Read the motor status
|
||||||
snprintf(command, pC_->C804_MAXBUF_ - 1, "%dTS", axisNo_);
|
snprintf(command, pC_->C804_MAXBUF_ - 1, "%dTS", axisNo_);
|
||||||
status = pC_->lowLevelWriteRead(this->axisNo_, command, response, true);
|
status = pC_->lowLevelWriteRead(this->axisNo_, command, response, true);
|
||||||
if (status == asynSuccess) {
|
if (status == asynSuccess)
|
||||||
|
{
|
||||||
int parsed_axis;
|
int parsed_axis;
|
||||||
sscanf(response, "%2dS%10d", &parsed_axis, &axis_status);
|
sscanf(response, "%2dS%10d", &parsed_axis, &axis_status);
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW,
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_FLOW,
|
||||||
"%s: Axis %d, response %s, status %d\n", functionName,
|
"%s: Axis %d, response %s, status %d\n", functionName, axisNo_, response, axis_status);
|
||||||
axisNo_, response, axis_status);
|
}
|
||||||
} else {
|
else
|
||||||
|
{
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"%s: Reading the motor status %d\n", functionName, axisNo_);
|
"%s: Reading the motor status %d\n", functionName, axisNo_);
|
||||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||||
@ -270,22 +292,24 @@ asynStatus C804Axis::poll_no_param_lib_update(bool *moving) {
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the axis is enabled by reading out bit 2 (see
|
// Check if the axis is enabled by reading out bit 2 (see https://stackoverflow.com/questions/2249731/how-do-i-get-bit-by-bit-data-from-an-integer-value-in-c)
|
||||||
// https://stackoverflow.com/questions/2249731/how-do-i-get-bit-by-bit-data-from-an-integer-value-in-c)
|
|
||||||
int mask = 1 << 2;
|
int mask = 1 << 2;
|
||||||
int masked_n = axis_status & mask;
|
int masked_n = axis_status & mask;
|
||||||
// Is 1 if the axis is disabled
|
// Is 1 if the axis is disabled
|
||||||
int disabled = masked_n >> 2;
|
int disabled = masked_n >> 2;
|
||||||
if (disabled) {
|
if (disabled)
|
||||||
|
{
|
||||||
enabled_ = false;
|
enabled_ = false;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
enabled_ = true;
|
enabled_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Determine if the motor is moving. This is determined by the following
|
Determine if the motor is moving. This is determined by the following criteria:
|
||||||
criteria: 1) The motor position changes from poll to poll 2) The motor is
|
1) The motor position changes from poll to poll
|
||||||
enabled
|
2) The motor is enabled
|
||||||
*/
|
*/
|
||||||
*moving = enabled_ && motor_position_steps != this->last_position_steps_;
|
*moving = enabled_ && motor_position_steps != this->last_position_steps_;
|
||||||
|
|
||||||
@ -298,21 +322,22 @@ asynStatus C804Axis::poll_no_param_lib_update(bool *moving) {
|
|||||||
moving. If it has spent too much time in a moving state without reaching
|
moving. If it has spent too much time in a moving state without reaching
|
||||||
the target, stop the motor and return an error.
|
the target, stop the motor and return an error.
|
||||||
*/
|
*/
|
||||||
if (*moving) {
|
if (*moving)
|
||||||
|
{
|
||||||
|
|
||||||
int motorStatusMoving = 0;
|
int motorStatusMoving = 0;
|
||||||
pC_->getIntegerParam(axisNo_, pC_->motorStatusMoving_,
|
pC_->getIntegerParam(axisNo_, pC_->motorStatusMoving_, &motorStatusMoving);
|
||||||
&motorStatusMoving);
|
|
||||||
|
|
||||||
// motor is moving, but didn't move in the last poll
|
// motor is moving, but didn't move in the last poll
|
||||||
if (motorStatusMoving == 0) {
|
if (motorStatusMoving == 0)
|
||||||
|
{
|
||||||
time_t current_time = time(NULL);
|
time_t current_time = time(NULL);
|
||||||
|
|
||||||
// Factor 2 of the calculated moving time
|
// Factor 2 of the calculated moving time
|
||||||
estimatedArrivalTime_ =
|
estimatedArrivalTime_ = current_time + std::ceil(2 * std::fabs(position_error) / programmed_motor_velocity);
|
||||||
current_time + std::ceil(2 * std::fabs(position_error) /
|
}
|
||||||
programmed_motor_velocity);
|
else
|
||||||
} else {
|
{
|
||||||
// /*
|
// /*
|
||||||
// Motor is moving for a longer time than it should: Stop it
|
// Motor is moving for a longer time than it should: Stop it
|
||||||
// */
|
// */
|
||||||
@ -320,9 +345,7 @@ asynStatus C804Axis::poll_no_param_lib_update(bool *moving) {
|
|||||||
// {
|
// {
|
||||||
// snprintf(command, pC_->C804_MAXBUF_ - 1, "%dST", axisNo_);
|
// snprintf(command, pC_->C804_MAXBUF_ - 1, "%dST", axisNo_);
|
||||||
// status = pC_->lowLevelWriteRead(axisNo_, command, response);
|
// status = pC_->lowLevelWriteRead(axisNo_, command, response);
|
||||||
// asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR, "%s: Stopped
|
// asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR, "%s: Stopped axis %d since it moved for double the time it should to reach its target\n", functionName, axisNo_);
|
||||||
// axis %d since it moved for double the time it should to reach
|
|
||||||
// its target\n", functionName, axisNo_);
|
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -338,58 +361,54 @@ asynStatus C804Axis::poll_no_param_lib_update(bool *moving) {
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus C804Axis::move(double position, int relative, double minVelocity,
|
asynStatus C804Axis::move(double position, int relative, double minVelocity, double maxVelocity, double acceleration)
|
||||||
double maxVelocity, double acceleration) {
|
{
|
||||||
asynStatus status;
|
asynStatus status;
|
||||||
static const char *functionName = "C804Axis::move";
|
static const char *functionName = "C804Axis::move";
|
||||||
char command[pC_->C804_MAXBUF_], response[pC_->C804_MAXBUF_];
|
char command[pC_->C804_MAXBUF_], response[pC_->C804_MAXBUF_];
|
||||||
double position_c_units = 0.0; // Controller units
|
double position_c_units = 0.0; // Controller units
|
||||||
int position_steps = 0;
|
int position_steps = 0;
|
||||||
|
|
||||||
// Convert from user coordinates (EGU) to controller coordinates (steps).
|
// Convert from user coordinates (EGU) to controller coordinates (steps). Check for overflow
|
||||||
// Check for overflow
|
if (motorRecResolution_ == 0.0)
|
||||||
if (motorRecResolution_ == 0.0) {
|
{
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR, "%s: MRES must not be zero. Movement is aborted", functionName);
|
||||||
"%s: MRES must not be zero. Movement is aborted",
|
|
||||||
functionName);
|
|
||||||
return asynError;
|
return asynError;
|
||||||
}
|
}
|
||||||
position_c_units = position / motorRecResolution_;
|
position_c_units = position / motorRecResolution_;
|
||||||
|
|
||||||
// Check for overflow during the division
|
// Check for overflow during the division
|
||||||
if (position_c_units * motorRecResolution_ != position) {
|
if (position_c_units * motorRecResolution_ != position)
|
||||||
asynPrint(
|
{
|
||||||
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"%s: could not convert from user units (%f) to controller units "
|
"%s: could not convert from user units (%f) to controller units (user units divided by resolution MRES %f) due to overflow.",
|
||||||
"(user units divided by resolution MRES %f) due to overflow.",
|
functionName, position, motorRecResolution_);
|
||||||
functionName, position, motorRecResolution_);
|
|
||||||
return asynError;
|
return asynError;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Steps can only be integer values => cast to integer while checking for
|
// Steps can only be integer values => cast to integer while checking for overflow
|
||||||
// overflow
|
if (std::numeric_limits<int>::max() < position_c_units || std::numeric_limits<int>::min() > position_c_units)
|
||||||
if (std::numeric_limits<int>::max() < position_c_units ||
|
{
|
||||||
std::numeric_limits<int>::min() > position_c_units) {
|
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"%s: target position %f cannot be converted to int "
|
"%s: target position %f cannot be converted to int (overflow). Check target value %f and MRES %f",
|
||||||
"(overflow). Check target value %f and MRES %f",
|
functionName, position_c_units, position_c_units, motorRecResolution_);
|
||||||
functionName, position_c_units, position_c_units,
|
|
||||||
motorRecResolution_);
|
|
||||||
return asynError;
|
return asynError;
|
||||||
}
|
}
|
||||||
position_steps = static_cast<int>(position_c_units);
|
position_steps = static_cast<int>(position_c_units);
|
||||||
|
|
||||||
// Convert from relative to absolute values
|
// Convert from relative to absolute values
|
||||||
if (relative) {
|
if (relative)
|
||||||
|
{
|
||||||
position_steps += last_position_steps_;
|
position_steps += last_position_steps_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the axis is currently disabled, enable it
|
// If the axis is currently disabled, enable it
|
||||||
if (!enabled_) {
|
if (!enabled_)
|
||||||
|
{
|
||||||
snprintf(command, pC_->C804_MAXBUF_ - 1, "%dGO", axisNo_);
|
snprintf(command, pC_->C804_MAXBUF_ - 1, "%dGO", axisNo_);
|
||||||
status =
|
status = pC_->lowLevelWriteRead(this->axisNo_, command, response, false);
|
||||||
pC_->lowLevelWriteRead(this->axisNo_, command, response, false);
|
if (status != asynSuccess)
|
||||||
if (status != asynSuccess) {
|
{
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"%s: Enabling axis %d\n failed", functionName, axisNo_);
|
"%s: Enabling axis %d\n failed", functionName, axisNo_);
|
||||||
return status;
|
return status;
|
||||||
@ -399,10 +418,10 @@ asynStatus C804Axis::move(double position, int relative, double minVelocity,
|
|||||||
// Start movement
|
// Start movement
|
||||||
snprintf(command, pC_->C804_MAXBUF_ - 1, "%dMA%d", axisNo_, position_steps);
|
snprintf(command, pC_->C804_MAXBUF_ - 1, "%dMA%d", axisNo_, position_steps);
|
||||||
status = pC_->lowLevelWriteRead(this->axisNo_, command, response, false);
|
status = pC_->lowLevelWriteRead(this->axisNo_, command, response, false);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess)
|
||||||
|
{
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"%s: Setting the target position %d failed for axis %d\n",
|
"%s: Setting the target position %d failed for axis %d\n", functionName, position_steps, axisNo_);
|
||||||
functionName, position_steps, axisNo_);
|
|
||||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -414,13 +433,14 @@ asynStatus C804Axis::move(double position, int relative, double minVelocity,
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus C804Axis::moveVelocity(double min_velocity, double max_velocity,
|
asynStatus C804Axis::moveVelocity(double min_velocity, double max_velocity, double acceleration)
|
||||||
double acceleration) {
|
{
|
||||||
static const char *functionName = "C804Axis::moveVelocity";
|
static const char *functionName = "C804Axis::moveVelocity";
|
||||||
return asynError;
|
return asynError;
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus C804Axis::stop(double acceleration) {
|
asynStatus C804Axis::stop(double acceleration)
|
||||||
|
{
|
||||||
asynStatus status = asynSuccess;
|
asynStatus status = asynSuccess;
|
||||||
static const char *functionName = "C804Axis::stop";
|
static const char *functionName = "C804Axis::stop";
|
||||||
char command[pC_->C804_MAXBUF_], response[pC_->C804_MAXBUF_];
|
char command[pC_->C804_MAXBUF_], response[pC_->C804_MAXBUF_];
|
||||||
@ -428,28 +448,26 @@ asynStatus C804Axis::stop(double acceleration) {
|
|||||||
bool moving = false;
|
bool moving = false;
|
||||||
|
|
||||||
poll(&moving);
|
poll(&moving);
|
||||||
if (moving) {
|
if (moving)
|
||||||
|
{
|
||||||
// ST = Stop
|
// ST = Stop
|
||||||
snprintf(command, pC_->C804_MAXBUF_ - 1, "%dST", axisNo_);
|
snprintf(command, pC_->C804_MAXBUF_ - 1, "%dST", axisNo_);
|
||||||
status = pC_->lowLevelWriteRead(axisNo_, command, response, false);
|
status = pC_->lowLevelWriteRead(axisNo_, command, response, false);
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACEIO_DEVICE, "%s: Stop axis %d\n",
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACEIO_DEVICE, "%s: Stop axis %d\n", functionName, axisNo_);
|
||||||
functionName, axisNo_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus C804Axis::home(double minVelocity, double maxVelocity,
|
asynStatus C804Axis::home(double minVelocity, double maxVelocity, double acceleration, int forwards)
|
||||||
double acceleration, int forwards) {
|
{
|
||||||
asynStatus status = asynSuccess;
|
asynStatus status = asynSuccess;
|
||||||
static const char *functionName = "C804Axis::home";
|
static const char *functionName = "C804Axis::home";
|
||||||
char command[pC_->C804_MAXBUF_], response[pC_->C804_MAXBUF_];
|
char command[pC_->C804_MAXBUF_], response[pC_->C804_MAXBUF_];
|
||||||
|
|
||||||
snprintf(command, pC_->C804_MAXBUF_ - 1, "%dFE0",
|
snprintf(command, pC_->C804_MAXBUF_ - 1, "%dFE0", axisNo_); // Home to the upper limit of the axis (25 mm)
|
||||||
axisNo_); // Home to the upper limit of the axis (25 mm)
|
|
||||||
status = pC_->lowLevelWriteRead(axisNo_, command, response, false);
|
status = pC_->lowLevelWriteRead(axisNo_, command, response, false);
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACEIO_DEVICE, "%s: Homing axis %d\n",
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACEIO_DEVICE, "%s: Homing axis %d\n", functionName, axisNo_);
|
||||||
functionName, axisNo_);
|
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -457,21 +475,23 @@ asynStatus C804Axis::home(double minVelocity, double maxVelocity,
|
|||||||
/**
|
/**
|
||||||
If on is 0, disable the motor, otherwise enable it.
|
If on is 0, disable the motor, otherwise enable it.
|
||||||
*/
|
*/
|
||||||
asynStatus C804Axis::enable(int on) {
|
asynStatus C804Axis::enable(int on)
|
||||||
|
{
|
||||||
asynStatus status = asynSuccess;
|
asynStatus status = asynSuccess;
|
||||||
static const char *functionName = "C804Axis::enable";
|
static const char *functionName = "C804Axis::enable";
|
||||||
char command[pC_->C804_MAXBUF_], response[pC_->C804_MAXBUF_];
|
char command[pC_->C804_MAXBUF_], response[pC_->C804_MAXBUF_];
|
||||||
|
|
||||||
if (on == 0) {
|
if (on == 0)
|
||||||
|
{
|
||||||
snprintf(command, pC_->C804_MAXBUF_ - 1, "%dMF", axisNo_);
|
snprintf(command, pC_->C804_MAXBUF_ - 1, "%dMF", axisNo_);
|
||||||
status = pC_->lowLevelWriteRead(axisNo_, command, response, false);
|
status = pC_->lowLevelWriteRead(axisNo_, command, response, false);
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACEIO_DEVICE,
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACEIO_DEVICE, "%s: Disable axis %d\n", functionName, axisNo_);
|
||||||
"%s: Disable axis %d\n", functionName, axisNo_);
|
}
|
||||||
} else {
|
else
|
||||||
|
{
|
||||||
snprintf(command, pC_->C804_MAXBUF_ - 1, "%dMN", axisNo_);
|
snprintf(command, pC_->C804_MAXBUF_ - 1, "%dMN", axisNo_);
|
||||||
status = pC_->lowLevelWriteRead(axisNo_, command, response, false);
|
status = pC_->lowLevelWriteRead(axisNo_, command, response, false);
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACEIO_DEVICE,
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACEIO_DEVICE, "%s: Enable axis %d\n", functionName, axisNo_);
|
||||||
"%s: Enable axis %d\n", functionName, axisNo_);
|
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -143,11 +143,6 @@ asynStatus EL734Controller::transactController(int axisNo, char command[COMLEN],
|
|||||||
|
|
||||||
pasynOctetSyncIO->flush(pasynUserController_);
|
pasynOctetSyncIO->flush(pasynUserController_);
|
||||||
|
|
||||||
if (axis != NULL)
|
|
||||||
{
|
|
||||||
axis->updateMsgTxtFromDriver("");
|
|
||||||
}
|
|
||||||
|
|
||||||
status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
|
status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
|
||||||
reply, COMLEN, 2., &out, &in, &reason);
|
reply, COMLEN, 2., &out, &in, &reason);
|
||||||
if (status != asynSuccess)
|
if (status != asynSuccess)
|
||||||
|
@ -114,7 +114,7 @@ typedef struct {
|
|||||||
unsigned int dbInit;
|
unsigned int dbInit;
|
||||||
}EL737priv;
|
}EL737priv;
|
||||||
|
|
||||||
static void dummyAsynCallback(asynUser *pasynUser)
|
static void dummyAsynCallback([[maybe_unused]] asynUser *pasynUser)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1186,8 +1186,6 @@ AmorDetectorAxis::AmorDetectorAxis(pmacController *pC, int axisNo, int function)
|
|||||||
pC_->debugFlow(functionName);
|
pC_->debugFlow(functionName);
|
||||||
|
|
||||||
_function = function;
|
_function = function;
|
||||||
det_starting = false;
|
|
||||||
det_startTime = time(NULL);
|
|
||||||
|
|
||||||
callParamCallbacks();
|
callParamCallbacks();
|
||||||
|
|
||||||
|
@ -1,180 +1,169 @@
|
|||||||
/********************************************
|
/********************************************
|
||||||
* pmacAxis.cpp
|
* pmacAxis.cpp
|
||||||
*
|
*
|
||||||
* PMAC Asyn motor based on the
|
* PMAC Asyn motor based on the
|
||||||
* asynMotorAxis class.
|
* asynMotorAxis class.
|
||||||
*
|
*
|
||||||
* Matthew Pearson
|
* Matthew Pearson
|
||||||
* 23 May 2012
|
* 23 May 2012
|
||||||
*
|
*
|
||||||
* Modified to use the MsgTxt field for SINQ
|
* Modified to use the MsgTxt field for SINQ
|
||||||
*
|
*
|
||||||
* Mark Koennecke, January 2019
|
* Mark Koennecke, January 2019
|
||||||
*
|
*
|
||||||
* EXtended with special motor axis for the Selene
|
* EXtended with special motor axis for the Selene
|
||||||
* guide, Mark Koennecke, February 2020
|
* guide, Mark Koennecke, February 2020
|
||||||
********************************************/
|
********************************************/
|
||||||
|
|
||||||
#ifndef pmacAxis_H
|
#ifndef pmacAxis_H
|
||||||
#define pmacAxis_H
|
#define pmacAxis_H
|
||||||
|
|
||||||
#include "SINQAxis.h"
|
|
||||||
#include "SINQController.h"
|
#include "SINQController.h"
|
||||||
|
#include "SINQAxis.h"
|
||||||
|
|
||||||
class pmacController;
|
class pmacController;
|
||||||
class SeleneController;
|
class SeleneController;
|
||||||
|
|
||||||
class pmacAxis : public SINQAxis {
|
class pmacAxis : public SINQAxis
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
/* These are the methods we override from the base class */
|
/* These are the methods we override from the base class */
|
||||||
pmacAxis(pmacController *pController, int axisNo, bool enable = true);
|
pmacAxis(pmacController *pController, int axisNo, bool enable=true);
|
||||||
virtual ~pmacAxis();
|
virtual ~pmacAxis();
|
||||||
asynStatus move(double position, int relative, double min_velocity,
|
asynStatus move(double position, int relative, double min_velocity, double max_velocity, double acceleration);
|
||||||
double max_velocity, double acceleration);
|
asynStatus moveVelocity(double min_velocity, double max_velocity, double acceleration);
|
||||||
asynStatus moveVelocity(double min_velocity, double max_velocity,
|
asynStatus home(double min_velocity, double max_velocity, double acceleration, int forwards);
|
||||||
double acceleration);
|
asynStatus stop(double acceleration);
|
||||||
asynStatus home(double min_velocity, double max_velocity,
|
asynStatus poll(bool *moving);
|
||||||
double acceleration, int forwards);
|
asynStatus setPosition(double position);
|
||||||
asynStatus stop(double acceleration);
|
asynStatus enable(int on);
|
||||||
asynStatus poll(bool *moving);
|
|
||||||
asynStatus setPosition(double position);
|
|
||||||
asynStatus enable(int on);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
pmacController *pC_;
|
pmacController *pC_;
|
||||||
|
|
||||||
|
asynStatus getAxisStatus(bool *moving);
|
||||||
|
asynStatus getAxisInitialStatus(void);
|
||||||
|
|
||||||
asynStatus getAxisStatus(bool *moving);
|
double setpointPosition_;
|
||||||
asynStatus getAxisInitialStatus(void);
|
double encoderPosition_;
|
||||||
|
double currentVelocity_;
|
||||||
|
double velocity_;
|
||||||
|
double accel_;
|
||||||
|
double highLimit_;
|
||||||
|
double lowLimit_;
|
||||||
|
double scale_;
|
||||||
|
double previous_position_;
|
||||||
|
int previous_direction_;
|
||||||
|
int encoder_axis_;
|
||||||
|
int axisErrorCount;
|
||||||
|
|
||||||
double setpointPosition_;
|
time_t startTime;
|
||||||
double encoderPosition_;
|
time_t status6Time;
|
||||||
double currentVelocity_;
|
int starting;
|
||||||
double velocity_;
|
int homing;
|
||||||
double accel_;
|
double statusPos;
|
||||||
double highLimit_;
|
|
||||||
double lowLimit_;
|
|
||||||
double scale_;
|
|
||||||
double previous_position_;
|
|
||||||
int previous_direction_;
|
|
||||||
int encoder_axis_;
|
|
||||||
int axisErrorCount;
|
|
||||||
|
|
||||||
time_t startTime;
|
time_t next_poll;
|
||||||
time_t status6Time;
|
|
||||||
int starting;
|
|
||||||
int homing;
|
|
||||||
double statusPos;
|
|
||||||
|
|
||||||
time_t next_poll;
|
bool autoEnable;
|
||||||
|
|
||||||
bool autoEnable;
|
friend class pmacController;
|
||||||
|
friend class pmacV3Controller;
|
||||||
friend class pmacController;
|
|
||||||
friend class pmacV3Controller;
|
|
||||||
};
|
};
|
||||||
/*--------------------------------------------------------------------------------------------*/
|
/*--------------------------------------------------------------------------------------------*/
|
||||||
class SeleneAxis : public pmacAxis {
|
class SeleneAxis : public pmacAxis
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
SeleneAxis(SeleneController *pController, int axisNo, double limitTarget);
|
SeleneAxis(SeleneController *pController, int axisNo, double limitTarget);
|
||||||
asynStatus move(double position, int relative, double min_velocity,
|
asynStatus move(double position, int relative, double min_velocity, double max_velocity, double acceleration);
|
||||||
double max_velocity, double acceleration);
|
asynStatus setPosition(double position);
|
||||||
asynStatus setPosition(double position);
|
asynStatus home(double min_velocity, double max_velocity, double acceleration, int forwards);
|
||||||
asynStatus home(double min_velocity, double max_velocity,
|
|
||||||
double acceleration, int forwards);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class SeleneController;
|
friend class SeleneController;
|
||||||
friend class pmacController;
|
friend class pmacController;
|
||||||
|
|
||||||
|
private:
|
||||||
|
double limitTarget;
|
||||||
|
asynStatus getSeleneAxisInitialStatus(void);
|
||||||
|
|
||||||
private:
|
|
||||||
double limitTarget;
|
|
||||||
asynStatus getSeleneAxisInitialStatus(void);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Yet another special set of motors for the Selene Guide at AMOR. Each segment
|
Yet another special set of motors for the Selene Guide at AMOR. Each segment can be lifted or tilted. This is
|
||||||
can be lifted or tilted. This is two motors. One acts as a slave and only
|
two motors. One acts as a slave and only writes a new target, the other also sets a new target and sends the
|
||||||
writes a new target, the other also sets a new target and sends the actual
|
actual movement command. Both motors are coordianted in the motor controller in order to avoid tension on
|
||||||
movement command. Both motors are coordianted in the motor controller in order
|
the guide elements. This gaves rise to the function code LIFTSLAVE and LIFTMASTER.
|
||||||
to avoid tension on the guide elements. This gaves rise to the function code
|
|
||||||
LIFTSLAVE and LIFTMASTER.
|
|
||||||
|
|
||||||
In another mode the whole guide can be lifted or tilted. Then motor 1 and 6
|
In another mode the whole guide can be lifted or tilted. Then motor 1 and 6 get new values and one of them
|
||||||
get new values and one of them sends the drive command. This causes all 6
|
sends the drive command. This causes all 6 motors to drive synchronously to their new targets. This is
|
||||||
motors to drive synchronously to their new targets. This is implemented
|
implemented through the LIFTSEGMENT function code.
|
||||||
through the LIFTSEGMENT function code.
|
|
||||||
|
|
||||||
Mark Koennecke, February 2020
|
Mark Koennecke, February 2020
|
||||||
|
|
||||||
The axis should not be enabled automatically
|
The axis should not be enabled automatically
|
||||||
|
|
||||||
Michele Brambilla, February 2020
|
Michele Brambilla, February 2020
|
||||||
|
|
||||||
*/
|
*/
|
||||||
class LiftAxis : public pmacAxis {
|
class LiftAxis : public pmacAxis
|
||||||
public:
|
{
|
||||||
/*
|
public:
|
||||||
The default constructor of LiftAxis just forwards to the pmacAxis
|
LiftAxis(pmacController *pController, int axisNo) : pmacAxis((pmacController *)pController,axisNo) {};
|
||||||
constructor, which has an optional argument "autoenable" with the default
|
asynStatus move(double position, int relative, double min_velocity, double max_velocity, double acceleration);
|
||||||
value "true". However, we want that argument to be false, hence we provide
|
asynStatus poll(bool *moving);
|
||||||
an explicit constructor.
|
asynStatus stop(double acceleration);
|
||||||
*/
|
private:
|
||||||
LiftAxis(pmacController *pController, int axisNo)
|
int waitStart;
|
||||||
: pmacAxis((pmacController *)pController, axisNo, false) {};
|
|
||||||
asynStatus move(double position, int relative, double min_velocity,
|
|
||||||
double max_velocity, double acceleration);
|
|
||||||
asynStatus poll(bool *moving);
|
|
||||||
asynStatus stop(double acceleration);
|
|
||||||
|
|
||||||
private:
|
|
||||||
int waitStart;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/********************************************
|
/********************************************
|
||||||
* Protocol version 3 requires just some minor change
|
* Protocol version 3 requires just some minor change
|
||||||
*
|
*
|
||||||
* Michele Brambilla, February 2022
|
* Michele Brambilla, February 2022
|
||||||
********************************************/
|
********************************************/
|
||||||
|
|
||||||
class pmacV3Axis : public pmacAxis {
|
class pmacV3Axis : public pmacAxis {
|
||||||
public:
|
public:
|
||||||
pmacV3Axis(pmacController *pController, int axisNo);
|
|
||||||
|
|
||||||
asynStatus move(double position, int relative, double min_velocity,
|
pmacV3Axis(pmacController *pController, int axisNo);
|
||||||
double max_velocity, double acceleration);
|
|
||||||
asynStatus poll(bool *moving);
|
|
||||||
|
|
||||||
protected:
|
asynStatus move(double position, int relative, double min_velocity,
|
||||||
int IsEnable;
|
double max_velocity, double acceleration);
|
||||||
double Speed;
|
asynStatus poll(bool *moving);
|
||||||
|
protected:
|
||||||
|
int IsEnable;
|
||||||
|
double Speed;
|
||||||
|
|
||||||
asynStatus getAxisStatus(bool *moving);
|
asynStatus getAxisStatus(bool *moving);
|
||||||
|
|
||||||
friend class pmacController;
|
friend class pmacController;
|
||||||
friend class pmacV3Controller;
|
friend class pmacV3Controller;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------------------------*/
|
||||||
class pmacHRPTAxis : public pmacV3Axis {
|
class pmacHRPTAxis : public pmacV3Axis
|
||||||
public:
|
{
|
||||||
pmacHRPTAxis(pmacController *pController, int axisNo)
|
public:
|
||||||
: pmacV3Axis(pController, axisNo) {};
|
pmacHRPTAxis(pmacController *pController, int axisNo) : pmacV3Axis(pController,axisNo) {};
|
||||||
/**
|
/**
|
||||||
* Override getAxisStatus in order to read the special parameter indicating
|
* Override getAxisStatus in order to read the special parameter indicating a
|
||||||
* a slit blade crash at HRPT
|
* slit blade crash at HRPT
|
||||||
*/
|
*/
|
||||||
asynStatus getAxisStatus(bool *moving);
|
asynStatus getAxisStatus(bool *moving);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class pmacController;
|
friend class pmacController;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Special motors for the AMOR detector movement. The whole
|
* Special motors for the AMOR detector movement. The whole
|
||||||
* command set is different but on a pmac controller. This implements
|
* command set is different but on a pmac controller. This implements
|
||||||
* a coordinated movement of cox, coz and ftz in order not to break
|
* a coordinated movement of cox, coz and ftz in order not to break
|
||||||
* the flight tube which may have been mounted. This is mapped to three
|
* the flight tube which may have been mounted. This is mapped to three
|
||||||
* motors selected via the function code: com, the detector omega, coz,
|
* motors selected via the function code: com, the detector omega, coz,
|
||||||
* the detector z offset and park, for parking the flightpath.
|
* the detector z offset and park, for parking the flightpath.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -182,41 +171,39 @@ class pmacHRPTAxis : public pmacV3Axis {
|
|||||||
#define ADCOZ 2
|
#define ADCOZ 2
|
||||||
#define ADPARK 3
|
#define ADPARK 3
|
||||||
|
|
||||||
class AmorDetectorAxis : public pmacAxis {
|
class AmorDetectorAxis: public pmacAxis {
|
||||||
public:
|
public:
|
||||||
AmorDetectorAxis(pmacController *pController, int axisNo, int function);
|
AmorDetectorAxis(pmacController *pController, int axisNo, int function);
|
||||||
|
|
||||||
asynStatus move(double position, int relative, double min_velocity,
|
asynStatus move(double position, int relative, double min_velocity,
|
||||||
double max_velocity, double acceleration);
|
double max_velocity, double acceleration);
|
||||||
asynStatus poll(bool *moving);
|
asynStatus poll(bool *moving);
|
||||||
asynStatus moveVelocity(double min_velocity, double max_velocity,
|
asynStatus moveVelocity(double min_velocity, double max_velocity, double acceleration);
|
||||||
double acceleration);
|
asynStatus home(double min_velocity, double max_velocity, double acceleration, int forwards);
|
||||||
asynStatus home(double min_velocity, double max_velocity,
|
asynStatus stop(double acceleration);
|
||||||
double acceleration, int forwards);
|
asynStatus setPosition(double position);
|
||||||
asynStatus stop(double acceleration);
|
|
||||||
asynStatus setPosition(double position);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int _function;
|
int _function;
|
||||||
int det_starting;
|
int det_starting;
|
||||||
time_t det_startTime;
|
time_t det_startTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
class GirderAxis : public pmacV3Axis {
|
|
||||||
|
class GirderAxis: public pmacV3Axis {
|
||||||
public:
|
public:
|
||||||
GirderAxis(pmacController *pController, int axisNo);
|
GirderAxis(pmacController *pController, int axisNo);
|
||||||
asynStatus move(double position, int relative, double min_velocity,
|
asynStatus move(double position, int relative, double min_velocity, double max_velocity, double acceleration);
|
||||||
double max_velocity, double acceleration);
|
|
||||||
asynStatus stop(double acceleration);
|
asynStatus stop(double acceleration);
|
||||||
asynStatus poll(bool *moving);
|
asynStatus poll(bool *moving);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int IsEnable;
|
int IsEnable;
|
||||||
|
|
||||||
friend class pmacController;
|
friend class pmacController;
|
||||||
friend class pmacV3Controller;
|
friend class pmacV3Controller;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* pmacAxis_H */
|
#endif /* pmacAxis_H */
|
||||||
|
@ -5,9 +5,9 @@ registrar(EL734Register)
|
|||||||
registrar(PhytronRegister)
|
registrar(PhytronRegister)
|
||||||
registrar(EuroMoveRegister)
|
registrar(EuroMoveRegister)
|
||||||
registrar(NanotecRegister)
|
registrar(NanotecRegister)
|
||||||
# registrar(pmacControllerRegister)
|
registrar(pmacControllerRegister)
|
||||||
registrar(C804ControllerRegister)
|
registrar(C804ControllerRegister)
|
||||||
# registrar(pmacAsynIPPortRegister)
|
registrar(pmacAsynIPPortRegister)
|
||||||
registrar(MasterMACSRegister)
|
registrar(MasterMACSRegister)
|
||||||
registrar(SINQControllerRegister)
|
registrar(SINQControllerRegister)
|
||||||
|
|
||||||
|
@ -1,213 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
# List of tuples which encodes the states given in the file description.
|
|
||||||
# Index first with the bit index, then with the bit value
|
|
||||||
interpretation = [
|
|
||||||
("Not ready to be switched on", "Ready to be switched on"), # Bit 0
|
|
||||||
("Not switched on", "Switched on"), # Bit 1
|
|
||||||
("Disabled", "Enabled"), # Bit 2
|
|
||||||
("Ok", "Fault condition set"), # Bit 3
|
|
||||||
("Motor supply voltage absent ", "Motor supply voltage present"), # Bit 4
|
|
||||||
("Motor performs quick stop", "Ok"), # Bit 5
|
|
||||||
("Switch on enabled", "Switch on disabled"), # Bit 6
|
|
||||||
("Ok", "RWarning: Movement function was called while motor is still moving. The function call is ignored"), # Bit 7
|
|
||||||
("Motor is idle", "Motor is currently moving"), # Bit 8
|
|
||||||
("Motor does not execute command messages (local mode)", "Motor does execute command messages (remote mode)"), # Bit 9
|
|
||||||
("Target not reached", "Target reached"), # Bit 10
|
|
||||||
("Ok", "Internal limit active"), # Bit 11
|
|
||||||
("Not specified", "Not specified"), # Bit 12
|
|
||||||
("Not specified", "Not specified"), # Bit 13
|
|
||||||
("No event set or event has not occurred yet", "Set event has occurred"), # Bit 14
|
|
||||||
("Axis off (power disabled)", "Axis on (power enabled)"), # Bit 15
|
|
||||||
]
|
|
||||||
|
|
||||||
def decode(value, big_endian: bool = False):
|
|
||||||
|
|
||||||
interpreted = []
|
|
||||||
|
|
||||||
bit_list = [(value >> shift_ind) & 1
|
|
||||||
for shift_ind in range(value.bit_length())] # little endian
|
|
||||||
|
|
||||||
if big_endian:
|
|
||||||
bit_list.reverse() # big endian
|
|
||||||
|
|
||||||
for (bit, interpretations) in zip(bit_list, interpretation):
|
|
||||||
interpreted.append(interpretations[bit])
|
|
||||||
return (bit_list, interpreted)
|
|
||||||
|
|
||||||
def print_decoded(bit_list, interpreted):
|
|
||||||
for (idx, (bit_value, msg)) in enumerate(zip(bit_list, interpreted)):
|
|
||||||
print(f"Bit {idx} = {bit_value}: {msg}")
|
|
||||||
|
|
||||||
def interactive():
|
|
||||||
|
|
||||||
# Imported here, because curses is not available in Windows. Using the
|
|
||||||
# interactive mode therefore fails on Windows, but at least the single
|
|
||||||
# command mode can be used (which would not be possible if we would import
|
|
||||||
# curses at the top level)
|
|
||||||
import curses
|
|
||||||
|
|
||||||
stdscr = curses.initscr()
|
|
||||||
curses.noecho()
|
|
||||||
curses.cbreak()
|
|
||||||
stdscr.keypad(True)
|
|
||||||
stdscr.scrollok(True)
|
|
||||||
|
|
||||||
stdscr.addstr(">> ")
|
|
||||||
stdscr.refresh()
|
|
||||||
|
|
||||||
history = [""]
|
|
||||||
ptr = len(history) - 1
|
|
||||||
|
|
||||||
while True:
|
|
||||||
c = stdscr.getch()
|
|
||||||
if c == curses.KEY_RIGHT:
|
|
||||||
(y, x) = stdscr.getyx()
|
|
||||||
if x < len(history[ptr]) + 3:
|
|
||||||
stdscr.move(y, x+1)
|
|
||||||
stdscr.refresh()
|
|
||||||
elif c == curses.KEY_LEFT:
|
|
||||||
(y, x) = stdscr.getyx()
|
|
||||||
if x > 3:
|
|
||||||
stdscr.move(y, x-1)
|
|
||||||
stdscr.refresh()
|
|
||||||
elif c == curses.KEY_UP:
|
|
||||||
if ptr > 0:
|
|
||||||
ptr -= 1
|
|
||||||
stdscr.addch("\r")
|
|
||||||
stdscr.clrtoeol()
|
|
||||||
stdscr.addstr(">> " + history[ptr])
|
|
||||||
elif c == curses.KEY_DOWN:
|
|
||||||
if ptr < len(history) - 1:
|
|
||||||
ptr += 1
|
|
||||||
stdscr.addch("\r")
|
|
||||||
stdscr.clrtoeol()
|
|
||||||
stdscr.addstr(">> " + history[ptr])
|
|
||||||
elif c == curses.KEY_ENTER or c == ord('\n') or c == ord('\r'):
|
|
||||||
if history[ptr] == 'quit':
|
|
||||||
break
|
|
||||||
|
|
||||||
# because of arrow keys move back to the end of the line
|
|
||||||
(y, x) = stdscr.getyx()
|
|
||||||
stdscr.move(y, 3+len(history[ptr]))
|
|
||||||
|
|
||||||
if history[ptr]:
|
|
||||||
result = interpret_inputs(history[ptr].split())
|
|
||||||
if result is None:
|
|
||||||
stdscr.addstr(f"\nBAD INPUT: Expected input of 'value [big_endian]', where 'value' is an int or a float and 'big_endian' is an optional boolean argument.")
|
|
||||||
else:
|
|
||||||
(arg, big_endian) = result
|
|
||||||
(bit_list, interpreted) = decode(arg, big_endian)
|
|
||||||
for (idx, (bit_value, msg)) in enumerate(zip(bit_list, interpreted)):
|
|
||||||
stdscr.addstr(f"\nBit {idx} = {bit_value}: {msg}")
|
|
||||||
stdscr.refresh()
|
|
||||||
|
|
||||||
if ptr == len(history) - 1 and history[ptr] != "":
|
|
||||||
history += [""]
|
|
||||||
else:
|
|
||||||
history[-1] = ""
|
|
||||||
ptr = len(history) - 1
|
|
||||||
|
|
||||||
stdscr.addstr("\n>> ")
|
|
||||||
stdscr.refresh()
|
|
||||||
|
|
||||||
else:
|
|
||||||
if ptr < len(history) - 1: # Modifying previous input
|
|
||||||
if len(history[-1]) == 0:
|
|
||||||
history[-1] = history[ptr]
|
|
||||||
ptr = len(history) - 1
|
|
||||||
|
|
||||||
else:
|
|
||||||
history += [history[ptr]]
|
|
||||||
ptr = len(history) - 1
|
|
||||||
|
|
||||||
if c == curses.KEY_BACKSPACE:
|
|
||||||
if len(history[ptr]) == 0:
|
|
||||||
continue
|
|
||||||
(y, x) = stdscr.getyx()
|
|
||||||
history[ptr] = history[ptr][0:x-4] + history[ptr][x-3:]
|
|
||||||
stdscr.addch("\r")
|
|
||||||
stdscr.clrtoeol()
|
|
||||||
stdscr.addstr(">> " + history[ptr])
|
|
||||||
stdscr.move(y, x-1)
|
|
||||||
stdscr.refresh()
|
|
||||||
|
|
||||||
else:
|
|
||||||
(y, x) = stdscr.getyx()
|
|
||||||
history[ptr] = history[ptr][0:x-3] + chr(c) + history[ptr][x-3:]
|
|
||||||
stdscr.addch("\r")
|
|
||||||
stdscr.clrtoeol()
|
|
||||||
stdscr.addstr(">> " + history[ptr])
|
|
||||||
stdscr.move(y, x+1)
|
|
||||||
stdscr.refresh()
|
|
||||||
|
|
||||||
# to quit
|
|
||||||
curses.nocbreak()
|
|
||||||
stdscr.keypad(False)
|
|
||||||
curses.echo()
|
|
||||||
curses.endwin()
|
|
||||||
|
|
||||||
def interpret_inputs(inputs):
|
|
||||||
|
|
||||||
number = None
|
|
||||||
big_endian = False
|
|
||||||
try:
|
|
||||||
number = int(float(inputs[0]))
|
|
||||||
if len(inputs) > 1:
|
|
||||||
second_arg = inputs[1]
|
|
||||||
if second_arg == "True" or second_arg == "true":
|
|
||||||
big_endian = True
|
|
||||||
elif second_arg == "False" or second_arg == "false":
|
|
||||||
big_endian = False
|
|
||||||
else:
|
|
||||||
big_endian = bool(int(second_arg))
|
|
||||||
return (number, big_endian)
|
|
||||||
except:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
from sys import argv
|
|
||||||
|
|
||||||
if len(argv) == 1:
|
|
||||||
# Start interactive mode
|
|
||||||
interactive()
|
|
||||||
else:
|
|
||||||
|
|
||||||
result = interpret_inputs(argv[1:])
|
|
||||||
|
|
||||||
if result is None:
|
|
||||||
print("""
|
|
||||||
Decode R10 message of MasterMACs
|
|
||||||
------------------
|
|
||||||
|
|
||||||
MasterMACs returns its status message (R10) as a floating-point number.
|
|
||||||
The bits of this float encode different states. These states are stored
|
|
||||||
in the interpretation variable.
|
|
||||||
|
|
||||||
This script can be used in two different ways:
|
|
||||||
|
|
||||||
Option 1: Single Command
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
Usage: decodeMasterMACStatusR10.py value [big_endian]
|
|
||||||
|
|
||||||
'value' is the return value of a R10 command. This value is interpreted
|
|
||||||
bit-wise and the result is printed out. The optional second argument can
|
|
||||||
be used to specify whether the input value needs to be interpreted as
|
|
||||||
little or big endian. Default is False.
|
|
||||||
|
|
||||||
Option 2: CLI Mode
|
|
||||||
------------------
|
|
||||||
|
|
||||||
Usage: decodeMasterMACStatusR10.py
|
|
||||||
|
|
||||||
A prompt will be opened. Type in the return value of a R10 command, hit
|
|
||||||
enter and the interpretation will be printed in the prompt. After that,
|
|
||||||
the next value can be typed in. Type 'quit' to close the prompt.
|
|
||||||
""")
|
|
||||||
else:
|
|
||||||
print("Motor status")
|
|
||||||
print("============")
|
|
||||||
(arg, big_endian) = result
|
|
||||||
(bit_list, interpreted) = decode(arg, big_endian)
|
|
||||||
print_decoded(bit_list, interpreted)
|
|
@ -64,7 +64,6 @@ if __name__ == "__main__":
|
|||||||
curses.noecho()
|
curses.noecho()
|
||||||
curses.cbreak()
|
curses.cbreak()
|
||||||
stdscr.keypad(True)
|
stdscr.keypad(True)
|
||||||
stdscr.scrollok(True)
|
|
||||||
|
|
||||||
stdscr.addstr(">> ")
|
stdscr.addstr(">> ")
|
||||||
stdscr.refresh()
|
stdscr.refresh()
|
||||||
|
Reference in New Issue
Block a user