16 Commits
1.4.1 ... main

Author SHA1 Message Date
6adca95ade Fixed wrong doc
Some checks failed
Test And Build / Lint (push) Failing after 4s
Test And Build / Build (push) Successful in 7s
2025-11-03 11:17:04 +01:00
b4454a3ab6 Fixed wrong doc
Some checks failed
Test And Build / Lint (push) Failing after 4s
Test And Build / Build (push) Successful in 7s
2025-11-03 11:16:24 +01:00
73c96a73bf Usage in IOC shell is part of the user guide
Some checks failed
Test And Build / Lint (push) Failing after 4s
Test And Build / Build (push) Successful in 8s
2025-11-03 11:14:39 +01:00
e1732639b2 Added manual and .gitignore
Some checks failed
Test And Build / Lint (push) Failing after 4s
Test And Build / Build (push) Successful in 7s
2025-11-03 08:40:25 +01:00
6f72766ae6 Improved script docs and script usage description in README.md
Some checks failed
Test And Build / Lint (push) Failing after 4s
Test And Build / Build (push) Successful in 7s
Also introduced graceful error handling when trying to access
interactive mode on Windows.
2025-09-24 15:43:22 +02:00
a435c3c960 Update src/masterMacsAxis.cpp
Some checks failed
Test And Build / Lint (push) Failing after 4s
Test And Build / Build (push) Successful in 7s
Updated comment: encoder type 0 can also mean "no encoder"
2025-09-23 15:11:07 +02:00
f1c41d3081 Perform poll even if init fails
Some checks failed
Test And Build / Lint (push) Failing after 5s
Test And Build / Build (push) Successful in 8s
2025-09-17 13:12:21 +02:00
d78586a815 Updated sinqMotor to 1.5.6
Some checks failed
Test And Build / Lint (push) Failing after 4s
Test And Build / Build (push) Successful in 7s
2025-09-17 12:38:30 +02:00
ebcf99ac56 Updated sinqMotor to 1.5.5 2025-09-17 12:34:47 +02:00
de32298609 Updated sinqMotor to 1.5.4 2025-09-17 12:19:00 +02:00
8f457889c0 Updated sinqMotor to 1.5.3 2025-09-17 11:28:53 +02:00
6f63e521c1 Updated sinqMotor to 1.5.2 2025-09-17 11:25:40 +02:00
670f01fbe3 Updated sinqMotor to 1.5.1 to get a better error message in case of speed problems 2025-09-17 10:54:56 +02:00
25286652d5 Moved version definition in Makefile
Some checks failed
Test And Build / Lint (push) Failing after 3s
Test And Build / Build (push) Successful in 7s
The expected version can now be set in the Makefile via USR_CXXFLAGS.
Additionally, the README.md has received documentation regarding the
version check. Lastly, the version check can now be disabled by omitting
the flags or setting one of them to a negative value.
2025-08-22 13:18:43 +02:00
27f7cc8602 Added version check prototype
Some checks failed
Test And Build / Lint (push) Failing after 4s
Test And Build / Build (push) Successful in 8s
2025-08-22 08:46:30 +02:00
21a73717a5 Fixed handshake detection and reset bugs
Some checks failed
Test And Build / Lint (push) Failing after 4s
Test And Build / Build (push) Successful in 7s
2025-08-14 17:16:14 +02:00
12 changed files with 509 additions and 281 deletions

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
O.*
.cvsignore
.vscode
utils/__pycache__

View File

@@ -29,4 +29,8 @@ TEMPLATES += db/masterMacs.db
DBDS += sinqMotor/src/sinqMotor.dbd DBDS += sinqMotor/src/sinqMotor.dbd
DBDS += src/masterMacs.dbd DBDS += src/masterMacs.dbd
USR_CFLAGS += -Wall -Wextra -Weffc++ -Wunused-result -Wextra -Werror USR_CFLAGS += -Wall -Wextra -Wunused-result -Wextra -Werror
# These flags define the expected firmware version. See README.md, section
# "Firmware version checking" for details.
USR_CXXFLAGS += -DFIRMWARE_MAJOR_VERSION=2 -DFIRMWARE_MINOR_VERSION=2 -Wall -Wextra -Weffc++ -Wunused-result -Wextra

BIN
MasterMACS_manual.pdf Normal file

Binary file not shown.

View File

