Compare commits

...

15 Commits

Author SHA1 Message Date
wall_e b633281f69 format with clang-format
Test And Build / Build (push) Successful in 13s
Test And Build / Lint (push) Failing after 13s
2026-04-27 14:06:05 +02:00
wall_e 683fa2138f adds gitea action
Test And Build / Lint (push) Failing after 7s
Test And Build / Build (push) Successful in 7s
2025-07-04 14:35:07 +02:00
mathis_s 354e9d90fb Fixed missing initializer for variables in Phytron-Axis 2025-06-20 13:46:10 +02:00
soederqvist_a deea821e3f Merge pull request 'el734' (#2) from el734 into master
Reviewed-on: #2
2025-06-11 15:07:19 +02:00
soederqvist_a 7a46788fd5 Install a el734 db file
also remove explicit libversion in the makefile
2025-06-11 15:05:14 +02:00
mathis_s 9e77eb585c Merge branch 'lift_axis_no_autoenable' 2025-04-17 17:00:19 +02:00
mathis_s 7e1fc78f76 Moved curses from top-level import to function-level import and added a
comment why that is necessary
2024-10-24 10:49:18 +02:00
mathis_s 9e0d8a4322 Added a new script utils/decodeMasterMACStatusR10.py which allows to
decode the R10 status message of the MasterMACs controller.

Also fixed a bug in utils/deltatau.py (error when printing too much text
at once)
2024-10-24 10:34:19 +02:00
mathis_s 3cccfe930c Removed typo from C804Axis.cpp 2024-10-18 09:53:47 +02:00
mathis_s 8860d0c59f Updated the first-time-poll of C804 Axis 2024-10-18 09:48:17 +02:00
mathis_s b6c38be113 Initial driver version for the C804 controller 2024-10-18 09:48:17 +02:00
wall_e b14b50c25a Merge branch 'can-we-have-pipelines' into 'master'
Adds CI-Pipeline with Formatting, Linter Checks and Build Steps

See merge request sinqdev/sinqepicsapp!4
2024-10-14 10:07:16 +02:00
wall_e 477ffdbc0b Adds CI-Pipeline with Formatting, Linter Checks and Build Steps 2024-10-14 10:07:16 +02:00
wall_e 0a23ec8f22 clang is too old 2024-10-10 13:22:09 +02:00
wall_e 39098fd0d1 Adds .clang-format style for formatting files 2024-09-25 16:21:01 +02:00
11 changed files with 955 additions and 440 deletions
+236
View File
@@ -0,0 +1,236 @@
---
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
...
+21
View File
@@ -0,0 +1,21 @@
name: Test And Build
on: [push]
jobs:
Lint:
runs-on: linepics
steps:
- name: checkout repo
uses: actions/checkout@v4
- name: cppcheck
run: cppcheck --std=c++17 --addon=cert --addon=misc --error-exitcode=1 sinqEPICSApp/src/*.cpp
- name: formatting
run: clang-format --style=file --Werror --dry-run sinqEPICSApp/src/*.cpp sinqEPICSApp/src/*.c sinqEPICSApp/src/*.h
Build:
runs-on: linepics
steps:
- name: checkout repo
uses: actions/checkout@v4
- run: |
sed -i 's/ARCH_FILTER=.*/ARCH_FILTER=linux%/' Makefile.RHEL8
make -f Makefile.RHEL8 install
+2 -4
View File
@@ -4,7 +4,7 @@ include /ioc/tools/driver.makefile
MODULE=sinq
BUILDCLASSES=Linux
EPICS_VERSIONS=7.0.7
ARCH_FILTER=RHEL%
ARCH_FILTER=RHEL8%
# additional module dependencies
REQUIRED+=SynApps
@@ -12,13 +12,11 @@ REQUIRED+=stream
REQUIRED+=scaler
REQUIRED+=motorBase
# Release version
LIBVERSION=2025
# DB files to include in the release
TEMPLATES += sinqEPICSApp/Db/dimetix.db
TEMPLATES += sinqEPICSApp/Db/slsvme.db
TEMPLATES += sinqEPICSApp/Db/spsamor.db
TEMPLATES += sinqEPICSApp/Db/el734.db
# DBD files to include in the release
DBDS += sinqEPICSApp/src/sinq.dbd
+9
View File
@@ -38,3 +38,12 @@ 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
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>
```
+34
View File
@@ -0,0 +1,34 @@
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")
}
+399 -401
View File
@@ -1,15 +1,15 @@
/*
FILENAME... NanotecDriver.cpp
USAGE... Motor driver support for the Nanotec SMCI controllers
USAGE... Motor driver support for the Nanotec SMCI controllers
connected to a RS-485 bus.
These motors sit on a bus. The address on the bus is a random number, not
necessarily the motor number. These asyn motor drivers do not have access to
the motor record. Thus it was impossible to pass the bus address through.
The option was to create an axiliary record but this sucked too because the
bus address a motor is an initialisation parameter and should not be visible
in the EPICS database. Thus I choose to pass the bus address as a comma separated
list to the motor controller constructor.
These motors sit on a bus. The address on the bus is a random number, not
necessarily the motor number. These asyn motor drivers do not have access to
the motor record. Thus it was impossible to pass the bus address through.
The option was to create an axiliary record but this sucked too because the
bus address a motor is an initialisation parameter and should not be visible
in the EPICS database. Thus I choose to pass the bus address as a comma
separated list to the motor controller constructor.
Mark Koennecke
July 2015
@@ -19,22 +19,21 @@ Modified to use the MsgTxt field for SINQ
Mark Koennecke, January 2019
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <iocsh.h>
#include <epicsThread.h>
#include <errlog.h>
#include <iocsh.h>
#include <asynOctetSyncIO.h>
#include "stptok.h"
#include "NanotecDriver.h"
#include "stptok.h"
#include <epicsExport.h>
#define IDLEPOLL 60
@@ -42,464 +41,463 @@ Mark Koennecke, January 2019
#define ABS(x) (x < 0 ? -(x) : (x))
/** Creates a new NanotecController object.
* \param[in] portName The name of the asyn port that will be created for this driver
* \param[in] NanotecPortName The name of the drvAsynSerialPort that was created previously to connect to the Nanotec controller
*/
NanotecController::NanotecController(const char *portName, const char *NanotecPortName, int motCount, const char *bus)
: SINQController(portName, NanotecPortName, motCount+1)
{
int axis, busAddress;
asynStatus status;
NanotecAxis *pAxis;
static const char *functionName = "NanotecController::NanotecController";
char *pPtr, busNoString[20];
* \param[in] portName The name of the asyn port that will be created
* for this driver
* \param[in] NanotecPortName The name of the drvAsynSerialPort that was
* created previously to connect to the Nanotec controller
*/
NanotecController::NanotecController(const char *portName,
const char *NanotecPortName, int motCount,
const char *bus)
: SINQController(portName, NanotecPortName, motCount + 1) {
int axis, busAddress;
asynStatus status;
NanotecAxis *pAxis;
static const char *functionName = "NanotecController::NanotecController";
char *pPtr, busNoString[20];
/* Connect to Nanotec controller */
status = pasynOctetSyncIO->connect(NanotecPortName, 0,
&pasynUserController_, NULL);
if (status) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"%s: cannot connect to Nanotec controller\n", functionName);
}
pasynOctetSyncIO->setOutputEos(pasynUserController_, "\r", strlen("\r"));
pasynOctetSyncIO->setInputEos(pasynUserController_, "\r", strlen("\r"));
/* Connect to Nanotec controller */
status = pasynOctetSyncIO->connect(NanotecPortName, 0, &pasynUserController_, NULL);
if (status) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"%s: cannot connect to Nanotec controller\n",
functionName);
}
pasynOctetSyncIO->setOutputEos(pasynUserController_,"\r",strlen("\r"));
pasynOctetSyncIO->setInputEos(pasynUserController_,"\r",strlen("\r"));
axis = 1;
pPtr = (char *)bus;
while ((pPtr = stptok(pPtr, busNoString, sizeof(busNoString), ",")) !=
NULL) {
busAddress = atoi(busNoString);
pAxis = new NanotecAxis(this, axis, busAddress);
errlogPrintf("Axis %d, busAddress = %d\n", axis, busAddress);
axis++;
}
axis = 1;
pPtr = (char *)bus;
while((pPtr = stptok(pPtr,busNoString,sizeof(busNoString),",")) != NULL){
busAddress = atoi(busNoString);
pAxis = new NanotecAxis(this, axis,busAddress);
errlogPrintf("Axis %d, busAddress = %d\n", axis, busAddress);
axis++;
}
startPoller(1000./1000., IDLEPOLL, 2);
startPoller(1000. / 1000., IDLEPOLL, 2);
}
/** Creates a new NanotecController object.
* Configuration command, called directly or from iocsh
* \param[in] portName The name of the asyn port that will be created for this driver
* \param[in] NanotecPortName The name of the drvAsynIPPPort that was created previously to connect to the Nanotec controller
*/
extern "C" int NanotecCreateController(const char *portName, const char *NanotecPortName, int numMot, const char *busAddresses)
{
NanotecController *pNanotecController
= new NanotecController(portName, NanotecPortName,numMot,busAddresses);
pNanotecController = NULL;
return(asynSuccess);
* Configuration command, called directly or from iocsh
* \param[in] portName The name of the asyn port that will be created
* for this driver
* \param[in] NanotecPortName The name of the drvAsynIPPPort that was
* created previously to connect to the Nanotec controller
*/
extern "C" int NanotecCreateController(const char *portName,
const char *NanotecPortName, int numMot,
const char *busAddresses) {
NanotecController *pNanotecController =
new NanotecController(portName, NanotecPortName, numMot, busAddresses);
pNanotecController = NULL;
return (asynSuccess);
}
/** Reports on status of the driver
* \param[in] fp The file pointer on which report information will be written
* \param[in] level The level of report detail desired
*
* If details > 0 then information is printed about each axis.
* After printing controller-specific information it calls asynMotorController::report()
*/
void NanotecController::report(FILE *fp, int level)
{
fprintf(fp, "Nanotec motor driver %s, numAxes=%d\n",
this->portName, numAxes_);
* \param[in] fp The file pointer on which report information will be written
* \param[in] level The level of report detail desired
*
* If details > 0 then information is printed about each axis.
* After printing controller-specific information it calls
* asynMotorController::report()
*/
void NanotecController::report(FILE *fp, int level) {
fprintf(fp, "Nanotec motor driver %s, numAxes=%d\n", this->portName,
numAxes_);
// Call the base class method
asynMotorController::report(fp, level);
// Call the base class method
asynMotorController::report(fp, level);
}
/** Returns a pointer to an NanotecAxis object.
* Returns NULL if the axis number encoded in pasynUser is invalid.
* \param[in] pasynUser asynUser structure that encodes the axis index number. */
NanotecAxis* NanotecController::getAxis(asynUser *pasynUser)
{
return static_cast<NanotecAxis*>(asynMotorController::getAxis(pasynUser));
* Returns NULL if the axis number encoded in pasynUser is invalid.
* \param[in] pasynUser asynUser structure that encodes the axis index number.
*/
NanotecAxis *NanotecController::getAxis(asynUser *pasynUser) {
return static_cast<NanotecAxis *>(asynMotorController::getAxis(pasynUser));
}
/** Returns a pointer to an NanotecAxis object.
* Returns NULL if the axis number encoded in pasynUser is invalid.
* \param[in] axisNo Axis index number. */
NanotecAxis* NanotecController::getAxis(int axisNo)
{
return static_cast<NanotecAxis*>(asynMotorController::getAxis(axisNo));
* Returns NULL if the axis number encoded in pasynUser is invalid.
* \param[in] axisNo Axis index number. */
NanotecAxis *NanotecController::getAxis(int axisNo) {
return static_cast<NanotecAxis *>(asynMotorController::getAxis(axisNo));
}
// These are the NanotecAxis methods
/** Creates a new NanotecAxis object.
* \param[in] pC Pointer to the NanotecController to which this axis belongs.
* \param[in] axisNo Index number of this axis, range 0 to pC->numAxes_-1.
*
* Initializes register numbers, etc.
*/
* \param[in] pC Pointer to the NanotecController to which this axis belongs.
* \param[in] axisNo Index number of this axis, range 0 to pC->numAxes_-1.
*
* Initializes register numbers, etc.
*/
NanotecAxis::NanotecAxis(NanotecController *pC, int axisNo, int busAddress)
: SINQAxis(pC, axisNo),
pC_(pC)
{
this->busAddress = busAddress;
next_poll = -1;
: SINQAxis(pC, axisNo), pC_(pC) {
this->busAddress = busAddress;
next_poll = -1;
}
/** Reports on status of the axis
* \param[in] fp The file pointer on which report information will be written
* \param[in] level The level of report detail desired
*
* After printing device-specific information calls asynMotorAxis::report()
*/
void NanotecAxis::report(FILE *fp, int level)
{
if (level > 0) {
fprintf(fp, " axis %d\n",
axisNo_);
}
// Call the base class method
//asynMotorAxis::report(fp, level);
}
asynStatus NanotecController::transactController(int axisNo, char command[COMLEN], char reply[COMLEN])
{
asynStatus status;
size_t in, out;
int reason;
SINQAxis *axis = getAxis(axisNo);
pasynOctetSyncIO->flush(pasynUserController_);
status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
reply,COMLEN, 1.,&out,&in,&reason);
if(status != asynSuccess){
if(axis != NULL){
axis->updateMsgTxtFromDriver("Lost connection to motor controller");
* \param[in] fp The file pointer on which report information will be written
* \param[in] level The level of report detail desired
*
* After printing device-specific information calls asynMotorAxis::report()
*/
void NanotecAxis::report(FILE *fp, int level) {
if (level > 0) {
fprintf(fp, " axis %d\n", axisNo_);
}
return status;
}
/*
check for Nanotec errors
*/
if(strstr(reply,"?") != NULL){
errlogSevPrintf(errlogMajor, "Bad command %s", command);
return asynError;
}
if(strlen(reply) < 1) {
errlogSevPrintf(errlogMajor, "No reply received for %s", command);
return asynError;
}
return status;
// Call the base class method
// asynMotorAxis::report(fp, level);
}
asynStatus NanotecAxis::move(double position, int relative, double minVelocity, double maxVelocity, double acceleration)
{
asynStatus status;
//static const char *functionName = "NanotecAxis::move";
char command[COMLEN], reply[COMLEN];
size_t in, out;
int reason;
asynStatus NanotecController::transactController(int axisNo,
char command[COMLEN],
char reply[COMLEN]) {
asynStatus status;
size_t in, out;
int reason;
SINQAxis *axis = getAxis(axisNo);
updateMsgTxtFromDriver("");
pasynOctetSyncIO->flush(pasynUserController_);
// status = sendAccelAndVelocity(acceleration, maxVelocity);
if (relative) {
position += this->position;
}
status = pasynOctetSyncIO->writeRead(pasynUserController_, command,
strlen(command), reply, COMLEN, 1.,
&out, &in, &reason);
if (status != asynSuccess) {
if (axis != NULL) {
axis->updateMsgTxtFromDriver("Lost connection to motor controller");
}
return status;
}
homing = 0;
setIntegerParam(pC_->motorStatusAtHome_, false);
setIntegerParam(pC_->motorStatusHighLimit_, false);
setIntegerParam(pC_->motorStatusLowLimit_, false);
/*
check for Nanotec errors
*/
if (strstr(reply, "?") != NULL) {
errlogSevPrintf(errlogMajor, "Bad command %s", command);
return asynError;
}
if (strlen(reply) < 1) {
errlogSevPrintf(errlogMajor, "No reply received for %s", command);
return asynError;
}
/*
set mode
*/
snprintf(command,sizeof(command),"#%dp2",busAddress);
status = pC_->transactController(axisNo_,command,reply);
if(status != asynSuccess){
return status;
}
/*
set target
*/
snprintf(command,sizeof(command),"#%ds%d",busAddress, (int)position);
status = pC_->transactController(axisNo_,command,reply);
if(status != asynSuccess){
return status;
}
/*
and start..
*/
snprintf(command,sizeof(command),"#%dA",busAddress);
status = pC_->transactController(axisNo_,command,reply);
if(status != asynSuccess){
return status;
}
next_poll = -1;
return status;
}
asynStatus NanotecAxis::home(double minVelocity, double maxVelocity, double acceleration, int forwards)
{
asynStatus status;
//static const char *functionName = "NanotecAxis::home";
char command[COMLEN], reply[COMLEN];
asynStatus NanotecAxis::move(double position, int relative, double minVelocity,
double maxVelocity, double acceleration) {
asynStatus status;
// static const char *functionName = "NanotecAxis::move";
char command[COMLEN], reply[COMLEN];
size_t in, out;
int reason;
setIntegerParam(pC_->motorStatusAtHome_, false);
updateMsgTxtFromDriver("");
updateMsgTxtFromDriver("");
// status = sendAccelAndVelocity(acceleration, maxVelocity);
/*
reset positioning errors
*/
snprintf(command,sizeof(command),"#%dD",busAddress);
status = pC_->transactController(axisNo_,command,reply);
if(status != asynSuccess){
if (relative) {
position += this->position;
}
homing = 0;
setIntegerParam(pC_->motorStatusAtHome_, false);
setIntegerParam(pC_->motorStatusHighLimit_, false);
setIntegerParam(pC_->motorStatusLowLimit_, false);
/*
set mode
*/
snprintf(command, sizeof(command), "#%dp2", busAddress);
status = pC_->transactController(axisNo_, command, reply);
if (status != asynSuccess) {
return status;
}
/*
set target
*/
snprintf(command, sizeof(command), "#%ds%d", busAddress, (int)position);
status = pC_->transactController(axisNo_, command, reply);
if (status != asynSuccess) {
return status;
}
/*
and start..
*/
snprintf(command, sizeof(command), "#%dA", busAddress);
status = pC_->transactController(axisNo_, command, reply);
if (status != asynSuccess) {
return status;
}
next_poll = -1;
return status;
}
/*
set mode
*/
snprintf(command,sizeof(command),"#%dp4",busAddress);
status = pC_->transactController(axisNo_,command,reply);
if(status != asynSuccess){
return status;
}
/*
set direction
*/
snprintf(command,sizeof(command),"#%dd0",busAddress);
status = pC_->transactController(axisNo_,command,reply);
if(status != asynSuccess){
return status;
}
/*
and start..
*/
snprintf(command,sizeof(command),"#%dA",busAddress);
status = pC_->transactController(axisNo_,command,reply);
if(status != asynSuccess){
return status;
}
homing = 1;
next_poll= -1;
return status;
}
asynStatus NanotecAxis::moveVelocity(double minVelocity, double maxVelocity, double acceleration)
{
asynStatus status;
//static const char *functionName = "NanotecAxis::moveVelocity";
asynStatus NanotecAxis::home(double minVelocity, double maxVelocity,
double acceleration, int forwards) {
asynStatus status;
// static const char *functionName = "NanotecAxis::home";
char command[COMLEN], reply[COMLEN];
setIntegerParam(pC_->motorStatusAtHome_, false);
updateMsgTxtFromDriver("");
/*
reset positioning errors
*/
snprintf(command, sizeof(command), "#%dD", busAddress);
status = pC_->transactController(axisNo_, command, reply);
if (status != asynSuccess) {
return status;
}
/*
set mode
*/
snprintf(command, sizeof(command), "#%dp4", busAddress);
status = pC_->transactController(axisNo_, command, reply);
if (status != asynSuccess) {
return status;
}
/*
set direction
*/
snprintf(command, sizeof(command), "#%dd0", busAddress);
status = pC_->transactController(axisNo_, command, reply);
if (status != asynSuccess) {
return status;
}
/*
and start..
*/
snprintf(command, sizeof(command), "#%dA", busAddress);
status = pC_->transactController(axisNo_, command, reply);
if (status != asynSuccess) {
return status;
}
homing = 1;
next_poll = -1;
return status;
}
asynStatus NanotecAxis::moveVelocity(double minVelocity, double maxVelocity,
double acceleration) {
asynStatus status;
// static const char *functionName = "NanotecAxis::moveVelocity";
double target;
// asynPrint(pasynUser_, ASYN_TRACE_FLOW,
// "%s: minVelocity=%f, maxVelocity=%f, acceleration=%f\n",
// functionName, minVelocity, maxVelocity, acceleration);
updateMsgTxtFromDriver("");
// asynPrint(pasynUser_, ASYN_TRACE_FLOW,
// "%s: minVelocity=%f, maxVelocity=%f, acceleration=%f\n",
// functionName, minVelocity, maxVelocity, acceleration);
updateMsgTxtFromDriver("");
if (maxVelocity > 0.) {
/* This is a positive move */
pC_->getDoubleParam(axisNo_,pC_->motorHighLimit_,&target);
} else {
/* This is a negative move */
pC_->getDoubleParam(axisNo_,pC_->motorLowLimit_,&target);
}
if (maxVelocity > 0.) {
/* This is a positive move */
pC_->getDoubleParam(axisNo_, pC_->motorHighLimit_, &target);
} else {
/* This is a negative move */
pC_->getDoubleParam(axisNo_, pC_->motorLowLimit_, &target);
}
status = move(target,0,0,0,0);
status = move(target, 0, 0, 0, 0);
return status;
return status;
}
asynStatus NanotecAxis::stop(double acceleration )
{
asynStatus status;
//static const char *functionName = "NanotecAxis::stop";
char command[COMLEN], reply[COMLEN];
asynStatus NanotecAxis::stop(double acceleration) {
asynStatus status;
// static const char *functionName = "NanotecAxis::stop";
char command[COMLEN], reply[COMLEN];
sprintf(command, "#%dS1", busAddress);
status = pC_->transactController(axisNo_,command,reply);
errlogPrintf("Sent STOP on Axis %d\n", axisNo_);
sprintf(command, "#%dS1", busAddress);
status = pC_->transactController(axisNo_, command, reply);
errlogPrintf("Sent STOP on Axis %d\n", axisNo_);
return status;
return status;
}
asynStatus NanotecAxis::setPosition(double position)
{
asynStatus status;
//static const char *functionName = "NanotecAxis::setPosition";
char command[COMLEN], reply[COMLEN];
asynStatus NanotecAxis::setPosition(double position) {
asynStatus status;
// static const char *functionName = "NanotecAxis::setPosition";
char command[COMLEN], reply[COMLEN];
updateMsgTxtFromDriver("");
updateMsgTxtFromDriver("");
sprintf(command, "#%dD%d", busAddress, (int)position);
status = pC_->transactController(axisNo_,command,reply);
next_poll = -1;
sprintf(command, "#%dD%d", busAddress, (int)position);
status = pC_->transactController(axisNo_, command, reply);
next_poll = -1;
return status;
return status;
}
asynStatus NanotecAxis::setClosedLoop(bool closedLoop)
{
//static const char *functionName = "NanotecAxis::setClosedLoop";
/*
This belongs into the Kingdom of Electronics.
We do not do this.
*/
asynStatus NanotecAxis::setClosedLoop(bool closedLoop) {
// static const char *functionName = "NanotecAxis::setClosedLoop";
return asynError;
/*
This belongs into the Kingdom of Electronics.
We do not do this.
*/
return asynError;
}
/** Polls the axis.
* This function reads the motor position, the limit status, the home status, the moving status,
* and the drive power-on status.
* It calls setIntegerParam() and setDoubleParam() for each item that it polls,
* and then calls callParamCallbacks() at the end.
* \param[out] moving A flag that is set indicating that the axis is moving (true) or done (false). */
asynStatus NanotecAxis::poll(bool *moving)
{
asynStatus comStatus;
char command[COMLEN], reply[COMLEN];
char *pPtr;
int posVal, statVal, count = 0;
double lowLim, highLim;
* This function reads the motor position, the limit status, the home status,
* the moving status, and the drive power-on status. It calls setIntegerParam()
* and setDoubleParam() for each item that it polls, and then calls
* callParamCallbacks() at the end.
* \param[out] moving A flag that is set indicating that the axis is moving
* (true) or done (false). */
asynStatus NanotecAxis::poll(bool *moving) {
asynStatus comStatus;
char command[COMLEN], reply[COMLEN];
char *pPtr;
int posVal, statVal, count = 0;
double lowLim, highLim;
// protect against excessive polling
if(time(NULL) < next_poll){
*moving = false;
return asynSuccess;
}
// Read the current motor position
sprintf(command,"#%dC", busAddress);
comStatus = pC_->transactController(axisNo_,command,reply);
if(comStatus) goto skip;
pPtr = strchr(reply,'C');
if(pPtr){
pPtr++;
count = sscanf(pPtr,"%d", &posVal);
}
if(pPtr == NULL || count < 1) {
errlogPrintf("Invalid response %s for #C received for axis %d, address %d\n", reply, axisNo_, busAddress);
return asynError;
}
//errlogPrintf("Axis %d, reply %s, position %d\n", axisNo_, reply, posVal);
setDoubleParam(pC_->motorPosition_, (double)posVal);
//setDoubleParam(pC_->motorEncoderPosition_, position);
// Read the moving status of this motor
sprintf(command,"#%d$",busAddress);
comStatus = pC_->transactController(axisNo_,command,reply);
if(comStatus) goto skip;
pPtr = strchr(reply,'$');
if(pPtr) {
pPtr++;
count = sscanf(pPtr, "%d", &statVal);
}
if(pPtr == NULL || count < 1) {
errlogPrintf("Invalid response %s for #$ received for axis %d busAddress %d\n", reply, axisNo_, busAddress);
return asynError;
}
//errlogPrintf("Axis %d, reply %s, statVal = %d\n",
// axisNo_, reply, statVal);
setIntegerParam(pC_->motorStatusDone_, false);
*moving = true;
pC_->getDoubleParam(axisNo_,pC_->motorLowLimit_,&lowLim);
pC_->getDoubleParam(axisNo_,pC_->motorHighLimit_,&highLim);
if(homing){
/*
code for homing
*/
switch(statVal) {
case 163:
setPosition(lowLim);
*moving = false;
setIntegerParam(pC_->motorStatusAtHome_, true);
setIntegerParam(pC_->motorStatusDone_, true);
break;
default :
if(statVal & 1) {
*moving = false;
setIntegerParam(pC_->motorStatusAtHome_, true);
setIntegerParam(pC_->motorStatusDone_, true);
}
break;
// protect against excessive polling
if (time(NULL) < next_poll) {
*moving = false;
return asynSuccess;
}
} else {
/*
code for normal movement
*/
if(statVal & 1) {
*moving = false;
setIntegerParam(pC_->motorStatusDone_, true);
} else if (statVal & 4) {
setIntegerParam(pC_->motorStatusDone_, true);
setIntegerParam(pC_->motorStatusProblem_, true);
errlogSevPrintf(errlogMajor, "Limit or other positioning problem at %d", axisNo_);
updateMsgTxtFromDriver("Positioning problem");
if(ABS(posVal - lowLim) < ABS(posVal - highLim)){
setIntegerParam(pC_->motorStatusLowLimit_, true);
updateMsgTxtFromDriver("Low Limit Hit");
} else {
setIntegerParam(pC_->motorStatusHighLimit_, true);
updateMsgTxtFromDriver("High Limit Hit");
}
*moving = false;
}
}
if(*moving == true){
next_poll = -1;
}
// Read the current motor position
sprintf(command, "#%dC", busAddress);
comStatus = pC_->transactController(axisNo_, command, reply);
if (comStatus)
goto skip;
skip:
setIntegerParam(pC_->motorStatusProblem_, comStatus ? 1:0);
callParamCallbacks();
return comStatus ? asynError : asynSuccess;
pPtr = strchr(reply, 'C');
if (pPtr) {
pPtr++;
count = sscanf(pPtr, "%d", &posVal);
}
if (pPtr == NULL || count < 1) {
errlogPrintf(
"Invalid response %s for #C received for axis %d, address %d\n",
reply, axisNo_, busAddress);
return asynError;
}
// errlogPrintf("Axis %d, reply %s, position %d\n", axisNo_, reply, posVal);
setDoubleParam(pC_->motorPosition_, (double)posVal);
// setDoubleParam(pC_->motorEncoderPosition_, position);
// Read the moving status of this motor
sprintf(command, "#%d$", busAddress);
comStatus = pC_->transactController(axisNo_, command, reply);
if (comStatus)
goto skip;
pPtr = strchr(reply, '$');
if (pPtr) {
pPtr++;
count = sscanf(pPtr, "%d", &statVal);
}
if (pPtr == NULL || count < 1) {
errlogPrintf(
"Invalid response %s for #$ received for axis %d busAddress %d\n",
reply, axisNo_, busAddress);
return asynError;
}
// errlogPrintf("Axis %d, reply %s, statVal = %d\n",
// axisNo_, reply, statVal);
setIntegerParam(pC_->motorStatusDone_, false);
*moving = true;
pC_->getDoubleParam(axisNo_, pC_->motorLowLimit_, &lowLim);
pC_->getDoubleParam(axisNo_, pC_->motorHighLimit_, &highLim);
if (homing) {
/*
code for homing
*/
switch (statVal) {
case 163:
setPosition(lowLim);
*moving = false;
setIntegerParam(pC_->motorStatusAtHome_, true);
setIntegerParam(pC_->motorStatusDone_, true);
break;
default:
if (statVal & 1) {
*moving = false;
setIntegerParam(pC_->motorStatusAtHome_, true);
setIntegerParam(pC_->motorStatusDone_, true);
}
break;
}
} else {
/*
code for normal movement
*/
if (statVal & 1) {
*moving = false;
setIntegerParam(pC_->motorStatusDone_, true);
} else if (statVal & 4) {
setIntegerParam(pC_->motorStatusDone_, true);
setIntegerParam(pC_->motorStatusProblem_, true);
errlogSevPrintf(errlogMajor,
"Limit or other positioning problem at %d",
axisNo_);
updateMsgTxtFromDriver("Positioning problem");
if (ABS(posVal - lowLim) < ABS(posVal - highLim)) {
setIntegerParam(pC_->motorStatusLowLimit_, true);
updateMsgTxtFromDriver("Low Limit Hit");
} else {
setIntegerParam(pC_->motorStatusHighLimit_, true);
updateMsgTxtFromDriver("High Limit Hit");
}
*moving = false;
}
}
if (*moving == true) {
next_poll = -1;
}
skip:
setIntegerParam(pC_->motorStatusProblem_, comStatus ? 1 : 0);
callParamCallbacks();
return comStatus ? asynError : asynSuccess;
}
/** Code for iocsh registration */
static const iocshArg NanotecCreateControllerArg0 = {"Port name", iocshArgString};
static const iocshArg NanotecCreateControllerArg1 = {"Nanotec port name", iocshArgString};
static const iocshArg NanotecCreateControllerArg2 = {"Number of axes", iocshArgInt};
static const iocshArg NanotecCreateControllerArg3 = {"Komma separated list of bus addresses", iocshArgString};
static const iocshArg * const NanotecCreateControllerArgs[] = {&NanotecCreateControllerArg0,
&NanotecCreateControllerArg1,
&NanotecCreateControllerArg2,
&NanotecCreateControllerArg3
};
static const iocshFuncDef NanotecCreateControllerDef = {"NanotecCreateController", 4, NanotecCreateControllerArgs};
static void NanotecCreateContollerCallFunc(const iocshArgBuf *args)
{
NanotecCreateController(args[0].sval, args[1].sval, args[2].ival,args[3].sval);
static const iocshArg NanotecCreateControllerArg0 = {"Port name",
iocshArgString};
static const iocshArg NanotecCreateControllerArg1 = {"Nanotec port name",
iocshArgString};
static const iocshArg NanotecCreateControllerArg2 = {"Number of axes",
iocshArgInt};
static const iocshArg NanotecCreateControllerArg3 = {
"Komma separated list of bus addresses", iocshArgString};
static const iocshArg *const NanotecCreateControllerArgs[] = {
&NanotecCreateControllerArg0, &NanotecCreateControllerArg1,
&NanotecCreateControllerArg2, &NanotecCreateControllerArg3};
static const iocshFuncDef NanotecCreateControllerDef = {
"NanotecCreateController", 4, NanotecCreateControllerArgs};
static void NanotecCreateContollerCallFunc(const iocshArgBuf *args) {
NanotecCreateController(args[0].sval, args[1].sval, args[2].ival,
args[3].sval);
}
static void NanotecRegister(void)
{
iocshRegister(&NanotecCreateControllerDef, NanotecCreateContollerCallFunc);
static void NanotecRegister(void) {
iocshRegister(&NanotecCreateControllerDef, NanotecCreateContollerCallFunc);
}
extern "C" {
+37 -34
View File
@@ -10,51 +10,54 @@ Modified to use the MsgTxt field for SINQ
Mark Koennecke, January 2019
*/
#include "SINQController.h"
#include "SINQAxis.h"
#include "SINQController.h"
#define COMLEN 80
#define MAXMOT 99
class NanotecAxis : public SINQAxis
{
public:
/* These are the methods we override from the base class */
NanotecAxis(class NanotecController *pC, int axis, int busAddress);
void report(FILE *fp, int level);
asynStatus move(double position, int relative, double min_velocity, double max_velocity, double acceleration);
asynStatus moveVelocity(double min_velocity, double max_velocity, double acceleration);
asynStatus home(double min_velocity, double max_velocity, double acceleration, int forwards);
asynStatus stop(double acceleration);
asynStatus poll(bool *moving);
asynStatus setPosition(double position);
asynStatus setClosedLoop(bool closedLoop);
class NanotecAxis : public SINQAxis {
public:
/* These are the methods we override from the base class */
NanotecAxis(class NanotecController *pC, int axis, int busAddress);
void report(FILE *fp, int level);
asynStatus move(double position, int relative, double min_velocity,
double max_velocity, double acceleration);
asynStatus moveVelocity(double min_velocity, double max_velocity,
double acceleration);
asynStatus home(double min_velocity, double max_velocity,
double acceleration, int forwards);
asynStatus stop(double acceleration);
asynStatus poll(bool *moving);
asynStatus setPosition(double position);
asynStatus setClosedLoop(bool closedLoop);
private:
NanotecController *pC_; /**< Pointer to the asynMotorController to which this axis belongs.
* Abbreviated because it is used very frequently */
double position;
int homing;
time_t next_poll;
int busAddress;
friend class NanotecController;
private:
NanotecController
*pC_; /**< Pointer to the asynMotorController to which this axis
* belongs. Abbreviated because it is used very frequently */
double position;
int homing;
time_t next_poll;
int busAddress;
friend class NanotecController;
};
class NanotecController : public SINQController {
public:
NanotecController(const char *portName, const char *NanotecPortName, int numMot, const char *busAddresses);
public:
NanotecController(const char *portName, const char *NanotecPortName,
int numMot, const char *busAddresses);
void report(FILE *fp, int level);
NanotecAxis* getAxis(asynUser *pasynUser);
NanotecAxis* getAxis(int axisNo);
friend class NanotecAxis;
private:
asynUser *pasynUserController_;
asynStatus transactController(int axisNo, char command[COMLEN], char reply[COMLEN]);
void report(FILE *fp, int level);
NanotecAxis *getAxis(asynUser *pasynUser);
NanotecAxis *getAxis(int axisNo);
friend class NanotecAxis;
private:
asynUser *pasynUserController_;
asynStatus transactController(int axisNo, char command[COMLEN],
char reply[COMLEN]);
};
+2
View File
@@ -250,6 +250,8 @@ PhytronAxis::PhytronAxis(PhytronController *pC, int axisNo, int enc)
haveBrake = 0;
brakeIO = -1;
next_poll = -1;
homing = 0;
homing_direction = 0;
}
int PhytronAxis::setBrake(int brakeNO)
+1 -1
View File
@@ -114,7 +114,7 @@ typedef struct {
unsigned int dbInit;
}EL737priv;
static void dummyAsynCallback([[maybe_unused]] asynUser *pasynUser)
static void dummyAsynCallback(asynUser *pasynUser)
{
}
+213
View File
@@ -0,0 +1,213 @@
#!/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)
+1
View File
@@ -64,6 +64,7 @@ if __name__ == "__main__":
curses.noecho()
curses.cbreak()
stdscr.keypad(True)
stdscr.scrollok(True)
stdscr.addstr(">> ")
stdscr.refresh()