Fixed moving after enable bug
When a MasterMacs motor is powered for the first time, it does not have a target set. Therefore, the targetReached bit is 0, which the driver used to interpret as "moving". This is solved now by an additional flag which checks if the motor did a handshake. Additionally, the communication module was simplified and new utility scripts were added. It is now made sure that the communication timeout for enabling and sending move commands is now at least equal to PowerCycleTimeout defined in src/masterMacsAxis.cpp.
This commit is contained in:
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.12.0
|
sinqMotor_VERSION=mathis_s
|
||||||
|
|
||||||
# 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
|
||||||
|
@ -14,6 +14,8 @@ This driver is a standard sinqMotor-derived driver and does not need any specifi
|
|||||||
|
|
||||||
The folder "utils" contains utility scripts for working with masterMacs motor controllers:
|
The folder "utils" contains utility scripts for working with masterMacs motor controllers:
|
||||||
- decodeStatus.py: Take the return message of a R10 (read status) command and print it in human-readable form.
|
- decodeStatus.py: Take the return message of a R10 (read status) command and print it in human-readable form.
|
||||||
|
- decodeError.py: Take the return message of a R11 (read error) command and print it in human-readable form.
|
||||||
|
- writeRead.py: Send messages to the controller and receive answers.
|
||||||
|
|
||||||
## Developer guide
|
## Developer guide
|
||||||
|
|
||||||
|
@ -11,6 +11,14 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
A special communication timeout is used in the following two cases:
|
||||||
|
1) Enable command
|
||||||
|
2) First move command after enabling the motor
|
||||||
|
This is due to MasterMACS running a powerup cycle, which can delay the answer.
|
||||||
|
*/
|
||||||
|
#define PowerCycleTimeout 10.0 // Value in seconds
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Contains all instances of turboPmacAxis which have been created and is used in
|
Contains all instances of turboPmacAxis which have been created and is used in
|
||||||
the initialization hook function.
|
the initialization hook function.
|
||||||
@ -79,7 +87,7 @@ masterMacsAxis::masterMacsAxis(masterMacsController *pC, int axisNo)
|
|||||||
stop completely, since this is a configuration error.
|
stop completely, since this is a configuration error.
|
||||||
*/
|
*/
|
||||||
if (axisNo >= pC->numAxes()) {
|
if (axisNo >= pC->numAxes()) {
|
||||||
asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR,
|
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:: FATAL ERROR: "
|
"Controller \"%s\", axis %d => %s, line %d:: FATAL ERROR: "
|
||||||
"Axis index %d must be smaller than the total number of axes "
|
"Axis index %d must be smaller than the total number of axes "
|
||||||
"%d. Call the support.",
|
"%d. Call the support.",
|
||||||
@ -106,12 +114,13 @@ masterMacsAxis::masterMacsAxis(masterMacsController *pC, int axisNo)
|
|||||||
// Flag for handshake waiting
|
// Flag for handshake waiting
|
||||||
waitForHandshake_ = false;
|
waitForHandshake_ = false;
|
||||||
timeAtHandshake_ = 0;
|
timeAtHandshake_ = 0;
|
||||||
|
targetReachedUninitialized_ = true;
|
||||||
|
|
||||||
// masterMacs motors can always be disabled
|
// masterMacs motors can always be disabled
|
||||||
status = pC_->setIntegerParam(axisNo_, pC_->motorCanDisable(), 1);
|
status = pC_->setIntegerParam(axisNo_, pC_->motorCanDisable(), 1);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(
|
asynPrint(
|
||||||
pC_->asynUserSelf(), ASYN_TRACE_ERROR,
|
pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
|
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
|
||||||
"(setting a parameter value failed with %s)\n. Terminating IOC",
|
"(setting a parameter value failed with %s)\n. Terminating IOC",
|
||||||
pC_->portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
pC_->portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
||||||
@ -123,7 +132,7 @@ masterMacsAxis::masterMacsAxis(masterMacsController *pC, int axisNo)
|
|||||||
status = pC_->setIntegerParam(axisNo_, pC_->motorStatusMoving(), false);
|
status = pC_->setIntegerParam(axisNo_, pC_->motorStatusMoving(), false);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(
|
asynPrint(
|
||||||
pC_->asynUserSelf(), ASYN_TRACE_ERROR,
|
pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
|
"Controller \"%s\", axis %d => %s, line %d:\nFATAL ERROR "
|
||||||
"(setting a parameter value failed with %s)\n. Terminating IOC",
|
"(setting a parameter value failed with %s)\n. Terminating IOC",
|
||||||
pC_->portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
pC_->portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
||||||
@ -148,7 +157,7 @@ asynStatus masterMacsAxis::init() {
|
|||||||
|
|
||||||
// Local variable declaration
|
// Local variable declaration
|
||||||
asynStatus pl_status = asynSuccess;
|
asynStatus pl_status = asynSuccess;
|
||||||
char response[pC_->MAXBUF_];
|
char response[pC_->MAXBUF_] = {0};
|
||||||
int nvals = 0;
|
int nvals = 0;
|
||||||
double motorRecResolution = 0.0;
|
double motorRecResolution = 0.0;
|
||||||
double motorPosition = 0.0;
|
double motorPosition = 0.0;
|
||||||
@ -167,7 +176,7 @@ asynStatus masterMacsAxis::init() {
|
|||||||
&motorRecResolution);
|
&motorRecResolution);
|
||||||
if (pl_status == asynParamUndefined) {
|
if (pl_status == asynParamUndefined) {
|
||||||
if (now + maxInitTime < time(NULL)) {
|
if (now + maxInitTime < time(NULL)) {
|
||||||
asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR,
|
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line "
|
"Controller \"%s\", axis %d => %s, line "
|
||||||
"%d\nInitializing the parameter library failed.\n",
|
"%d\nInitializing the parameter library failed.\n",
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__,
|
||||||
@ -259,7 +268,7 @@ asynStatus masterMacsAxis::init() {
|
|||||||
// If we can't communicate with the parameter library, it doesn't
|
// If we can't communicate with the parameter library, it doesn't
|
||||||
// make sense to try and upstream this to the user -> Just log the
|
// make sense to try and upstream this to the user -> Just log the
|
||||||
// error
|
// error
|
||||||
asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR,
|
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line "
|
"Controller \"%s\", axis %d => %s, line "
|
||||||
"%d:\ncallParamCallbacks failed with %s.\n",
|
"%d:\ncallParamCallbacks failed with %s.\n",
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
@ -281,7 +290,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
|
|||||||
// Status of parameter library operations
|
// Status of parameter library operations
|
||||||
asynStatus pl_status = asynSuccess;
|
asynStatus pl_status = asynSuccess;
|
||||||
|
|
||||||
char response[pC_->MAXBUF_];
|
char response[pC_->MAXBUF_] = {0};
|
||||||
int nvals = 0;
|
int nvals = 0;
|
||||||
|
|
||||||
int direction = 0;
|
int direction = 0;
|
||||||
@ -306,8 +315,8 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
|
|||||||
|
|
||||||
if (pC_->getMsgPrintControl().shouldBePrinted(
|
if (pC_->getMsgPrintControl().shouldBePrinted(
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, timedOut,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, timedOut,
|
||||||
pC_->asynUserSelf())) {
|
pC_->pasynUser())) {
|
||||||
asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR,
|
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d\nAsked for a "
|
"Controller \"%s\", axis %d => %s, line %d\nAsked for a "
|
||||||
"handshake at %ld s and didn't get a positive reply yet "
|
"handshake at %ld s and didn't get a positive reply yet "
|
||||||
"(current time is %ld s).\n",
|
"(current time is %ld s).\n",
|
||||||
@ -341,6 +350,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
|
|||||||
// Handshake has been performed successfully -> Continue with the
|
// Handshake has been performed successfully -> Continue with the
|
||||||
// poll
|
// poll
|
||||||
waitForHandshake_ = false;
|
waitForHandshake_ = false;
|
||||||
|
targetReachedUninitialized_ = false;
|
||||||
} else {
|
} else {
|
||||||
// Still waiting for the handshake - try again in the next busy
|
// Still waiting for the handshake - try again in the next busy
|
||||||
// poll. This is already part of the movement procedure.
|
// poll. This is already part of the movement procedure.
|
||||||
@ -385,12 +395,18 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
|
|||||||
return rw_status;
|
return rw_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the motor is switched off or if it reached its target, it is not
|
if (targetReachedUninitialized_) {
|
||||||
// moving.
|
|
||||||
if (targetReached() || !switchedOn()) {
|
|
||||||
*moving = false;
|
*moving = false;
|
||||||
} else {
|
} else {
|
||||||
*moving = true;
|
if (targetReached() || !switchedOn()) {
|
||||||
|
*moving = false;
|
||||||
|
} else {
|
||||||
|
*moving = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetReached()) {
|
||||||
|
targetReachedUninitialized_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the current position
|
// Read the current position
|
||||||
@ -420,9 +436,9 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
|
|||||||
since this information is not reliable.
|
since this information is not reliable.
|
||||||
*/
|
*/
|
||||||
if (communicationError()) {
|
if (communicationError()) {
|
||||||
if (pC_->getMsgPrintControl().shouldBePrinted(
|
if (pC_->getMsgPrintControl().shouldBePrinted(keyError, true,
|
||||||
keyError, true, pC_->asynUserSelf())) {
|
pC_->pasynUser())) {
|
||||||
asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR,
|
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line "
|
"Controller \"%s\", axis %d => %s, line "
|
||||||
"%d\nCommunication error.%s\n",
|
"%d\nCommunication error.%s\n",
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
@ -579,8 +595,8 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
|
|||||||
|
|
||||||
if (strlen(shellMessage) > 0) {
|
if (strlen(shellMessage) > 0) {
|
||||||
if (pC_->getMsgPrintControl().shouldBePrinted(
|
if (pC_->getMsgPrintControl().shouldBePrinted(
|
||||||
keyError, true, pC_->asynUserSelf())) {
|
keyError, true, pC_->pasynUser())) {
|
||||||
asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR,
|
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line "
|
"Controller \"%s\", axis %d => %s, line "
|
||||||
"%d\n%s%s\n",
|
"%d\n%s%s\n",
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__,
|
||||||
@ -597,7 +613,7 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pC_->getMsgPrintControl().resetCount(keyError, pC_->asynUserSelf());
|
pC_->getMsgPrintControl().resetCount(keyError, pC_->pasynUser());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read out the limits, if the motor is not moving
|
// Read out the limits, if the motor is not moving
|
||||||
@ -750,7 +766,7 @@ asynStatus masterMacsAxis::doMove(double position, int relative,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (enabled == 0) {
|
if (enabled == 0) {
|
||||||
asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR,
|
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nAxis is "
|
"Controller \"%s\", axis %d => %s, line %d:\nAxis is "
|
||||||
"disabled.\n",
|
"disabled.\n",
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
||||||
@ -762,7 +778,7 @@ asynStatus masterMacsAxis::doMove(double position, int relative,
|
|||||||
motorVelocity = maxVelocity * motorRecResolution;
|
motorVelocity = maxVelocity * motorRecResolution;
|
||||||
|
|
||||||
asynPrint(
|
asynPrint(
|
||||||
pC_->asynUserSelf(), ASYN_TRACE_FLOW,
|
pC_->pasynUser(), ASYN_TRACE_FLOW,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nMove to position %lf.\n",
|
"Controller \"%s\", axis %d => %s, line %d:\nMove to position %lf.\n",
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, position);
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__, position);
|
||||||
|
|
||||||
@ -805,7 +821,7 @@ asynStatus masterMacsAxis::doMove(double position, int relative,
|
|||||||
return rw_status;
|
return rw_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
asynPrint(pC_->asynUserSelf(), ASYN_TRACE_FLOW,
|
asynPrint(pC_->pasynUser(), ASYN_TRACE_FLOW,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nSetting speed "
|
"Controller \"%s\", axis %d => %s, line %d:\nSetting speed "
|
||||||
"to %lf.\n",
|
"to %lf.\n",
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
@ -825,11 +841,17 @@ asynStatus masterMacsAxis::doMove(double position, int relative,
|
|||||||
return rw_status;
|
return rw_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the motor has just been enabled, use Enable
|
||||||
|
double timeout = pC_->comTimeout();
|
||||||
|
if (targetReachedUninitialized_ && timeout < PowerCycleTimeout) {
|
||||||
|
timeout = PowerCycleTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
// Start the move
|
// Start the move
|
||||||
if (relative) {
|
if (relative) {
|
||||||
rw_status = pC_->write(axisNo_, 00, "2");
|
rw_status = pC_->write(axisNo_, 00, "2", timeout);
|
||||||
} else {
|
} else {
|
||||||
rw_status = pC_->write(axisNo_, 00, "1");
|
rw_status = pC_->write(axisNo_, 00, "1", timeout);
|
||||||
}
|
}
|
||||||
if (rw_status != asynSuccess) {
|
if (rw_status != asynSuccess) {
|
||||||
pl_status = setIntegerParam(pC_->motorStatusProblem(), true);
|
pl_status = setIntegerParam(pC_->motorStatusProblem(), true);
|
||||||
@ -912,7 +934,7 @@ asynStatus masterMacsAxis::doHome(double min_velocity, double max_velocity,
|
|||||||
// Status of parameter library operations
|
// Status of parameter library operations
|
||||||
asynStatus pl_status = asynSuccess;
|
asynStatus pl_status = asynSuccess;
|
||||||
|
|
||||||
char response[pC_->MAXBUF_];
|
char response[pC_->MAXBUF_] = {0};
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
@ -964,7 +986,8 @@ asynStatus masterMacsAxis::readEncoderType() {
|
|||||||
// Status of parameter library operations
|
// Status of parameter library operations
|
||||||
asynStatus pl_status = asynSuccess;
|
asynStatus pl_status = asynSuccess;
|
||||||
|
|
||||||
char command[pC_->MAXBUF_], response[pC_->MAXBUF_];
|
char command[pC_->MAXBUF_] = {0};
|
||||||
|
char response[pC_->MAXBUF_] = {0};
|
||||||
int nvals = 0;
|
int nvals = 0;
|
||||||
int encoder_id = 0;
|
int encoder_id = 0;
|
||||||
|
|
||||||
@ -1016,6 +1039,13 @@ asynStatus masterMacsAxis::enable(bool on) {
|
|||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
|
/*
|
||||||
|
When the motor is changing its enable state, its targetReached bit is set to
|
||||||
|
0. In order to prevent the poll method in interpreting the motor state as
|
||||||
|
"moving", this flag is used. It is reset in the handshake.
|
||||||
|
*/
|
||||||
|
targetReachedUninitialized_ = true;
|
||||||
|
|
||||||
doPoll(&moving);
|
doPoll(&moving);
|
||||||
|
|
||||||
// If the axis is currently moving, it cannot be disabled. Ignore the
|
// If the axis is currently moving, it cannot be disabled. Ignore the
|
||||||
@ -1023,7 +1053,7 @@ asynStatus masterMacsAxis::enable(bool on) {
|
|||||||
// axis instead of "moving", since status -6 is also moving, but the
|
// axis instead of "moving", since status -6 is also moving, but the
|
||||||
// motor can actually be disabled in this state!
|
// motor can actually be disabled in this state!
|
||||||
if (moving) {
|
if (moving) {
|
||||||
asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR,
|
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nAxis is not "
|
"Controller \"%s\", axis %d => %s, line %d:\nAxis is not "
|
||||||
"idle and can therefore not be disabled.\n",
|
"idle and can therefore not be disabled.\n",
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__);
|
||||||
@ -1045,7 +1075,7 @@ asynStatus masterMacsAxis::enable(bool on) {
|
|||||||
|
|
||||||
if ((readyToBeSwitchedOn() && switchedOn()) == on) {
|
if ((readyToBeSwitchedOn() && switchedOn()) == on) {
|
||||||
asynPrint(
|
asynPrint(
|
||||||
pC_->asynUserSelf(), ASYN_TRACE_WARNING,
|
pC_->pasynUser(), ASYN_TRACE_WARNING,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nAxis is already %s.\n",
|
"Controller \"%s\", axis %d => %s, line %d:\nAxis is already %s.\n",
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
on ? "enabled" : "disabled");
|
on ? "enabled" : "disabled");
|
||||||
@ -1054,7 +1084,7 @@ asynStatus masterMacsAxis::enable(bool on) {
|
|||||||
|
|
||||||
// Enable / disable the axis if it is not moving
|
// Enable / disable the axis if it is not moving
|
||||||
snprintf(value, sizeof(value), "%d", on);
|
snprintf(value, sizeof(value), "%d", on);
|
||||||
asynPrint(pC_->asynUserSelf(), ASYN_TRACE_FLOW,
|
asynPrint(pC_->pasynUser(), ASYN_TRACE_FLOW,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\n%s axis.\n",
|
"Controller \"%s\", axis %d => %s, line %d:\n%s axis.\n",
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
on ? "Enable" : "Disable");
|
on ? "Enable" : "Disable");
|
||||||
@ -1072,7 +1102,12 @@ asynStatus masterMacsAxis::enable(bool on) {
|
|||||||
// The answer to the enable command on MasterMACS might take some time,
|
// The answer to the enable command on MasterMACS might take some time,
|
||||||
// hence we wait for a custom timespan in seconds instead of
|
// hence we wait for a custom timespan in seconds instead of
|
||||||
// pC_->comTimeout_
|
// pC_->comTimeout_
|
||||||
rw_status = pC_->write(axisNo_, 04, value, 1.0);
|
double timeout = pC_->comTimeout();
|
||||||
|
if (targetReachedUninitialized_ && timeout < PowerCycleTimeout) {
|
||||||
|
timeout = PowerCycleTimeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
rw_status = pC_->write(axisNo_, 04, value, timeout);
|
||||||
if (rw_status != asynSuccess) {
|
if (rw_status != asynSuccess) {
|
||||||
return rw_status;
|
return rw_status;
|
||||||
}
|
}
|
||||||
@ -1099,7 +1134,7 @@ asynStatus masterMacsAxis::enable(bool on) {
|
|||||||
|
|
||||||
// Failed to change axis status within timeout_enable_disable => Send a
|
// Failed to change axis status within timeout_enable_disable => Send a
|
||||||
// corresponding message
|
// corresponding message
|
||||||
asynPrint(pC_->asynUserSelf(), ASYN_TRACE_ERROR,
|
asynPrint(pC_->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nFailed to %s axis "
|
"Controller \"%s\", axis %d => %s, line %d:\nFailed to %s axis "
|
||||||
"within %d seconds\n",
|
"within %d seconds\n",
|
||||||
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
pC_->portName, axisNo_, __PRETTY_FUNCTION__, __LINE__,
|
||||||
@ -1132,7 +1167,7 @@ std::bitset<16> toBitset(float val) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
asynStatus masterMacsAxis::readAxisStatus() {
|
asynStatus masterMacsAxis::readAxisStatus() {
|
||||||
char response[pC_->MAXBUF_];
|
char response[pC_->MAXBUF_] = {0};
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
@ -1153,7 +1188,7 @@ asynStatus masterMacsAxis::readAxisStatus() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
asynStatus masterMacsAxis::readAxisError() {
|
asynStatus masterMacsAxis::readAxisError() {
|
||||||
char response[pC_->MAXBUF_];
|
char response[pC_->MAXBUF_] = {0};
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
|
@ -111,6 +111,8 @@ class masterMacsAxis : public sinqAxis {
|
|||||||
bool waitForHandshake_;
|
bool waitForHandshake_;
|
||||||
time_t timeAtHandshake_;
|
time_t timeAtHandshake_;
|
||||||
|
|
||||||
|
bool targetReachedUninitialized_;
|
||||||
|
|
||||||
asynStatus readConfig();
|
asynStatus readConfig();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -70,7 +70,7 @@ masterMacsController::masterMacsController(const char *portName,
|
|||||||
the message length is encoded in the message header.
|
the message length is encoded in the message header.
|
||||||
*/
|
*/
|
||||||
const char *message_from_device = "\x0D"; // Hex-code for CR
|
const char *message_from_device = "\x0D"; // Hex-code for CR
|
||||||
status = pasynOctetSyncIO->setInputEos(ipPortAsynOctetSyncIO_,
|
status = pasynOctetSyncIO->setInputEos(pasynOctetSyncIOipPort(),
|
||||||
message_from_device,
|
message_from_device,
|
||||||
strlen(message_from_device));
|
strlen(message_from_device));
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
@ -79,7 +79,7 @@ masterMacsController::masterMacsController(const char *portName,
|
|||||||
"input EOS failed with %s).\nTerminating IOC",
|
"input EOS failed with %s).\nTerminating IOC",
|
||||||
portName, __PRETTY_FUNCTION__, __LINE__,
|
portName, __PRETTY_FUNCTION__, __LINE__,
|
||||||
stringifyAsynStatus(status));
|
stringifyAsynStatus(status));
|
||||||
pasynOctetSyncIO->disconnect(ipPortAsynOctetSyncIO_);
|
pasynOctetSyncIO->disconnect(pasynOctetSyncIOipPort());
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ masterMacsController::masterMacsController(const char *portName,
|
|||||||
"ParamLib callbacks failed with %s).\nTerminating IOC",
|
"ParamLib callbacks failed with %s).\nTerminating IOC",
|
||||||
portName, __PRETTY_FUNCTION__, __LINE__,
|
portName, __PRETTY_FUNCTION__, __LINE__,
|
||||||
stringifyAsynStatus(status));
|
stringifyAsynStatus(status));
|
||||||
pasynOctetSyncIO->disconnect(ipPortAsynOctetSyncIO_);
|
pasynOctetSyncIO->disconnect(pasynOctetSyncIOipPort());
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -133,8 +133,6 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
|
|||||||
asynStatus pl_status = asynSuccess;
|
asynStatus pl_status = asynSuccess;
|
||||||
char fullCommand[MAXBUF_] = {0};
|
char fullCommand[MAXBUF_] = {0};
|
||||||
char fullResponse[MAXBUF_] = {0};
|
char fullResponse[MAXBUF_] = {0};
|
||||||
char printableCommand[MAXBUF_] = {0};
|
|
||||||
char printableResponse[MAXBUF_] = {0};
|
|
||||||
char drvMessageText[MAXBUF_] = {0};
|
char drvMessageText[MAXBUF_] = {0};
|
||||||
int motorStatusProblem = 0;
|
int motorStatusProblem = 0;
|
||||||
|
|
||||||
@ -158,7 +156,7 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
|
|||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
// Check if a timeout has been given
|
// Check if a custom timeout has been given
|
||||||
if (comTimeout < 0.0) {
|
if (comTimeout < 0.0) {
|
||||||
comTimeout = comTimeout_;
|
comTimeout = comTimeout_;
|
||||||
}
|
}
|
||||||
@ -169,6 +167,7 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
|
|||||||
return asynError;
|
return asynError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build the full command depending on the inputs to this function
|
||||||
if (isRead) {
|
if (isRead) {
|
||||||
snprintf(fullCommand, MAXBUF_ - 1, "%dR%02d\x0D", axisNo, tcpCmd);
|
snprintf(fullCommand, MAXBUF_ - 1, "%dR%02d\x0D", axisNo, tcpCmd);
|
||||||
} else {
|
} else {
|
||||||
@ -183,95 +182,39 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
|
|||||||
// Calculate the command length
|
// Calculate the command length
|
||||||
const size_t fullCommandLength = strlen(fullCommand);
|
const size_t fullCommandLength = strlen(fullCommand);
|
||||||
|
|
||||||
adjustForPrint(printableCommand, fullCommand, MAXBUF_);
|
// Flush the IOC-side socket, then write the command and wait for the
|
||||||
|
// response.
|
||||||
|
status = pasynOctetSyncIO->writeRead(
|
||||||
|
pasynOctetSyncIOipPort(), fullCommand, fullCommandLength, fullResponse,
|
||||||
|
MAXBUF_, comTimeout, &nbytesOut, &nbytesIn, &eomReason);
|
||||||
|
|
||||||
// Send out the command
|
// If a communication error occured, print this message to the
|
||||||
status = pasynOctetSyncIO->write(ipPortAsynOctetSyncIO_, fullCommand,
|
msgPrintControlKey comKey =
|
||||||
fullCommandLength, comTimeout, &nbytesOut);
|
|
||||||
|
|
||||||
if (status != asynSuccess) {
|
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nError "
|
|
||||||
"%s while writing to the controller\n",
|
|
||||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
|
||||||
stringifyAsynStatus(status));
|
|
||||||
}
|
|
||||||
|
|
||||||
msgPrintControlKey writeKey =
|
|
||||||
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||||
|
if (status != asynSuccess) {
|
||||||
if (status == asynSuccess) {
|
if (msgPrintControl_.shouldBePrinted(comKey, true, pasynUserSelf)) {
|
||||||
msgPrintControl_.resetCount(writeKey, pasynUserSelf);
|
char printableCommand[MAXBUF_] = {0};
|
||||||
|
adjustForPrint(printableCommand, fullCommand, MAXBUF_);
|
||||||
// Try to read the answer repeatedly
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
int maxTrials = 2;
|
"Controller \"%s\", axis %d => %s, line %d:\nError "
|
||||||
for (int i = 0; i < maxTrials; i++) {
|
"%s while sending command %s to the controller\n",
|
||||||
|
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
||||||
/*
|
stringifyAsynStatus(status), printableCommand);
|
||||||
A typical response of the MasterMacs controller looks like this:
|
|
||||||
(.. TCP Header ...) 31 20 52 20 31 31 3d 35 31 32 2e 30 30 30 30 06
|
|
||||||
0d 00 00 00 00 00 00 00 00 00 00 00 00 00
|
|
||||||
The message terminator is the carriage return (0d), which is
|
|
||||||
specified in the controller constructor as the end-of-string (EOS)
|
|
||||||
character. However, we also need to remove the buffer zeros at the
|
|
||||||
end, because they will otherwise confuse the
|
|
||||||
pasynOctetSyncIO->read() during the next call. The
|
|
||||||
pasynOctetSyncIO->flush() method does exactly that: it takes all
|
|
||||||
bytes it can find in the socket and throws them away. We don't check
|
|
||||||
the return value of flush(), because it is always asynSuccess (see
|
|
||||||
https://www.slac.stanford.edu/grp/lcls/controls/global/doc/epics-modules/R3-14-12/asyn/asyn-R4-18-lcls2/asyn/interfaces/asynOctetBase.c)
|
|
||||||
*/
|
|
||||||
status = pasynOctetSyncIO->read(ipPortAsynOctetSyncIO_,
|
|
||||||
fullResponse, MAXBUF_, comTimeout,
|
|
||||||
&nbytesIn, &eomReason);
|
|
||||||
pasynOctetSyncIO->flush(ipPortAsynOctetSyncIO_);
|
|
||||||
|
|
||||||
if (status == asynSuccess) {
|
|
||||||
status = parseResponse(fullCommand, fullResponse,
|
|
||||||
drvMessageText, &valueStart, &valueStop,
|
|
||||||
axisNo, tcpCmd, isRead);
|
|
||||||
|
|
||||||
if (status == asynSuccess) {
|
|
||||||
// Received the correct message
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (status != asynTimeout) {
|
|
||||||
asynPrint(
|
|
||||||
this->pasynUserSelf, ASYN_TRACE_ERROR,
|
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nError "
|
|
||||||
"%s while reading from the controller\n",
|
|
||||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
|
||||||
stringifyAsynStatus(status));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i + 1 == maxTrials && status == asynError) {
|
|
||||||
asynPrint(
|
|
||||||
this->pasynUserSelf, ASYN_TRACE_ERROR,
|
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nFailed "
|
|
||||||
"%d times to get the correct response. Aborting read.\n",
|
|
||||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__, maxTrials);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (msgPrintControl_.shouldBePrinted(writeKey, true, pasynUserSelf)) {
|
msgPrintControl_.resetCount(comKey, pasynUserSelf);
|
||||||
asynPrint(
|
|
||||||
this->pasynUserSelf, ASYN_TRACE_ERROR,
|
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nError %s while "
|
|
||||||
"writing to the controller.%s\n",
|
|
||||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
|
||||||
stringifyAsynStatus(status), msgPrintControl_.getSuffix());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create custom error messages for different failure modes
|
// Create custom error messages for different failure modes
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case asynSuccess:
|
case asynSuccess:
|
||||||
|
// We did get a response, but does it make sense and is it designated as
|
||||||
|
// OK from the controller? This is checked here.
|
||||||
|
status = parseResponse(fullCommand, fullResponse, drvMessageText,
|
||||||
|
&valueStart, &valueStop, axisNo, tcpCmd, isRead);
|
||||||
|
|
||||||
if (isRead) {
|
// Read out the important information from the response
|
||||||
|
if (status == asynSuccess && isRead) {
|
||||||
/*
|
/*
|
||||||
If a property has been read, we need just the part between the
|
If a property has been read, we need just the part between the
|
||||||
"=" (0x3D) and the [ACK] (0x06). Therefore, we remove all
|
"=" (0x3D) and the [ACK] (0x06). Therefore, we remove all
|
||||||
@ -282,31 +225,30 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
|
|||||||
response[i] = fullResponse[i + valueStart];
|
response[i] = fullResponse[i + valueStart];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case asynTimeout:
|
case asynTimeout:
|
||||||
snprintf(drvMessageText, sizeof(drvMessageText),
|
snprintf(drvMessageText, sizeof(drvMessageText),
|
||||||
"connection timeout for axis %d", axisNo);
|
"Connection timeout. Please call the support.");
|
||||||
break;
|
break;
|
||||||
case asynDisconnected:
|
case asynDisconnected:
|
||||||
snprintf(drvMessageText, sizeof(drvMessageText),
|
snprintf(drvMessageText, sizeof(drvMessageText),
|
||||||
"axis is not connected");
|
"Axis is not connected.");
|
||||||
break;
|
break;
|
||||||
case asynDisabled:
|
case asynDisabled:
|
||||||
snprintf(drvMessageText, sizeof(drvMessageText), "axis is disabled");
|
snprintf(drvMessageText, sizeof(drvMessageText), "Axis is disabled.");
|
||||||
break;
|
break;
|
||||||
case asynError:
|
case asynError:
|
||||||
// Do nothing - error message drvMessageText has already been set.
|
// Do nothing - error message drvMessageText has already been set.
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
snprintf(drvMessageText, sizeof(drvMessageText),
|
snprintf(drvMessageText, sizeof(drvMessageText),
|
||||||
"Communication failed (%s)", stringifyAsynStatus(status));
|
"Communication failed (%s). Please call the support.",
|
||||||
|
stringifyAsynStatus(status));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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_);
|
|
||||||
pl_status = axis->setIntegerParam(this->motorStatusCommsError_, 0);
|
pl_status = axis->setIntegerParam(this->motorStatusCommsError_, 0);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
@ -401,6 +343,7 @@ asynStatus masterMacsController::parseResponse(
|
|||||||
|
|
||||||
if (msgPrintControl_.shouldBePrinted(parseKey, true,
|
if (msgPrintControl_.shouldBePrinted(parseKey, true,
|
||||||
pasynUserSelf)) {
|
pasynUserSelf)) {
|
||||||
|
adjustForPrint(printableCommand, fullCommand, MAXBUF_);
|
||||||
asynPrint(
|
asynPrint(
|
||||||
this->pasynUserSelf, ASYN_TRACE_ERROR,
|
this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nTried to "
|
"Controller \"%s\", axis %d => %s, line %d:\nTried to "
|
||||||
@ -440,13 +383,13 @@ asynStatus masterMacsController::parseResponse(
|
|||||||
|
|
||||||
if (msgPrintControl_.shouldBePrinted(parseKey, true,
|
if (msgPrintControl_.shouldBePrinted(parseKey, true,
|
||||||
pasynUserSelf)) {
|
pasynUserSelf)) {
|
||||||
asynPrint(
|
asynPrint(this->pasynUserSelf, ASYN_TRACEIO_DRIVER,
|
||||||
this->pasynUserSelf, ASYN_TRACEIO_DRIVER,
|
"Controller \"%s\", axis %d => %s, line "
|
||||||
"Controller \"%s\", axis %d => %s, line %d:\nMismatched "
|
"%d:\nMismatched "
|
||||||
"response %s to command %s.%s\n",
|
"response %s to command %s.%s\n",
|
||||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
||||||
printableResponse, printableCommand,
|
printableResponse, printableCommand,
|
||||||
msgPrintControl_.getSuffix());
|
msgPrintControl_.getSuffix());
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(drvMessageText, MAXBUF_,
|
snprintf(drvMessageText, MAXBUF_,
|
||||||
|
@ -118,6 +118,13 @@ class masterMacsController : public sinqController {
|
|||||||
// responses from it.
|
// responses from it.
|
||||||
static const uint32_t MAXBUF_ = 200;
|
static const uint32_t MAXBUF_ = 200;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the communication timeout used in the writeRead command
|
||||||
|
*
|
||||||
|
* @return double Timeout in seconds
|
||||||
|
*/
|
||||||
|
double comTimeout() { return comTimeout_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*
|
/*
|
||||||
Stores the constructor input comTimeout
|
Stores the constructor input comTimeout
|
||||||
|
171
utils/writeRead.py
Normal file
171
utils/writeRead.py
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
This script allows direct interaction with a MasterMACS-Controller over an ethernet connection.
|
||||||
|
To read the manual, simply run this script without any arguments.
|
||||||
|
|
||||||
|
Stefan Mathis, April 2025
|
||||||
|
"""
|
||||||
|
|
||||||
|
import struct
|
||||||
|
import socket
|
||||||
|
import curses
|
||||||
|
|
||||||
|
def packMasterMacsCommand(command):
|
||||||
|
# 0x0D = Carriage return
|
||||||
|
buf = struct.pack('B',0x0D)
|
||||||
|
buf = bytes(command,'utf-8') + buf
|
||||||
|
return bytes(command,'utf-8')
|
||||||
|
|
||||||
|
def readMasterMacsReply(input):
|
||||||
|
msg = bytearray()
|
||||||
|
expectAck = True
|
||||||
|
while True:
|
||||||
|
b = input.recv(1)
|
||||||
|
bint = int.from_bytes(b,byteorder='little')
|
||||||
|
if bint == 2 or bint == 7: #STX or BELL
|
||||||
|
expectAck = False
|
||||||
|
continue
|
||||||
|
if expectAck and bint == 6: # ACK
|
||||||
|
return bytes(msg)
|
||||||
|
else:
|
||||||
|
if bint == 13 and not expectAck: # CR
|
||||||
|
return bytes(msg)
|
||||||
|
else:
|
||||||
|
msg.append(bint)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
from sys import argv
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
addr = argv[1].split(':')
|
||||||
|
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
|
||||||
|
s.connect((addr[0],int(addr[1])))
|
||||||
|
|
||||||
|
if len(argv) == 3:
|
||||||
|
buf = packMasterMacsCommand(argv[2])
|
||||||
|
s.send(buf)
|
||||||
|
reply = readMasterMacsReply(s)
|
||||||
|
print(reply.decode('utf-8') + '\n')
|
||||||
|
|
||||||
|
else:
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
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]:
|
||||||
|
buf = packMasterMacsCommand(history[ptr])
|
||||||
|
s.send(buf)
|
||||||
|
reply = readMasterMacsReply(s)
|
||||||
|
stdscr.addstr("\n" + reply.decode('utf-8')[0:-1])
|
||||||
|
|
||||||
|
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()
|
||||||
|
|
||||||
|
finally:
|
||||||
|
|
||||||
|
# to quit
|
||||||
|
curses.nocbreak()
|
||||||
|
stdscr.keypad(False)
|
||||||
|
curses.echo()
|
||||||
|
curses.endwin()
|
||||||
|
|
||||||
|
except:
|
||||||
|
print("""
|
||||||
|
Invalid Arguments
|
||||||
|
|
||||||
|
Option 1: Single Command
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
Usage: writeRead.py pmachost:port command
|
||||||
|
This then returns the response for command.
|
||||||
|
|
||||||
|
Option 2: CLI Mode
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Usage: writeRead.py pmachost:port
|
||||||
|
|
||||||
|
You can then type in a command, hit enter, and the response will see
|
||||||
|
the reponse, before being prompted to again enter a command. Type
|
||||||
|
'quit' to close prompt.
|
||||||
|
""")
|
||||||
|
|
Reference in New Issue
Block a user