@@ -17,15 +17,38 @@ The folder "utils" contains utility scripts for working with masterMacs motor co
- decodeError.py: Take the return message of a R11 (read error) 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. - writeRead.py: Send messages to the controller and receive answers.
## Developer guide These scripts can be run from anywhere. On Linux, the shebang (#!) automatically
calls the system Python 3 executable:
```bash
# To show the help, use either flag -h or --help (works on all scripts)
/path/to/mastermacs_repo/utils/decodeStatus.py -h
/path/to/mastermacs_repo/utils/decodeError.py --help
/path/to/mastermacs_repo/utils/writeRead.py -h
# To run in non-interactive mode, give the value as an argument
/path/to/mastermacs_repo/utils/decodeStatus.py 1234
/path/to/mastermacs_repo/utils/decodeError.py 5678
/path/to/mastermacs_repo/utils/writeRead.py "R11"
# To run in interactive mode, don't give any argument. This only works on Linux
/path/to/mastermacs_repo/utils/decodeStatus.py
/path/to/mastermacs_repo/utils/decodeError.py
/path/to/mastermacs_repo/utils/writeRead.py
```
To use these scripts on Windows, prefix the Python 3 executable:
```bash
C:/path/to/python3.exe C:/path/to/mastermacs_repo/utils/decodeStatus.py 1234
```
### Usage in IOC shell ### Usage in IOC shell
masterMacs exposes the following IOC shell functions (all in masterMacsController.cpp): masterMacs exposes the following IOC shell functions:
- `masterMacsController`: Create a new controller object. - `masterMacsController`: Create a new controller object.
- `masterMacsAxis`: Create a new axis object. - `masterMacsAxis`: Create a new axis object.
The full mcu.cmd file looks like this: The full masterMacsX.cmd file looks like this:
``` ```
# Define the name of the controller and the corresponding port # Define the name of the controller and the corresponding port
@@ -62,10 +85,38 @@ dbLoadTemplate("$(TOP)/$(NAME).substitutions", "INSTR=$(INSTR)$(NAME):,CONTROLLE
dbLoadRecords("$(masterMacs_DB)/asynRecord.db","P=$(INSTR)$(NAME),PORT=$(ASYN_PORT)") dbLoadRecords("$(masterMacs_DB)/asynRecord.db","P=$(INSTR)$(NAME),PORT=$(ASYN_PORT)")
``` ```
## Developer guide
### Versioning ### Versioning
Please see the documentation for the module sinqMotor: https://git.psi.ch/sinq-epics-modules/sinqmotor/-/blob/main/README.md. Please see the documentation for the module sinqMotor: https://git.psi.ch/sinq-epics-modules/sinqmotor/-/blob/main/README.md.
### Firmware version checking
This driver expects a certain version of the firmware running on the controller itself.
This is checked at IOC startup by reading the version directly from the hardware.
If the firmware version is incompatible to the driver, the IOC will be shut down.
If the firmware version cannot be read (e.g. because the variable used to do so
does not exist yet on old firmware versions), the firmware is assumed to be compatible
to the driver.
The version check is separated into a check of the major and the minor firmware
version against expected values. The firmware is seen as compatible if the following conditions hold:
- Read-out major version == Expected major version
- Read-out read major version >= Expected minor version
The expected versions are defined via compiler flags in `Makefile`:
```
USR_CXXFLAGS += -DFIRMWARE_MAJOR_VERSION=1 -DFIRMWARE_MINOR_VERSION=0
```
Be aware that these flags are only used to compile C++-files (.cpp, .cxx) and not
C-files (.c). For C-files, the Makefile variable `USR_CFLAGS` must be used.
In order to disable the checks, the flags can be set to -1 or just be removed
entirely. If one of the flags is not given, both the major and the minor version
checks are deactivated.
### How to build it ### How to build it
Please see the documentation for the module sinqMotor: https://git.psi.ch/sinq-epics-modules/sinqmotor/-/blob/main/README.md. Please see the documentation for the module sinqMotor: https://git.psi.ch/sinq-epics-modules/sinqmotor/-/blob/main/README.md.

View File

@@ -85,7 +85,14 @@ void appendErrorMessage(char *fullMessage, size_t capacityFullMessage,
} }
masterMacsAxis::masterMacsAxis(masterMacsController *pC, int axisNo) masterMacsAxis::masterMacsAxis(masterMacsController *pC, int axisNo)
: sinqAxis(pC, axisNo), pC_(pC) { : sinqAxis(pC, axisNo), pC_(pC),
pMasterMacsA_(std::make_unique<masterMacsAxisImpl>((masterMacsAxisImpl){
.axisStatus = std::bitset<16>(0),
.axisError = std::bitset<16>(0),
.waitForHandshake = false,
.timeAtHandshake = 0,
.targetReachedUninitialized = true,
})) {
asynStatus status = asynSuccess; asynStatus status = asynSuccess;
@@ -118,14 +125,6 @@ masterMacsAxis::masterMacsAxis(masterMacsController *pC, int axisNo)
// Collect all axes into this list which will be used in the hook function // Collect all axes into this list which will be used in the hook function
axes.push_back(this); axes.push_back(this);
pMasterMacsA_ = std::make_unique<masterMacsAxisImpl>((masterMacsAxisImpl){
.axisStatus = std::bitset<16>(0),
.axisError = std::bitset<16>(0),
.waitForHandshake = false,
.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) {
@@ -330,10 +329,8 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
// Does the axis need to be intialized? // Does the axis need to be intialized?
if (needInit()) { if (needInit()) {
rw_status = init(); // Perform the rest of the poll, but remember if sth. failed in the init.
if (rw_status != asynSuccess) { poll_status = init();
return rw_status;
}
} }
// Are we currently waiting for a handshake? // Are we currently waiting for a handshake?
@@ -357,7 +354,10 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
if (timedOut) { if (timedOut) {
setAxisParamChecked(this, motorMessageText, setAxisParamChecked(this, motorMessageText,
"Timed out while waiting for a handshake"); "Timed out while waiting for a handshake. "
"Please call the support.");
poll_status = asynError;
} }
pC_->read(axisNo_, 86, response); pC_->read(axisNo_, 86, response);
@@ -377,14 +377,10 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
pMasterMacsA_->waitForHandshake = false; pMasterMacsA_->waitForHandshake = false;
pMasterMacsA_->targetReachedUninitialized = false; pMasterMacsA_->targetReachedUninitialized = false;
} else { } else {
// Still waiting for the handshake - try again in the next busy
// poll. This is already part of the movement procedure.
*moving = true; *moving = true;
setAxisParamChecked(this, motorStatusMoving, *moving); setAxisParamChecked(this, motorStatusMoving, *moving);
setAxisParamChecked(this, motorStatusDone, !(*moving)); setAxisParamChecked(this, motorStatusDone, !(*moving));
return poll_status;
return asynSuccess;
} }
} }
@@ -403,6 +399,9 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
return rw_status; return rw_status;
} }
// If we wait for a handshake, but the motor was moving in its last poll
// cycle and has reached its target, it is not moving. Otherwise it is
// considered moving, even if we're still waiting for the handshake.
if (pMasterMacsA_->targetReachedUninitialized) { if (pMasterMacsA_->targetReachedUninitialized) {
*moving = false; *moving = false;
} else { } else {
@@ -679,7 +678,6 @@ asynStatus masterMacsAxis::doPoll(bool *moving) {
if (pl_status != asynSuccess) { if (pl_status != asynSuccess) {
return pl_status; return pl_status;
} }
return poll_status; return poll_status;
} }
@@ -687,6 +685,11 @@ asynStatus masterMacsAxis::doMove(double position, int relative,
double minVelocity, double maxVelocity, double minVelocity, double maxVelocity,
double acceleration) { double acceleration) {
// Suppress unused variable warning
(void)minVelocity;
(void)maxVelocity;
(void)acceleration;
// Status of read-write-operations of ASCII commands to the controller // Status of read-write-operations of ASCII commands to the controller
asynStatus status = asynSuccess; asynStatus status = asynSuccess;
@@ -789,6 +792,9 @@ asynStatus masterMacsAxis::doMove(double position, int relative,
asynStatus masterMacsAxis::stop(double acceleration) { asynStatus masterMacsAxis::stop(double acceleration) {
// Suppress unused variable warning
(void)acceleration;
asynStatus status = pC_->write(axisNo_, 00, "8"); asynStatus status = pC_->write(axisNo_, 00, "8");
if (status != asynSuccess) { if (status != asynSuccess) {
setAxisParamChecked(this, motorStatusProblem, true); setAxisParamChecked(this, motorStatusProblem, true);
@@ -805,8 +811,8 @@ asynStatus masterMacsAxis::doReset() {
asynStatus status = asynSuccess; asynStatus status = asynSuccess;
// Reset the controller ("node reset") // Reset any errors
status = pC_->write(axisNo_, 16, ""); status = pC_->write(axisNo_, 17, "");
if (status != asynSuccess) { if (status != asynSuccess) {
setAxisParamChecked(this, motorStatusProblem, true); setAxisParamChecked(this, motorStatusProblem, true);
} }
@@ -822,9 +828,9 @@ asynStatus masterMacsAxis::nodeReset() {
asynStatus status = asynSuccess; asynStatus status = asynSuccess;
// Reset any errors in the controller. Since the node reset results in a // Reset the controller ("node reset"). Since the node reset results in a
// power cycle, we use the corresponding timeout. // power cycle, we use the corresponding timeout.
status = pC_->write(axisNo_, 17, "", PowerCycleTimeout); status = pC_->write(axisNo_, 16, "", PowerCycleTimeout);
if (status != asynSuccess) { if (status != asynSuccess) {
setAxisParamChecked(this, motorStatusProblem, true); setAxisParamChecked(this, motorStatusProblem, true);
} }
@@ -844,13 +850,19 @@ asynStatus masterMacsAxis::nodeReset() {
/* /*
Home the axis. On absolute encoder systems, this is a no-op Home the axis. On absolute encoder systems, this is a no-op
*/ */
asynStatus masterMacsAxis::doHome(double min_velocity, double max_velocity, asynStatus masterMacsAxis::doHome(double minVelocity, double maxVelocity,
double acceleration, int forwards) { double acceleration, int forwards) {
char response[pC_->MAXBUF_] = {0}; char response[pC_->MAXBUF_] = {0};
// ========================================================================= // =========================================================================
// Suppress unused variable warning
(void)minVelocity;
(void)maxVelocity;
(void)acceleration;
(void)forwards;
getAxisParamChecked(this, encoderType, &response); getAxisParamChecked(this, encoderType, &response);
// Only send the home command if the axis has an incremental encoder // Only send the home command if the axis has an incremental encoder
@@ -904,7 +916,7 @@ asynStatus masterMacsAxis::readEncoderType() {
/* /*
Defined encoder IDs: Defined encoder IDs:
0=INC (Incremental) 0=INC (Incremental or no encoder)
1=SSI (Absolute encoder with SSI interface) 1=SSI (Absolute encoder with SSI interface)
2=SSI (Absolute encoder with BiSS interface) 2=SSI (Absolute encoder with BiSS interface)
*/ */
@@ -1245,8 +1257,9 @@ static const iocshArg CreateAxisArg0 = {"Controller name (e.g. mmacs1)",
static const iocshArg CreateAxisArg1 = {"Axis number", iocshArgInt}; static const iocshArg CreateAxisArg1 = {"Axis number", iocshArgInt};
static const iocshArg *const CreateAxisArgs[] = {&CreateAxisArg0, static const iocshArg *const CreateAxisArgs[] = {&CreateAxisArg0,
&CreateAxisArg1}; &CreateAxisArg1};
static const iocshFuncDef configMasterMacsCreateAxis = {"masterMacsAxis", 2, static const iocshFuncDef configMasterMacsCreateAxis = {
CreateAxisArgs}; "masterMacsAxis", 2, CreateAxisArgs,
"Create a new instance of a MasterMACS axis."};
static void configMasterMacsCreateAxisCallFunc(const iocshArgBuf *args) { static void configMasterMacsCreateAxisCallFunc(const iocshArgBuf *args) {
masterMacsCreateAxis(args[0].sval, args[1].ival); masterMacsCreateAxis(args[0].sval, args[1].ival);
} }

View File

@@ -16,6 +16,13 @@ class HIDDEN masterMacsAxis : public sinqAxis {
*/ */
masterMacsAxis(masterMacsController *pController, int axisNo); masterMacsAxis(masterMacsController *pController, int axisNo);
/**
* @brief Delete the copy and copy assignment constructors, because this
* class should not be copied (it is tied to hardware!)
*/
masterMacsAxis(const masterMacsAxis &) = delete;
masterMacsAxis &operator=(const masterMacsAxis &) = delete;
/** /**
* @brief Destroy the masterMacsAxis * @brief Destroy the masterMacsAxis
* *
@@ -50,13 +57,13 @@ class HIDDEN masterMacsAxis : public sinqAxis {
* *
* @param position * @param position
* @param relative * @param relative
* @param min_velocity * @param minVelocity
* @param max_velocity * @param maxVelocity
* @param acceleration * @param acceleration
* @return asynStatus * @return asynStatus
*/ */
asynStatus doMove(double position, int relative, double min_velocity, asynStatus doMove(double position, int relative, double minVelocity,
double max_velocity, double acceleration); double maxVelocity, double acceleration);
/** /**
* @brief Implementation of the `stop` function from asynMotorAxis * @brief Implementation of the `stop` function from asynMotorAxis
@@ -141,163 +148,191 @@ class HIDDEN masterMacsAxis : public sinqAxis {
/** /**
* @brief Read the Master MACS status with the xR10 command and store * @brief Read the Master MACS status with the xR10 command and store
* the result in axisStatus_ * the result in axisStatus (see masterMacsAxisImpl redefinition in
* masterMacsAxis.cpp)
* *
*/ */
asynStatus readAxisStatus(); asynStatus readAxisStatus();
/* /*
The functions below read the specified status bit from the axisStatus The functions below read the specified status bit from the axisStatus (see
bitset. Since a bit can either be 0 or 1, the return value is given as a masterMacsAxisImpl redefinition in masterMacsAxis.cpp) bitset. Since a bit
boolean. can either be 0 or 1, the return value is given as a boolean.
*/ */
/** /**
* @brief Read the property from axisStatus_ * @brief Read the property from axisStatus (see masterMacsAxisImpl
* redefinition in masterMacsAxis.cpp)
*/ */
bool readyToBeSwitchedOn(); bool readyToBeSwitchedOn();
/** /**
* @brief Read the property from axisStatus_ * @brief Read the property from axisStatus (see masterMacsAxisImpl
* redefinition in masterMacsAxis.cpp)
*/ */
bool switchedOn(); bool switchedOn();
// Bit 2 is unused // Bit 2 is unused
/** /**
* @brief Read the property from axisStatus_ * @brief Read the property from axisStatus (see masterMacsAxisImpl
* redefinition in masterMacsAxis.cpp)
*/ */
bool faultConditionSet(); bool faultConditionSet();
/** /**
* @brief Read the property from axisStatus_ * @brief Read the property from axisStatus (see masterMacsAxisImpl
* redefinition in masterMacsAxis.cpp)
*/ */
bool voltagePresent(); bool voltagePresent();
/** /**
* @brief Read the property from axisStatus_ * @brief Read the property from axisStatus (see masterMacsAxisImpl
* redefinition in masterMacsAxis.cpp)
*/ */
bool quickStopping(); bool quickStopping();
/** /**
* @brief Read the property from axisStatus_ * @brief Read the property from axisStatus (see masterMacsAxisImpl
* redefinition in masterMacsAxis.cpp)
*/ */
bool switchOnDisabled(); bool switchOnDisabled();
/** /**
* @brief Read the property from axisStatus_ * @brief Read the property from axisStatus (see masterMacsAxisImpl
* redefinition in masterMacsAxis.cpp)
*/ */
bool warning(); bool warning();
// Bit 8 is unused // Bit 8 is unused
/** /**
* @brief Read the property from axisStatus_ * @brief Read the property from axisStatus (see masterMacsAxisImpl
* redefinition in masterMacsAxis.cpp)
*/ */
bool remoteMode(); bool remoteMode();
/** /**
* @brief Read the property from axisStatus_ * @brief Read the property from axisStatus (see masterMacsAxisImpl
* redefinition in masterMacsAxis.cpp)
*/ */
bool targetReached(); bool targetReached();
/** /**
* @brief Read the property from axisStatus_ * @brief Read the property from axisStatus (see masterMacsAxisImpl
* redefinition in masterMacsAxis.cpp)
*/ */
bool internalLimitActive(); bool internalLimitActive();
// Bits 12 and 13 are unused // Bits 12 and 13 are unused
/** /**
* @brief Read the property from axisStatus_ * @brief Read the property from axisStatus (see masterMacsAxisImpl
* redefinition in masterMacsAxis.cpp)
*/ */
bool setEventHasOcurred(); bool setEventHasOcurred();
/** /**
* @brief Read the property from axisStatus_ * @brief Read the property from axisStatus (see masterMacsAxisImpl
* redefinition in masterMacsAxis.cpp)
*/ */
bool powerEnabled(); bool powerEnabled();
/** /**
* @brief Read the Master MACS status with the xR10 command and store * @brief Read the Master MACS error with the xR10 command and store
* the result in axisStatus_ * the result in axisError (see masterMacsAxisImpl redefinition in
* masterMacsAxis.cpp)
* *
*/ */
asynStatus readAxisError(); asynStatus readAxisError();
/* /*
The functions below read the specified error bit from the axisError_ The functions below read the specified error bit from the axisError (see
bitset. Since a bit can either be 0 or 1, the return value is given as a masterMacsAxisImpl redefinition in masterMacsAxis.cpp) bitset. Since a bit
boolean. can either be 0 or 1, the return value is given as a boolean.
*/ */
/** /**
* @brief Read the property from axisError_ * @brief Read the property from axisError (see masterMacsAxisImpl
* redefinition in masterMacsAxis.cpp)
*/ */
bool shortCircuit(); bool shortCircuit();
/** /**
* @brief Read the property from axisError_ * @brief Read the property from axisError (see masterMacsAxisImpl
* redefinition in masterMacsAxis.cpp)
*/ */
bool encoderError(); bool encoderError();
/** /**
* @brief Read the property from axisError_ * @brief Read the property from axisError (see masterMacsAxisImpl
* redefinition in masterMacsAxis.cpp)
*/ */
bool followingError(); bool followingError();
/** /**
* @brief Read the property from axisError_ * @brief Read the property from axisError (see masterMacsAxisImpl
* redefinition in masterMacsAxis.cpp)
*/ */
bool communicationError(); bool communicationError();
/** /**
* @brief Read the property from axisError_ * @brief Read the property from axisError (see masterMacsAxisImpl
* redefinition in masterMacsAxis.cpp)
*/ */
bool feedbackError(); bool feedbackError();
/** /**
* @brief Read the property from axisError_ * @brief Read the property from axisError (see masterMacsAxisImpl
* redefinition in masterMacsAxis.cpp)
*/ */
bool positiveLimitSwitch(); bool positiveLimitSwitch();
/** /**
* @brief Read the property from axisError_ * @brief Read the property from axisError (see masterMacsAxisImpl
* redefinition in masterMacsAxis.cpp)
*/ */
bool negativeLimitSwitch(); bool negativeLimitSwitch();
/** /**
* @brief Read the property from axisError_ * @brief Read the property from axisError (see masterMacsAxisImpl
* redefinition in masterMacsAxis.cpp)
*/ */
bool positiveSoftwareLimit(); bool positiveSoftwareLimit();
/** /**
* @brief Read the property from axisError_ * @brief Read the property from axisError (see masterMacsAxisImpl
* redefinition in masterMacsAxis.cpp)
*/ */
bool negativeSoftwareLimit(); bool negativeSoftwareLimit();
/** /**
* @brief Read the property from axisError_ * @brief Read the property from axisError (see masterMacsAxisImpl
* redefinition in masterMacsAxis.cpp)
*/ */
bool overCurrent(); bool overCurrent();
/** /**
* @brief Read the property from axisError_ * @brief Read the property from axisError (see masterMacsAxisImpl
* redefinition in masterMacsAxis.cpp)
*/ */
bool overTemperature(); bool overTemperature();
/** /**
* @brief Read the property from axisError_ * @brief Read the property from axisError (see masterMacsAxisImpl
* redefinition in masterMacsAxis.cpp)
*/ */
bool overVoltage(); bool overVoltage();
/** /**
* @brief Read the property from axisError_ * @brief Read the property from axisError (see masterMacsAxisImpl
* redefinition in masterMacsAxis.cpp)
*/ */
bool underVoltage(); bool underVoltage();
/** /**
* @brief Read the property from axisError_ * @brief Read the property from axisError (see masterMacsAxisImpl
* redefinition in masterMacsAxis.cpp)
*/ */
bool stoFault(); bool stoFault();

View File

@@ -12,6 +12,28 @@
#include <string> #include <string>
#include <unistd.h> #include <unistd.h>
/*
These functions are used to read out the compiler flags defining the major and
minor versions. See README.md, section "Firmware version checking" for
details. If these flags are not given, a default value of -1 is used, which
disables the version checks (it suffices to have one of these at -1 to disable
both major and minor version check)
*/
constexpr int firmware_major_version() {
#ifdef FIRMWARE_MAJOR_VERSION
return FIRMWARE_MAJOR_VERSION;
#else
return -1;
#endif
}
constexpr int firmware_minor_version() {
#ifdef FIRMWARE_MINOR_VERSION
return FIRMWARE_MINOR_VERSION;
#else
return -1;
#endif
}
struct masterMacsControllerImpl { struct masterMacsControllerImpl {
double comTimeout; double comTimeout;
@@ -59,17 +81,18 @@ masterMacsController::masterMacsController(const char *portName,
: sinqController(portName, ipPortConfigName, numAxes, movingPollPeriod, : sinqController(portName, ipPortConfigName, numAxes, movingPollPeriod,
idlePollPeriod, idlePollPeriod,
// No additional parameter library entries // No additional parameter library entries
0) 0),
pMasterMacsC_(
std::make_unique<masterMacsControllerImpl>((masterMacsControllerImpl){
.comTimeout = comTimeout,
.nodeReset = 0, // Overwritten later
}))
{ {
// Initialization of local variables // Initialization of local variables
asynStatus status = asynSuccess; asynStatus status = asynSuccess;
char response[MAXBUF_] = {0};
pMasterMacsC_ =
std::make_unique<masterMacsControllerImpl>((masterMacsControllerImpl){
.comTimeout = comTimeout,
});
// ========================================================================= // =========================================================================
// Create additional parameter library entries // Create additional parameter library entries
@@ -116,6 +139,60 @@ masterMacsController::masterMacsController(const char *portName,
pasynOctetSyncIO->disconnect(pasynOctetSyncIOipPort()); pasynOctetSyncIO->disconnect(pasynOctetSyncIOipPort());
exit(-1); exit(-1);
} }
// =========================================================================
if (firmware_major_version() >= 0 && firmware_minor_version() >= 0) {
// Check the firmware version according to the conditions outlined in
// README.md
status = read(0, 99, response);
if (status == asynSuccess) {
// Just interpret the version if the variable already exists
double versionRaw = 0.0;
int nvals = sscanf(response, "%lf", &versionRaw);
if (nvals == 1 && versionRaw != 0.0) {
// Discard decimal part
long long versionInt = (long long)versionRaw;
// Extract bugfix (last 3 digits)
// Currently not used, just here for completions sake
// int bugfix = versionInt % 1000;
versionInt /= 1000;
// Extract minor (next 3 digits)
int minor = versionInt % 1000;
versionInt /= 1000;
// Remaining is major
int major = (int)versionInt;
// Compare to target values
if (firmware_major_version() != major ||
firmware_minor_version() > minor) {
asynPrint(this->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\" => %s, line %d\nFATAL ERROR "
"(Incorrect "
"version number of firmware: Expected major "
"version equal "
"to %d, got %d. Expected minor version equal to "
"or larger "
"than %d, got %d).\nTerminating IOC",
portName, __PRETTY_FUNCTION__, __LINE__,
firmware_major_version(), major,
firmware_minor_version(), minor);
exit(-1);
}
}
} else {
asynPrint(
this->pasynUser(), ASYN_TRACE_ERROR,
"Controller \"%s\" => %s, line %d\nCould not read firmware "
"version\n",
portName, __PRETTY_FUNCTION__, __LINE__);
}
}
} }
/* /*
@@ -154,7 +231,7 @@ asynStatus masterMacsController::writeInt32(asynUser *pasynUser,
} }
asynStatus masterMacsController::read(int axisNo, int tcpCmd, char *response, asynStatus masterMacsController::read(int axisNo, int tcpCmd, char *response,
double comTimeout) { double /*comTimeout*/) {
return writeRead(axisNo, tcpCmd, NULL, response); return writeRead(axisNo, tcpCmd, NULL, response);
} }
@@ -199,12 +276,6 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
comTimeout = pMasterMacsC_->comTimeout; comTimeout = pMasterMacsC_->comTimeout;
} }
masterMacsAxis *axis = getMasterMacsAxis(axisNo);
if (axis == nullptr) {
// We already did the error logging directly in getAxis
return asynError;
}
// Build the full command depending on the inputs to this function // 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);
@@ -286,32 +357,39 @@ 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 (axisNo != 0) {
setAxisParamChecked(axis, motorStatusCommsError, false); masterMacsAxis *axis = getMasterMacsAxis(axisNo);
} else { if (axis == nullptr) {
// We already did the error logging directly in getAxis
return asynError;
}
/* if (status == asynSuccess) {
Since the communication failed, there is the possibility that the
controller is not connected at all to the network. In that case, we
cannot be sure that the information read out in the init method of the
axis is still up-to-date the next time we get a connection. Therefore,
an info flag is set which the axis object can use at the start of its
poll method to try to initialize itself.
*/
axis->setNeedInit(true);
/*
Check if the axis already is in an error communication mode. If
it is not, upstream the error. This is done to avoid "flooding"
the user with different error messages if more than one error
ocurred before an error-free communication
*/
getAxisParamChecked(axis, motorStatusProblem, &motorStatusProblem);
if (motorStatusProblem == 0) {
setAxisParamChecked(axis, motorMessageText, drvMessageText);
setAxisParamChecked(axis, motorStatusProblem, true);
setAxisParamChecked(axis, motorStatusCommsError, false); setAxisParamChecked(axis, motorStatusCommsError, false);
} else {
/*
Since the communication failed, there is the possibility that the
controller is not connected at all to the network. In that case, we
cannot be sure that the information read out in the init method of
the axis is still up-to-date the next time we get a connection.
Therefore, an info flag is set which the axis object can use at the
start of its poll method to try to initialize itself.
*/
axis->setNeedInit(true);
/*
Check if the axis already is in an error communication mode. If
it is not, upstream the error. This is done to avoid "flooding"
the user with different error messages if more than one error
ocurred before an error-free communication
*/
getAxisParamChecked(axis, motorStatusProblem, &motorStatusProblem);
if (motorStatusProblem == 0) {
setAxisParamChecked(axis, motorMessageText, drvMessageText);
setAxisParamChecked(axis, motorStatusProblem, true);
setAxisParamChecked(axis, motorStatusCommsError, false);
}
} }
} }
@@ -334,7 +412,7 @@ asynStatus masterMacsController::parseResponse(
bool responseValid = false; bool responseValid = false;
int responseStart = 0; int responseStart = 0;
asynStatus status = asynSuccess; asynStatus status = asynSuccess;
int prevConnected = 0; int prevConnected = 1;
char printableCommand[MAXBUF_] = {0}; char printableCommand[MAXBUF_] = {0};
char printableResponse[MAXBUF_] = {0}; char printableResponse[MAXBUF_] = {0};
@@ -342,12 +420,14 @@ asynStatus masterMacsController::parseResponse(
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__); msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
masterMacsAxis *axis = getMasterMacsAxis(axisNo); masterMacsAxis *axis = getMasterMacsAxis(axisNo);
if (axis == nullptr) { if (axisNo != 0 && axis == nullptr) {
return asynError; return asynError;
} }
// Was the motor previously connected? // Was the motor previously connected?
getAxisParamChecked(axis, motorConnected, &prevConnected); if (axis != nullptr) {
getAxisParamChecked(axis, motorConnected, &prevConnected);
}
// 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.
@@ -371,14 +451,17 @@ asynStatus masterMacsController::parseResponse(
"connected.\n", "connected.\n",
portName, axisNo, __PRETTY_FUNCTION__, __LINE__); portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
setAxisParamChecked(axis, motorConnected, true); if (axis != nullptr) {
status = callParamCallbacks(); setAxisParamChecked(axis, motorConnected, true);
if (status != asynSuccess) { status = callParamCallbacks();
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, if (status != asynSuccess) {
"Controller \"%s\", axis %d => %s, line " asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"%d:\nCould not update parameter library\n", "Controller \"%s\", axis %d => %s, line "
portName, axisNo, __PRETTY_FUNCTION__, __LINE__); "%d:\nCould not update parameter library\n",
return status; portName, axisNo, __PRETTY_FUNCTION__,
__LINE__);
return status;
}
} }
} }
@@ -399,14 +482,17 @@ asynStatus masterMacsController::parseResponse(
"disconnected.\n", "disconnected.\n",
portName, axisNo, __PRETTY_FUNCTION__, __LINE__); portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
setAxisParamChecked(axis, motorConnected, false); if (axis != nullptr) {
status = callParamCallbacks(); setAxisParamChecked(axis, motorConnected, false);
if (status != asynSuccess) { status = callParamCallbacks();
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, if (status != asynSuccess) {
"Controller \"%s\", axis %d => %s, line " asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"%d:\nCould not update parameter library\n", "Controller \"%s\", axis %d => %s, line "
portName, axisNo, __PRETTY_FUNCTION__, __LINE__); "%d:\nCould not update parameter library\n",
return status; portName, axisNo, __PRETTY_FUNCTION__,
__LINE__);
return status;
}
} }
} }
break; break;
@@ -553,7 +639,8 @@ static const iocshArg *const CreateControllerArgs[] = {
&CreateControllerArg0, &CreateControllerArg1, &CreateControllerArg2, &CreateControllerArg0, &CreateControllerArg1, &CreateControllerArg2,
&CreateControllerArg3, &CreateControllerArg4, &CreateControllerArg5}; &CreateControllerArg3, &CreateControllerArg4, &CreateControllerArg5};
static const iocshFuncDef configMasterMacsCreateController = { static const iocshFuncDef configMasterMacsCreateController = {
"masterMacsController", 6, CreateControllerArgs}; "masterMacsController", 6, CreateControllerArgs,
"Create a new instance of a MasterMACS controller."};
static void configMasterMacsCreateControllerCallFunc(const iocshArgBuf *args) { static void configMasterMacsCreateControllerCallFunc(const iocshArgBuf *args) {
masterMacsCreateController(args[0].sval, args[1].sval, args[2].ival, masterMacsCreateController(args[0].sval, args[1].sval, args[2].ival,
args[3].dval, args[4].dval, args[5].dval); args[3].dval, args[4].dval, args[5].dval);

View File

@@ -38,6 +38,13 @@ class HIDDEN masterMacsController : public sinqController {
int numAxes, double movingPollPeriod, int numAxes, double movingPollPeriod,
double idlePollPeriod, double comTimeout); double idlePollPeriod, double comTimeout);
/**
* @brief Delete the copy and copy assignment constructors, because this
* class should not be copied (it is tied to hardware!)
*/
masterMacsController(const masterMacsController &) = delete;
masterMacsController &operator=(const masterMacsController &) = delete;
/** /**
* @brief Overloaded version of the sinqController version * @brief Overloaded version of the sinqController version
* *

View File

@@ -9,73 +9,82 @@ To read the manual, simply run this script without any arguments.
Stefan Mathis, January 2025 Stefan Mathis, January 2025
""" """
import platform
from decodeCommon import interactive, decode, print_decoded from decodeCommon import interactive, decode, print_decoded
# List of tuples which encodes the states given in the file description. # List of tuples which encodes the states given in the file description.
# Index first with the bit index, then with the bit value # Index first with the bit index, then with the bit value
interpretation = [ interpretation = [
("Not specified", "Not specified"), # Bit 0 ("Not specified", "Not specified"), # Bit 0
("Ok", "Short circuit"), # Bit 1 ("Ok", "Short circuit"), # Bit 1
("Ok", "Encoder error"), # Bit 2 ("Ok", "Encoder error"), # Bit 2
("Ok", "Following error"), # Bit 3 ("Ok", "Following error"), # Bit 3
("Ok", "Communication error"), # Bit 4 ("Ok", "Communication error"), # Bit 4
("Ok", "Feedback error"), # Bit 5 ("Ok", "Feedback error"), # Bit 5
("Ok", "Positive limit switch hit"), # Bit 6 ("Ok", "Positive limit switch hit"), # Bit 6
("Ok", "Negative limit switch hit"), # Bit 7 ("Ok", "Negative limit switch hit"), # Bit 7
("Ok", "Positive software limit hit"), # Bit 8 ("Ok", "Positive software limit hit"), # Bit 8
("Ok", "Negative software limit hit"), # Bit 9 ("Ok", "Negative software limit hit"), # Bit 9
("Ok", "Over-current"), # Bit 10 ("Ok", "Over-current"), # Bit 10
("Ok", "Over-temperature drive"), # Bit 11 ("Ok", "Over-temperature drive"), # Bit 11
("Ok", "Over-voltage"), # Bit 12 ("Ok", "Over-voltage"), # Bit 12
("Ok", "Under-voltage"), # Bit 13 ("Ok", "Under-voltage"), # Bit 13
("Not specified", "Not specified"), # Bit 14 ("Not specified", "Not specified"), # Bit 14
("Ok", "STO fault (STO input is on disable state)"), # Bit 15 ("Ok", "STO fault (STO input is on disable state)"), # Bit 15
] ]
help = """
Decode R11 message of MasterMACs
------------------
MasterMACs returns its error message (R11) 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: decodeError.py value
'value' is the return value of a R11 command. This value is interpreted
bit-wise and the result is printed out.
Option 2: CLI Mode (Linux-only)
-------------------------------
Usage: decodeError.py
ONLY AVAILABLE ON LINUX!
A prompt will be opened. Type in the return value of a R11 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.
"""
if __name__ == "__main__": if __name__ == "__main__":
from sys import argv from sys import argv
if "-h" or "--help" in argv:
print(help)
if len(argv) == 1: if len(argv) == 1:
# Start interactive mode # Start interactive mode
interactive() if platform.system() == "Linux":
interactive()
else:
print(help)
else: else:
number = None number = None
try: try:
number = int(float(argv[1])) number = int(float(argv[1]))
except: except:
print(""" print(help)
Decode R11 message of MasterMACs
------------------
MasterMACs returns its error message (R11) 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: decodeError.py value
'value' is the return value of a R11 command. This value is interpreted
bit-wise and the result is printed out.
Option 2: CLI Mode
------------------
Usage: decodeError.py
A prompt will be opened. Type in the return value of a R11 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.
""")
if number is not None: if number is not None:
print("Motor error") print("Motor error")
print("============") print("===========")
(bit_list, interpreted) = decode(number, interpretation) (bit_list, interpreted) = decode(number, interpretation)
print_decoded(bit_list, interpreted) print_decoded(bit_list, interpreted)

View File

@@ -9,71 +9,81 @@ To read the manual, simply run this script without any arguments.
Stefan Mathis, December 2024 Stefan Mathis, December 2024
""" """
import platform
from decodeCommon import interactive, decode, print_decoded from decodeCommon import interactive, decode, print_decoded
# List of tuples which encodes the states given in the file description. # List of tuples which encodes the states given in the file description.
# Index first with the bit index, then with the bit value # Index first with the bit index, then with the bit value
interpretation = [ interpretation = [
("Not ready to be switched on", "Ready to be switched on"), # Bit 0 ("Not ready to be switched on", "Ready to be switched on"), # Bit 0
("Not switched on", "Switched on"), # Bit 1 ("Not switched on", "Switched on"), # Bit 1
("Disabled", "Enabled"), # Bit 2 ("Disabled", "Enabled"), # Bit 2
("Ok", "Fault condition set"), # Bit 3 ("Ok", "Fault condition set"), # Bit 3
("Motor supply voltage absent ", "Motor supply voltage present"), # Bit 4 ("Motor supply voltage absent ", "Motor supply voltage present"), # Bit 4
("Motor performs quick stop", "Ok"), # Bit 5 ("Motor performs quick stop", "Ok"), # Bit 5
("Switch on enabled", "Switch on disabled"), # Bit 6 ("Switch on enabled", "Switch on disabled"), # Bit 6
("Ok", "Warning: Movement function was called while motor is still moving. The function call is ignored"), # Bit 7 ("Ok", "Warning: Movement function was called while motor is still moving. The function call is ignored"), # Bit 7
("Not specified", "Not specified"), # Bit 8 ("Not specified", "Not specified"), # Bit 8
("Motor does not execute command messages (local mode)", "Motor does execute command messages (remote mode)"), # Bit 9 ("Motor does not execute command messages (local mode)",
("Target not reached", "Target reached"), # Bit 10 "Motor does execute command messages (remote mode)"), # Bit 9
("Ok", "Internal limit active (current, voltage, velocity or position)"), # Bit 11 ("Target not reached", "Target reached"), # Bit 10
("Not specified", "Not specified"), # Bit 12 ("Ok", "Internal limit active (current, voltage, velocity or position)"), # Bit 11
("Not specified", "Not specified"), # Bit 13 ("Not specified", "Not specified"), # Bit 12
("Not specified", "Not specified"), # Bit 14 ("Not specified", "Not specified"), # Bit 13
("Not specified", "Not specified"), # Bit 15 ("Not specified", "Not specified"), # Bit 14
("Not specified", "Not specified"), # Bit 15
] ]
help = """
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: decodeStatus.py value
'value' is the return value of a R10 command. This value is interpreted
bit-wise and the result is printed out.
Option 2: CLI Mode (Linux-only)
-------------------------------
Usage: decodeStatus.py
ONLY AVAILABLE ON LINUX!
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.
"""
if __name__ == "__main__": if __name__ == "__main__":
from sys import argv from sys import argv
if "-h" or "--help" in argv:
print(help)
if len(argv) == 1: if len(argv) == 1:
# Start interactive mode # Start interactive mode
interactive() if platform.system() == "Linux":
interactive()
else:
print(help)
else: else:
number = None number = None
try: try:
number = int(float(argv[1])) number = int(float(argv[1]))
except: except:
print(""" print(help)
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: decodeStatus.py value
'value' is the return value of a R10 command. This value is interpreted
bit-wise and the result is printed out.
Option 2: CLI Mode
------------------
Usage: decodeStatus.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.
""")
if number is not None: if number is not None:
print("Motor status") print("Motor status")
print("============") print("============")

View File

@@ -6,51 +6,72 @@ To read the manual, simply run this script without any arguments.
Stefan Mathis, April 2025 Stefan Mathis, April 2025
""" """
import platform
import struct import struct
import socket import socket
import curses
help = """
Send commands to and receive replies from MasterMACS controllers
Option 1: Single Command
------------------------
Usage: writeRead.py pmachost:port command
This then returns the response for command.
Option 2: CLI Mode (Linux-only)
-------------------------------
Usage: writeRead.py pmachost:port
ONLY AVAILABLE ON LINUX!
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.
"""
def packMasterMacsCommand(command): def packMasterMacsCommand(command):
# 0x0D = Carriage return # 0x0D = Carriage return
buf = struct.pack('B',0x0D) buf = struct.pack('B', 0x0D)
buf = bytes(command,'utf-8') + buf buf = bytes(command, 'utf-8') + buf
return bytes(command,'utf-8') return bytes(command, 'utf-8')
def readMasterMacsReply(input): def readMasterMacsReply(input):
msg = bytearray() msg = bytearray()
expectAck = True expectAck = True
while True: while True:
b = input.recv(1) b = input.recv(1)
bint = int.from_bytes(b,byteorder='little') bint = int.from_bytes(b, byteorder='little')
if bint == 2 or bint == 7: #STX or BELL if bint == 2 or bint == 7: # STX or BELL
expectAck = False expectAck = False
continue continue
if expectAck and bint == 6: # ACK if expectAck and bint == 6: # ACK
return bytes(msg) return bytes(msg)
else: else:
if bint == 13 and not expectAck: # CR if bint == 13 and not expectAck: # CR
return bytes(msg) return bytes(msg)
else: else:
msg.append(bint) msg.append(bint)
if __name__ == "__main__": if __name__ == "__main__":
from sys import argv from sys import argv
try: if "-h" or "--help" in argv:
print(help)
else:
addr = argv[1].split(':') addr = argv[1].split(':')
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((addr[0],int(addr[1]))) s.connect((addr[0], int(addr[1])))
if len(argv) == 3: if len(argv) == 2:
buf = packMasterMacsCommand(argv[2])
s.send(buf)
reply = readMasterMacsReply(s)
print(reply.decode('utf-8') + '\n')
else: if platform.system() == "Linux":
import curses
try:
stdscr = curses.initscr() stdscr = curses.initscr()
curses.noecho() curses.noecho()
@@ -80,13 +101,13 @@ if __name__ == "__main__":
if ptr > 0: if ptr > 0:
ptr -= 1 ptr -= 1
stdscr.addch("\r") stdscr.addch("\r")
stdscr.clrtoeol() stdscr.clrtoeol()
stdscr.addstr(">> " + history[ptr]) stdscr.addstr(">> " + history[ptr])
elif c == curses.KEY_DOWN: elif c == curses.KEY_DOWN:
if ptr < len(history) - 1: if ptr < len(history) - 1:
ptr += 1 ptr += 1
stdscr.addch("\r") stdscr.addch("\r")
stdscr.clrtoeol() stdscr.clrtoeol()
stdscr.addstr(">> " + history[ptr]) stdscr.addstr(">> " + history[ptr])
elif c == curses.KEY_ENTER or c == ord('\n') or c == ord('\r'): elif c == curses.KEY_ENTER or c == ord('\n') or c == ord('\r'):
if history[ptr] == 'quit': if history[ptr] == 'quit':
@@ -112,7 +133,7 @@ if __name__ == "__main__":
stdscr.refresh() stdscr.refresh()
else: else:
if ptr < len(history) - 1: # Modifying previous input if ptr < len(history) - 1: # Modifying previous input
if len(history[-1]) == 0: if len(history[-1]) == 0:
history[-1] = history[ptr] history[-1] = history[ptr]
ptr = len(history) - 1 ptr = len(history) - 1
@@ -125,47 +146,34 @@ if __name__ == "__main__":
if len(history[ptr]) == 0: if len(history[ptr]) == 0:
continue continue
(y, x) = stdscr.getyx() (y, x) = stdscr.getyx()
history[ptr] = history[ptr][0:x-4] + history[ptr][x-3:] history[ptr] = history[ptr][0:x-4] + \
history[ptr][x-3:]
stdscr.addch("\r") stdscr.addch("\r")
stdscr.clrtoeol() stdscr.clrtoeol()
stdscr.addstr(">> " + history[ptr]) stdscr.addstr(">> " + history[ptr])
stdscr.move(y, x-1) stdscr.move(y, x-1)
stdscr.refresh() stdscr.refresh()
else: else:
(y, x) = stdscr.getyx() (y, x) = stdscr.getyx()
history[ptr] = history[ptr][0:x-3] + chr(c) + history[ptr][x-3:] history[ptr] = history[ptr][0:x-3] + \
chr(c) + history[ptr][x-3:]
stdscr.addch("\r") stdscr.addch("\r")
stdscr.clrtoeol() stdscr.clrtoeol()
stdscr.addstr(">> " + history[ptr]) stdscr.addstr(">> " + history[ptr])
stdscr.move(y, x+1) stdscr.move(y, x+1)
stdscr.refresh() stdscr.refresh()
# to quit
finally: curses.nocbreak()
stdscr.keypad(False)
# to quit curses.echo()
curses.nocbreak() curses.endwin()
stdscr.keypad(False) else:
curses.echo() print(help)
curses.endwin() elif len(argv) == 3:
buf = packMasterMacsCommand(argv[2])
except: s.send(buf)
print(""" reply = readMasterMacsReply(s)
Invalid Arguments print(reply.decode('utf-8') + '\n')
else:
Option 1: Single Command print(help)
------------------------
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.
""")