Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
d975af75a2 | |||
55aabb0468 | |||
755ae42b3b | |||
4ad842c097 | |||
cb91a8aa36 |
246
.clang-format
Normal file
246
.clang-format
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
# BasedOnStyle: LLVM
|
||||||
|
AccessModifierOffset: -2
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignArrayOfStructures: None
|
||||||
|
AlignConsecutiveAssignments:
|
||||||
|
Enabled: false
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
AlignFunctionPointers: false
|
||||||
|
PadOperators: true
|
||||||
|
AlignConsecutiveBitFields:
|
||||||
|
Enabled: false
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
AlignFunctionPointers: false
|
||||||
|
PadOperators: false
|
||||||
|
AlignConsecutiveDeclarations:
|
||||||
|
Enabled: false
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
AlignFunctionPointers: false
|
||||||
|
PadOperators: false
|
||||||
|
AlignConsecutiveMacros:
|
||||||
|
Enabled: false
|
||||||
|
AcrossEmptyLines: false
|
||||||
|
AcrossComments: false
|
||||||
|
AlignCompound: false
|
||||||
|
AlignFunctionPointers: 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
|
||||||
|
AllowBreakBeforeNoexceptSpecifier: Never
|
||||||
|
AllowShortBlocksOnASingleLine: Never
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortCompoundRequirementOnASingleLine: true
|
||||||
|
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
|
||||||
|
BreakAdjacentStringLiterals: true
|
||||||
|
BreakAfterAttributes: Leave
|
||||||
|
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
|
||||||
|
PenaltyBreakScopeResolution: 500
|
||||||
|
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
|
||||||
|
SkipMacroDefinitionBody: false
|
||||||
|
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
|
||||||
|
AfterPlacementOperator: true
|
||||||
|
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: 8
|
||||||
|
UseTab: Never
|
||||||
|
VerilogBreakBetweenInstancePorts: true
|
||||||
|
WhitespaceSensitiveMacros:
|
||||||
|
- BOOST_PP_STRINGIZE
|
||||||
|
- CF_SWIFT_NAME
|
||||||
|
- NS_SWIFT_NAME
|
||||||
|
- PP_STRINGIZE
|
||||||
|
- STRINGIZE
|
||||||
|
---
|
||||||
|
|
@ -1,6 +1,6 @@
|
|||||||
default:
|
default:
|
||||||
image: docker.psi.ch:5000/sinqdev/sinqepics:latest
|
image: docker.psi.ch:5000/sinqdev/sinqepics:latest
|
||||||
|
|
||||||
stages:
|
stages:
|
||||||
- lint
|
- lint
|
||||||
- build
|
- build
|
||||||
@ -9,7 +9,7 @@ stages:
|
|||||||
cppcheck:
|
cppcheck:
|
||||||
stage: lint
|
stage: lint
|
||||||
script:
|
script:
|
||||||
- cppcheck --std=c++17 --addon=cert --addon=misc --error-exitcode=1 src/*.cpp
|
- cppcheck --std=c++17 --addon=cert --addon=misc --suppress=cert-STR07-C --error-exitcode=1 src/*.cpp
|
||||||
artifacts:
|
artifacts:
|
||||||
expire_in: 1 week
|
expire_in: 1 week
|
||||||
tags:
|
tags:
|
||||||
@ -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
@ -13,7 +13,7 @@ REQUIRED+=sinqMotor
|
|||||||
motorBase_VERSION=7.2.2
|
motorBase_VERSION=7.2.2
|
||||||
|
|
||||||
# Specify the version of sinqMotor we want to build against
|
# Specify the version of sinqMotor we want to build against
|
||||||
sinqMotor_VERSION=0.7.0
|
sinqMotor_VERSION=0.8.0
|
||||||
|
|
||||||
# These headers allow to depend on this library for derived drivers.
|
# These headers allow to depend on this library for derived drivers.
|
||||||
HEADERS += src/masterMacsAxis.h
|
HEADERS += src/masterMacsAxis.h
|
||||||
|
50
README.md
50
README.md
@ -18,22 +18,42 @@ The folder "utils" contains utility scripts for working with masterMacs motor co
|
|||||||
masterMacs exposes the following IOC shell functions (all in masterMacsController.cpp):
|
masterMacs exposes the following IOC shell functions (all in masterMacsController.cpp):
|
||||||
- `masterMacsController`: Create a new controller object.
|
- `masterMacsController`: Create a new controller object.
|
||||||
- `masterMacsAxis`: Create a new axis object.
|
- `masterMacsAxis`: Create a new axis object.
|
||||||
These functions are parametrized as follows:
|
|
||||||
|
The full mcu.cmd file looks like this:
|
||||||
|
|
||||||
```
|
```
|
||||||
masterMacsController(
|
# Define the name of the controller and the corresponding port
|
||||||
"$(NAME)", # Name of the MCU, e.g. mcu1. This parameter should be provided by an environment variable.
|
epicsEnvSet("NAME","mcu")
|
||||||
"$(ASYN_PORT)", # IP-Port of the MCU. This parameter should be provided by an environment variable.
|
epicsEnvSet("ASYN_PORT","p$(NAME)")
|
||||||
8, # Maximum number of axes
|
|
||||||
0.05, # Busy poll period in seconds
|
# 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
|
||||||
1, # Idle poll period in seconds
|
drvAsynIPPortConfigure("$(ASYN_PORT)","172.28.101.24:1025")
|
||||||
0.05 # Communication timeout in seconds
|
|
||||||
);
|
# Create the controller object with the defined name and connect it to the socket via the port name.
|
||||||
```
|
# The other parameters are as follows:
|
||||||
```
|
# 8: Maximum number of axes
|
||||||
masterMacsAxis(
|
# 0.05: Busy poll period in seconds
|
||||||
"$(NAME)", # Name of the associated MCU, e.g. mcu1. This parameter should be provided by an environment variable.
|
# 1: Idle poll period in seconds
|
||||||
1, # Index of the axis.
|
# 1: Socket communication timeout in seconds
|
||||||
);
|
masterMacsController("$(NAME)", "$(ASYN_PORT)", 8, 0.05, 1, 1);
|
||||||
|
|
||||||
|
# Define some axes for the specified MCU at the given slot (1, 2 and 5). No slot may be used twice!
|
||||||
|
masterMacsAxis("$(NAME)",1);
|
||||||
|
masterMacsAxis("$(NAME)",2);
|
||||||
|
masterMacsAxis("$(NAME)",5);
|
||||||
|
|
||||||
|
# Set the number of subsequent timeouts
|
||||||
|
setMaxSubsequentTimeouts("$(NAME)", 20);
|
||||||
|
|
||||||
|
# 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")
|
||||||
|
dbLoadTemplate("$(TOP)/$(NAME).substitutions", "INSTR=$(INSTR)$(NAME):,CONTROLLER=$(NAME)")
|
||||||
|
epicsEnvSet("SINQDBPATH","$(masterMacs_DB)/masterMacs.db")
|
||||||
|
dbLoadTemplate("$(TOP)/$(NAME).substitutions", "INSTR=$(INSTR)$(NAME):,CONTROLLER=$(NAME)")
|
||||||
|
dbLoadRecords("$(sinqMotor_DB)/asynRecord.db","P=$(INSTR)$(NAME),PORT=$(ASYN_PORT)")
|
||||||
```
|
```
|
||||||
|
|
||||||
### Versioning
|
### Versioning
|
||||||
|
@ -34,6 +34,34 @@ static void epicsInithookFunction(initHookState iState) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void appendErrorMessage(char *fullMessage, size_t capacityFullMessage,
|
||||||
|
const char *toBeAppended) {
|
||||||
|
size_t lenFullMessage = strlen(fullMessage);
|
||||||
|
size_t lenToBeAppended = strlen(toBeAppended);
|
||||||
|
|
||||||
|
if (lenFullMessage == 0) {
|
||||||
|
// The error message is empty -> Just copy the content of toBeAppended
|
||||||
|
// into fullMessage, if the formers capacity suffices
|
||||||
|
if (lenToBeAppended < capacityFullMessage) {
|
||||||
|
|
||||||
|
// We check before that the capacity of fullMessage is sufficient
|
||||||
|
strcpy(fullMessage, toBeAppended);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Append the message and add a linebreak in between, if the capacity of
|
||||||
|
// fullMessage suffices. We need capacity for one additional character
|
||||||
|
// because of the linebreak.
|
||||||
|
if (lenFullMessage + lenToBeAppended + 1 < capacityFullMessage) {
|
||||||
|
// Append the linebreak and readd the null terminator behind it
|
||||||
|
// fullMessage[lenFullMessage] = '\n';
|
||||||
|
// fullMessage[lenFullMessage + 1] = '\0';
|
||||||
|
|
||||||
|
// We check before that the capacity of fullMessage is sufficient
|
||||||
|
strcat(fullMessage, toBeAppended);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
masterMacsAxis::masterMacsAxis(masterMacsController *pC, int axisNo)
|
masterMacsAxis::masterMacsAxis(masterMacsController *pC, int axisNo)
|
||||||
: sinqAxis(pC, axisNo), pC_(pC) {
|
: sinqAxis(pC, axisNo), pC_(pC) {
|
||||||
|
|
||||||
@ -340,8 +368,9 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
|
|||||||
return rw_status;
|
return rw_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if we reached the target
|
// If the motor is switched off or if it reached its target, it is not
|
||||||
if (targetReached()) {
|
// moving.
|
||||||
|
if (targetReached() || !switchedOn()) {
|
||||||
*moving = false;
|
*moving = false;
|
||||||
} else {
|
} else {
|
||||||
*moving = true;
|
*moving = true;
|
||||||
@ -362,70 +391,26 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
|
|||||||
Read out the error if either a fault condition status flag has been set or
|
Read out the error if either a fault condition status flag has been set or
|
||||||
if a movement has just ended.
|
if a movement has just ended.
|
||||||
*/
|
*/
|
||||||
if (faultConditionSet()) {
|
msgPrintControlKey keyError = msgPrintControlKey(
|
||||||
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
||||||
|
|
||||||
|
if (faultConditionSet() || !(*moving)) {
|
||||||
rw_status = readAxisError();
|
rw_status = readAxisError();
|
||||||
|
|
||||||
if (shortCircuit()) {
|
/*
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
A communication error is a special case. If a communication between
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nShort "
|
controller and axis error occurred, all subsequent errors are ignored,
|
||||||
"circuit fault.\n",
|
since this information is not reliable.
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
*/
|
||||||
|
|
||||||
pl_status =
|
|
||||||
setStringParam(pC_->motorMessageText_,
|
|
||||||
"Short circuit error. Please call the support.");
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
poll_status = asynError;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (encoderError()) {
|
|
||||||
asynPrint(
|
|
||||||
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nEncoder error.\n",
|
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
|
||||||
|
|
||||||
pl_status =
|
|
||||||
setStringParam(pC_->motorMessageText_,
|
|
||||||
"Encoder error. Please call the support.");
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
poll_status = asynError;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (followingError()) {
|
|
||||||
asynPrint(
|
|
||||||
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nMaximum allowed "
|
|
||||||
"following error exceeded.\n",
|
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
|
||||||
|
|
||||||
pl_status = setStringParam(
|
|
||||||
pC_->motorMessageText_,
|
|
||||||
"Maximum allowed following error exceeded.Check if movement "
|
|
||||||
"range is blocked. Otherwise please call the support.");
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
poll_status = asynError;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (communicationError()) {
|
if (communicationError()) {
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
if (pC_->msgPrintControl_.shouldBePrinted(keyError, true,
|
||||||
"Controller \"%s\", axis %d => %s, line "
|
pC_->pasynUserSelf)) {
|
||||||
"%d\nCommunication error.\n",
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
"Controller \"%s\", axis %d => %s, line "
|
||||||
|
"%d\nCommunication error.%s\n",
|
||||||
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
pC_->msgPrintControl_.getSuffix());
|
||||||
|
}
|
||||||
|
|
||||||
pl_status =
|
pl_status =
|
||||||
setStringParam(pC_->motorMessageText_,
|
setStringParam(pC_->motorMessageText_,
|
||||||
@ -438,172 +423,164 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
poll_status = asynError;
|
poll_status = asynError;
|
||||||
}
|
} else {
|
||||||
|
|
||||||
if (feedbackError()) {
|
// This buffer must be initialized to zero because we build the
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
// error message by appending strings.
|
||||||
"Controller \"%s\", axis %d => %s, line "
|
char userMessage[pC_->MAXBUF_] = {0};
|
||||||
"%d\nFeedback error.\n",
|
char shellMessage[pC_->MAXBUF_] = {0};
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
|
||||||
|
|
||||||
pl_status =
|
// Concatenate all other errors
|
||||||
setStringParam(pC_->motorMessageText_,
|
if (shortCircuit()) {
|
||||||
"Feedback error. Please call the support.");
|
appendErrorMessage(shellMessage, sizeof(shellMessage),
|
||||||
|
"Short circuit fault.");
|
||||||
|
appendErrorMessage(
|
||||||
|
userMessage, sizeof(userMessage),
|
||||||
|
"Short circuit error. Please call the support.");
|
||||||
|
|
||||||
|
poll_status = asynError;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (encoderError()) {
|
||||||
|
appendErrorMessage(shellMessage, sizeof(shellMessage),
|
||||||
|
"Encoder error.");
|
||||||
|
appendErrorMessage(userMessage, sizeof(userMessage),
|
||||||
|
"Encoder error. Please call the support.");
|
||||||
|
|
||||||
|
poll_status = asynError;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (followingError()) {
|
||||||
|
appendErrorMessage(
|
||||||
|
shellMessage, sizeof(shellMessage),
|
||||||
|
"Maximum callowed following error exceeded.");
|
||||||
|
appendErrorMessage(
|
||||||
|
userMessage, sizeof(userMessage),
|
||||||
|
"Maximum allowed following error exceeded.Check if "
|
||||||
|
"movement range is blocked. Otherwise please call the "
|
||||||
|
"support.");
|
||||||
|
|
||||||
|
poll_status = asynError;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (feedbackError()) {
|
||||||
|
appendErrorMessage(shellMessage, sizeof(shellMessage),
|
||||||
|
"Feedback error.");
|
||||||
|
appendErrorMessage(userMessage, sizeof(userMessage),
|
||||||
|
"Feedback error. Please call the support.");
|
||||||
|
|
||||||
|
poll_status = asynError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Either the software limits or the end switches of the controller
|
||||||
|
have been hit. Since the EPICS limits are derived from the software
|
||||||
|
limits and are a little bit smaller, these error cases can only
|
||||||
|
happen if either the axis has an incremental encoder which is not
|
||||||
|
properly homed or if a bug occured.
|
||||||
|
*/
|
||||||
|
if (positiveLimitSwitch() || negativeLimitSwitch() ||
|
||||||
|
positiveSoftwareLimit() || negativeSoftwareLimit()) {
|
||||||
|
|
||||||
|
// Distinction for developers
|
||||||
|
if (positiveLimitSwitch()) {
|
||||||
|
appendErrorMessage(shellMessage, sizeof(shellMessage),
|
||||||
|
"Positive limit switch.");
|
||||||
|
}
|
||||||
|
if (negativeLimitSwitch()) {
|
||||||
|
appendErrorMessage(shellMessage, sizeof(shellMessage),
|
||||||
|
"Negative limit switch.");
|
||||||
|
}
|
||||||
|
if (positiveSoftwareLimit()) {
|
||||||
|
appendErrorMessage(shellMessage, sizeof(shellMessage),
|
||||||
|
"Positive software limit.");
|
||||||
|
}
|
||||||
|
if (negativeSoftwareLimit()) {
|
||||||
|
appendErrorMessage(shellMessage, sizeof(shellMessage),
|
||||||
|
"Negative software limit.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generic error message for user
|
||||||
|
appendErrorMessage(
|
||||||
|
userMessage, sizeof(userMessage),
|
||||||
|
"Software limits or end switch hit. Try homing the motor, "
|
||||||
|
"moving in the opposite direction or check the SPS for "
|
||||||
|
"errors (if available). Otherwise please call the "
|
||||||
|
"support.");
|
||||||
|
|
||||||
|
poll_status = asynError;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (overCurrent()) {
|
||||||
|
appendErrorMessage(shellMessage, sizeof(shellMessage),
|
||||||
|
"Overcurrent error.");
|
||||||
|
appendErrorMessage(
|
||||||
|
userMessage, sizeof(userMessage),
|
||||||
|
"Overcurrent error. Please call the support.");
|
||||||
|
|
||||||
|
poll_status = asynError;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (overTemperature()) {
|
||||||
|
appendErrorMessage(shellMessage, sizeof(shellMessage),
|
||||||
|
"Overtemperature error.");
|
||||||
|
appendErrorMessage(
|
||||||
|
userMessage, sizeof(userMessage),
|
||||||
|
"Overtemperature error. Please call the support.");
|
||||||
|
|
||||||
|
poll_status = asynError;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (overVoltage()) {
|
||||||
|
appendErrorMessage(shellMessage, sizeof(shellMessage),
|
||||||
|
"Overvoltage error.");
|
||||||
|
appendErrorMessage(
|
||||||
|
userMessage, sizeof(userMessage),
|
||||||
|
"Overvoltage error. Please call the support.");
|
||||||
|
|
||||||
|
poll_status = asynError;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (underVoltage()) {
|
||||||
|
appendErrorMessage(shellMessage, sizeof(shellMessage),
|
||||||
|
"Undervoltage error.");
|
||||||
|
appendErrorMessage(
|
||||||
|
userMessage, sizeof(userMessage),
|
||||||
|
"Undervoltage error. Please call the support.");
|
||||||
|
|
||||||
|
poll_status = asynError;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stoFault()) {
|
||||||
|
appendErrorMessage(shellMessage, sizeof(shellMessage),
|
||||||
|
"STO input is on disable state.");
|
||||||
|
appendErrorMessage(userMessage, sizeof(userMessage),
|
||||||
|
"STO fault. Please call the support.");
|
||||||
|
|
||||||
|
poll_status = asynError;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen(shellMessage) > 0) {
|
||||||
|
if (pC_->msgPrintControl_.shouldBePrinted(keyError, true,
|
||||||
|
pC_->pasynUserSelf)) {
|
||||||
|
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
|
"Controller \"%s\", axis %d => %s, line "
|
||||||
|
"%d\n%s.%s\n",
|
||||||
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__,
|
||||||
|
__LINE__, shellMessage,
|
||||||
|
pC_->msgPrintControl_.getSuffix());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pl_status = setStringParam(pC_->motorMessageText_, userMessage);
|
||||||
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__,
|
||||||
__LINE__);
|
__LINE__);
|
||||||
}
|
}
|
||||||
|
|
||||||
poll_status = asynError;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Either the software limits or the end switches of the controller have
|
|
||||||
been hit. Since the EPICS limits are derived from the software limits
|
|
||||||
and are a little bit smaller, these error cases can only happen if
|
|
||||||
either the axis has an incremental encoder which is not properly homed
|
|
||||||
or if a bug occured.
|
|
||||||
*/
|
|
||||||
if (positiveLimitSwitch() || negativeLimitSwitch() ||
|
|
||||||
positiveSoftwareLimit() || negativeSoftwareLimit()) {
|
|
||||||
|
|
||||||
// Distinction for developers
|
|
||||||
if (positiveLimitSwitch()) {
|
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nAxis "
|
|
||||||
"hit the positive limit end switch.\n",
|
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
if (negativeLimitSwitch()) {
|
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nAxis "
|
|
||||||
"hit the negative limit end switch.\n",
|
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
if (positiveSoftwareLimit()) {
|
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nAxis "
|
|
||||||
"hit the positive software limit.\n",
|
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
if (negativeSoftwareLimit()) {
|
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nAxis "
|
|
||||||
"hit the negative software limit.\n",
|
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generic error message for user
|
|
||||||
pl_status = setStringParam(
|
|
||||||
pC_->motorMessageText_,
|
|
||||||
"Software limits or end switch hit. Try homing the motor, "
|
|
||||||
"moving in the opposite direction or check the SPS for "
|
|
||||||
"errors (if available). Otherwise please call the "
|
|
||||||
"support.");
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
poll_status = asynError;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (overCurrent()) {
|
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nOvercurrent "
|
|
||||||
"error.\n",
|
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
|
||||||
|
|
||||||
pl_status =
|
|
||||||
setStringParam(pC_->motorMessageText_,
|
|
||||||
"Overcurrent error. Please call the support.");
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
poll_status = asynError;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (overTemperature()) {
|
|
||||||
asynPrint(
|
|
||||||
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nOvertemperature "
|
|
||||||
"error.\n",
|
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
|
||||||
|
|
||||||
pl_status = setStringParam(
|
|
||||||
pC_->motorMessageText_,
|
|
||||||
"Overtemperature error. Please call the support.");
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
poll_status = asynError;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (overVoltage()) {
|
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nOvervoltage "
|
|
||||||
"error.\n",
|
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
|
||||||
|
|
||||||
pl_status =
|
|
||||||
setStringParam(pC_->motorMessageText_,
|
|
||||||
"Overvoltage error. Please call the support.");
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
poll_status = asynError;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (underVoltage()) {
|
|
||||||
asynPrint(
|
|
||||||
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nUndervoltage "
|
|
||||||
"error.\n",
|
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
|
||||||
|
|
||||||
pl_status =
|
|
||||||
setStringParam(pC_->motorMessageText_,
|
|
||||||
"Undervoltage error. Please call the support.");
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
poll_status = asynError;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stoFault()) {
|
|
||||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nSTO fault - "
|
|
||||||
"STO input is on disable state.\n",
|
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
|
||||||
|
|
||||||
pl_status = setStringParam(pC_->motorMessageText_,
|
|
||||||
"STO fault. Please call the support.");
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
|
||||||
axisNo_, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
poll_status = asynError;
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
pC_->msgPrintControl_.resetCount(keyError);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read out the limits, if the motor is not moving
|
// Read out the limits, if the motor is not moving
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
#include <bitset>
|
#include <bitset>
|
||||||
|
|
||||||
// Forward declaration of the controller class to resolve the cyclic dependency
|
// Forward declaration of the controller class to resolve the cyclic dependency
|
||||||
// between C804Controller.h and C804Axis.h. See
|
// between the controller and the axis .h-file. See
|
||||||
// https://en.cppreference.com/w/cpp/language/class.
|
// https://en.cppreference.com/w/cpp/language/class.
|
||||||
class masterMacsController;
|
class masterMacsController;
|
||||||
|
|
||||||
|
@ -117,39 +117,18 @@ Access one of the axes of the controller via the axis adress stored in asynUser.
|
|||||||
If the axis does not exist or is not a Axis, a nullptr is returned and an
|
If the axis does not exist or is not a Axis, a nullptr is returned and an
|
||||||
error is emitted.
|
error is emitted.
|
||||||
*/
|
*/
|
||||||
masterMacsAxis *masterMacsController::getAxis(asynUser *pasynUser) {
|
masterMacsAxis *masterMacsController::getMasterMacsAxis(asynUser *pasynUser) {
|
||||||
asynMotorAxis *asynAxis = asynMotorController::getAxis(pasynUser);
|
asynMotorAxis *asynAxis = asynMotorController::getAxis(pasynUser);
|
||||||
return masterMacsController::castToAxis(asynAxis);
|
return dynamic_cast<masterMacsAxis *>(asynAxis);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Access one of the axes of the controller via the axis index.
|
Access one of the axes of the controller via the axis index.
|
||||||
If the axis does not exist or is not a Axis, the function must return Null
|
If the axis does not exist or is not a Axis, the function must return Null
|
||||||
*/
|
*/
|
||||||
masterMacsAxis *masterMacsController::getAxis(int axisNo) {
|
masterMacsAxis *masterMacsController::getMasterMacsAxis(int axisNo) {
|
||||||
asynMotorAxis *asynAxis = asynMotorController::getAxis(axisNo);
|
asynMotorAxis *asynAxis = asynMotorController::getAxis(axisNo);
|
||||||
return masterMacsController::castToAxis(asynAxis);
|
return dynamic_cast<masterMacsAxis *>(asynAxis);
|
||||||
}
|
|
||||||
|
|
||||||
masterMacsAxis *masterMacsController::castToAxis(asynMotorAxis *asynAxis) {
|
|
||||||
|
|
||||||
// =========================================================================
|
|
||||||
|
|
||||||
// If the axis slot of the pAxes_ array is empty, a nullptr must be returned
|
|
||||||
if (asynAxis == nullptr) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Here, an error is emitted since asyn_axis is not a nullptr but also not
|
|
||||||
// an instance of Axis
|
|
||||||
masterMacsAxis *axis = dynamic_cast<masterMacsAxis *>(asynAxis);
|
|
||||||
if (axis == nullptr) {
|
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nAxis is not "
|
|
||||||
"an instance of masterMacsAxis",
|
|
||||||
portName, axis->axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
|
||||||
}
|
|
||||||
return axis;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus masterMacsController::read(int axisNo, int tcpCmd, char *response) {
|
asynStatus masterMacsController::read(int axisNo, int tcpCmd, char *response) {
|
||||||
@ -195,7 +174,7 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
|
|||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
masterMacsAxis *axis = getAxis(axisNo);
|
masterMacsAxis *axis = getMasterMacsAxis(axisNo);
|
||||||
if (axis == nullptr) {
|
if (axis == nullptr) {
|
||||||
// We already did the error logging directly in getAxis
|
// We already did the error logging directly in getAxis
|
||||||
return asynError;
|
return asynError;
|
||||||
@ -248,17 +227,17 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
|
|||||||
fullCommand[2] = lenWithMetadataSep.quot; // MSB
|
fullCommand[2] = lenWithMetadataSep.quot; // MSB
|
||||||
|
|
||||||
adjustForPrint(printableCommand, fullCommand, MAXBUF_);
|
adjustForPrint(printableCommand, fullCommand, MAXBUF_);
|
||||||
asynPrint(
|
|
||||||
this->pasynUserSelf, ASYN_TRACEIO_DRIVER,
|
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nSending command %s\n",
|
|
||||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__, printableCommand);
|
|
||||||
|
|
||||||
// Send out the command
|
// Send out the command
|
||||||
status =
|
status =
|
||||||
pasynOctetSyncIO->write(lowLevelPortUser_, fullCommand,
|
pasynOctetSyncIO->write(lowLevelPortUser_, fullCommand,
|
||||||
fullCommandLength, comTimeout_, &nbytesOut);
|
fullCommandLength, comTimeout_, &nbytesOut);
|
||||||
|
|
||||||
|
msgPrintControlKey writeKey =
|
||||||
|
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||||
|
|
||||||
if (status == asynSuccess) {
|
if (status == asynSuccess) {
|
||||||
|
msgPrintControl_.resetCount(writeKey);
|
||||||
|
|
||||||
// Try to read the answer repeatedly
|
// Try to read the answer repeatedly
|
||||||
int maxTrials = 2;
|
int maxTrials = 2;
|
||||||
@ -294,15 +273,18 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
if (msgPrintControl_.shouldBePrinted(writeKey, true, pasynUserSelf)) {
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nError %s while "
|
asynPrint(
|
||||||
"writing to the controller\n",
|
this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
"Controller \"%s\", axis %d => %s, line %d:\nError %s while "
|
||||||
stringifyAsynStatus(status));
|
"writing to the controller.%s\n",
|
||||||
|
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
stringifyAsynStatus(status), msgPrintControl_.getSuffix());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MasterMACS needs a bit of time between messages, therefore thr program
|
// MasterMACS needs a bit of time between messages, therefore thr
|
||||||
// execution is paused after the communication happened.
|
// program execution is paused after the communication happened.
|
||||||
// usleep(1500);
|
// usleep(1500);
|
||||||
|
|
||||||
// Create custom error messages for different failure modes
|
// Create custom error messages for different failure modes
|
||||||
@ -345,10 +327,6 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
|
|||||||
// Log the overall status (communication successfull or not)
|
// Log the overall status (communication successfull or not)
|
||||||
if (status == asynSuccess) {
|
if (status == asynSuccess) {
|
||||||
adjustForPrint(printableResponse, fullResponse, MAXBUF_);
|
adjustForPrint(printableResponse, fullResponse, MAXBUF_);
|
||||||
asynPrint(
|
|
||||||
lowLevelPortUser_, ASYN_TRACEIO_DRIVER,
|
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nReturn value: %s\n",
|
|
||||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__, printableResponse);
|
|
||||||
pl_status = axis->setIntegerParam(this->motorStatusCommsError_, 0);
|
pl_status = axis->setIntegerParam(this->motorStatusCommsError_, 0);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@ -408,6 +386,9 @@ asynStatus masterMacsController::parseResponse(
|
|||||||
char printableCommand[MAXBUF_] = {0};
|
char printableCommand[MAXBUF_] = {0};
|
||||||
char printableResponse[MAXBUF_] = {0};
|
char printableResponse[MAXBUF_] = {0};
|
||||||
|
|
||||||
|
msgPrintControlKey parseKey =
|
||||||
|
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||||
|
|
||||||
// We don't use strlen here since the C string terminator 0x00
|
// We don't use strlen here since the C string terminator 0x00
|
||||||
// occurs in the middle of the char array.
|
// occurs in the middle of the char array.
|
||||||
for (uint32_t i = 0; i < MAXBUF_; i++) {
|
for (uint32_t i = 0; i < MAXBUF_; i++) {
|
||||||
@ -422,27 +403,39 @@ asynStatus masterMacsController::parseResponse(
|
|||||||
} else if (fullResponse[i] == '\x15') {
|
} else if (fullResponse[i] == '\x15') {
|
||||||
// NAK
|
// NAK
|
||||||
snprintf(drvMessageText, MAXBUF_, "Communication failed.");
|
snprintf(drvMessageText, MAXBUF_, "Communication failed.");
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACEIO_DRIVER,
|
|
||||||
"Controller \"%s\", axis %d => %s, line "
|
if (msgPrintControl_.shouldBePrinted(parseKey, true,
|
||||||
"%d:\nCommunication failed\n",
|
pasynUserSelf)) {
|
||||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
|
"Controller \"%s\", axis %d => %s, line "
|
||||||
|
"%d:\nCommunication failed.%s\n",
|
||||||
|
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
msgPrintControl_.getSuffix());
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
} else if (fullResponse[i] == '\x18') {
|
} else if (fullResponse[i] == '\x18') {
|
||||||
// CAN
|
// CAN
|
||||||
snprintf(drvMessageText, MAXBUF_,
|
snprintf(drvMessageText, MAXBUF_,
|
||||||
"Tried to write with a read-only command. This is a "
|
"Tried to write with a read-only command. This is a "
|
||||||
"bug, please call the support.");
|
"bug, please call the support.");
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nTried to "
|
if (msgPrintControl_.shouldBePrinted(parseKey, true,
|
||||||
"write with the read-only command %s\n",
|
pasynUserSelf)) {
|
||||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
asynPrint(
|
||||||
printableCommand);
|
this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
|
"Controller \"%s\", axis %d => %s, line %d:\nTried to "
|
||||||
|
"write with the read-only command %s.%s\n",
|
||||||
|
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
printableCommand, msgPrintControl_.getSuffix());
|
||||||
|
}
|
||||||
responseValid = false;
|
responseValid = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (responseValid) {
|
if (responseValid) {
|
||||||
|
msgPrintControl_.resetCount(parseKey);
|
||||||
|
|
||||||
// Check if the response matches the expectations. Each response
|
// Check if the response matches the expectations. Each response
|
||||||
// contains the string "axisNo R tcpCmd" (including the spaces)
|
// contains the string "axisNo R tcpCmd" (including the spaces)
|
||||||
char expectedResponseSubstring[MAXBUF_] = {0};
|
char expectedResponseSubstring[MAXBUF_] = {0};
|
||||||
@ -457,22 +450,32 @@ asynStatus masterMacsController::parseResponse(
|
|||||||
tcpCmd);
|
tcpCmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
msgPrintControlKey responseMatchKey =
|
||||||
|
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||||
|
|
||||||
if (strstr(&fullResponse[responseStart], expectedResponseSubstring) ==
|
if (strstr(&fullResponse[responseStart], expectedResponseSubstring) ==
|
||||||
NULL) {
|
NULL) {
|
||||||
adjustForPrint(printableCommand, fullCommand, MAXBUF_);
|
adjustForPrint(printableCommand, fullCommand, MAXBUF_);
|
||||||
adjustForPrint(printableResponse, fullResponse, MAXBUF_);
|
adjustForPrint(printableResponse, fullResponse, MAXBUF_);
|
||||||
|
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACEIO_DRIVER,
|
if (msgPrintControl_.shouldBePrinted(parseKey, true,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nMismatched "
|
pasynUserSelf)) {
|
||||||
"response %s to command %s\n",
|
asynPrint(
|
||||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
this->pasynUserSelf, ASYN_TRACEIO_DRIVER,
|
||||||
printableResponse, printableCommand);
|
"Controller \"%s\", axis %d => %s, line %d:\nMismatched "
|
||||||
|
"response %s to command %s.%s\n",
|
||||||
|
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
printableResponse, printableCommand,
|
||||||
|
msgPrintControl_.getSuffix());
|
||||||
|
}
|
||||||
|
|
||||||
snprintf(drvMessageText, MAXBUF_,
|
snprintf(drvMessageText, MAXBUF_,
|
||||||
"Mismatched response %s to command %s. Please call the "
|
"Mismatched response %s to command %s. Please call the "
|
||||||
"support.",
|
"support.",
|
||||||
printableResponse, printableCommand);
|
printableResponse, printableCommand);
|
||||||
return asynError;
|
return asynError;
|
||||||
|
} else {
|
||||||
|
msgPrintControl_.resetCount(responseMatchKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return asynSuccess;
|
return asynSuccess;
|
||||||
|
@ -38,7 +38,7 @@ class masterMacsController : public sinqController {
|
|||||||
* @return masterMacsAxis* If no axis could be found, this is a
|
* @return masterMacsAxis* If no axis could be found, this is a
|
||||||
* nullptr
|
* nullptr
|
||||||
*/
|
*/
|
||||||
masterMacsAxis *getAxis(asynUser *pasynUser);
|
masterMacsAxis *getMasterMacsAxis(asynUser *pasynUser);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the axis object
|
* @brief Get the axis object
|
||||||
@ -47,7 +47,7 @@ class masterMacsController : public sinqController {
|
|||||||
* @return masterMacsAxis* If no axis could be found, this is a
|
* @return masterMacsAxis* If no axis could be found, this is a
|
||||||
* nullptr
|
* nullptr
|
||||||
*/
|
*/
|
||||||
masterMacsAxis *getAxis(int axisNo);
|
masterMacsAxis *getMasterMacsAxis(int axisNo);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
asynUser *lowLevelPortUser_;
|
asynUser *lowLevelPortUser_;
|
||||||
@ -114,15 +114,6 @@ class masterMacsController : public sinqController {
|
|||||||
int *valueStop, int axisNo, int tcpCmd,
|
int *valueStop, int axisNo, int tcpCmd,
|
||||||
bool isRead);
|
bool isRead);
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Save cast of the given asynAxis pointer to a masterMacsAxis
|
|
||||||
* pointer. If the cast fails, this function returns a nullptr.
|
|
||||||
*
|
|
||||||
* @param asynAxis
|
|
||||||
* @return masterMacsAxis*
|
|
||||||
*/
|
|
||||||
masterMacsAxis *castToAxis(asynMotorAxis *asynAxis);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Set the maximum buffer size. This is an empirical value which must be
|
// Set the maximum buffer size. This is an empirical value which must be
|
||||||
// large enough to avoid overflows for all commands to the device /
|
// large enough to avoid overflows for all commands to the device /
|
||||||
|
@ -2,9 +2,14 @@
|
|||||||
Code shared by "decodeError.py" and "decodeStatus.py"
|
Code shared by "decodeError.py" and "decodeStatus.py"
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import struct
|
||||||
|
|
||||||
def decode(value: int, interpretation):
|
def decode(value: int, interpretation):
|
||||||
|
|
||||||
bit_list = [int(char) for char in bin(value)[2:]]
|
# Pack the input as a short and unpack it as an unsigned short
|
||||||
|
value_uint16 = format(value, '016b') # Format as 16-bit unsigned integer
|
||||||
|
|
||||||
|
bit_list = [int(char) for char in value_uint16]
|
||||||
bit_list.reverse()
|
bit_list.reverse()
|
||||||
|
|
||||||
interpreted = []
|
interpreted = []
|
||||||
|
@ -32,109 +32,6 @@ interpretation = [
|
|||||||
("Not specified", "Not specified"), # Bit 15
|
("Not specified", "Not specified"), # Bit 15
|
||||||
]
|
]
|
||||||
|
|
||||||
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]:
|
|
||||||
(bit_list, interpreted) = decode(history[ptr])
|
|
||||||
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()
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
from sys import argv
|
from sys import argv
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user