Compare commits
52 Commits
static-dep
...
1.5.2
| Author | SHA1 | Date | |
|---|---|---|---|
| d834c8858e | |||
| 5314362c83 | |||
| 5efb94f83e | |||
| 7e7b8f486c | |||
| 6adca95ade | |||
| b4454a3ab6 | |||
| 73c96a73bf | |||
| e1732639b2 | |||
| 6f72766ae6 | |||
| a435c3c960 | |||
| f1c41d3081 | |||
| d78586a815 | |||
| ebcf99ac56 | |||
| de32298609 | |||
| 8f457889c0 | |||
| 6f63e521c1 | |||
| 670f01fbe3 | |||
| 25286652d5 | |||
| 27f7cc8602 | |||
| 21a73717a5 | |||
| 2cbb4f9028 | |||
| 23a911206a | |||
| 6553b468c8 | |||
| 954fc82414 | |||
| ff183576ec | |||
| 83f9be3be8 | |||
| 2c0c9a33b7 | |||
| 8bb81b1716 | |||
| c32708e49c | |||
| 14a733fb67 | |||
| 64b932c3ae | |||
| 09897b6125 | |||
| 9d47cd4e24 | |||
| 52fa4e1e78 | |||
| a9e08460d9 | |||
| 37dacbd3ee | |||
| d198dc8c9f | |||
| 13f2ec4fbf | |||
| 6ccb60f263 | |||
| b8730e80e0 | |||
| deb6e6996e | |||
| d1d694ad6b | |||
| e0a74c5598 | |||
| c334ed9f04 | |||
| 4b0031c3af | |||
| 61335970ce | |||
| 081a21073b | |||
| f2e8eb2762 | |||
| e93f11e779 | |||
| 989410474e | |||
| 8d8561d833 | |||
| a56a8cf646 |
24
.gitea/workflows/action.yaml
Normal file
24
.gitea/workflows/action.yaml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
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 src/*.cpp
|
||||||
|
- name: formatting
|
||||||
|
run: clang-format --style=file --Werror --dry-run src/*.cpp
|
||||||
|
Build:
|
||||||
|
runs-on: linepics
|
||||||
|
steps:
|
||||||
|
- name: checkout repo
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: 'true'
|
||||||
|
- run: |
|
||||||
|
sed -i 's/ARCH_FILTER=.*/ARCH_FILTER=linux%/' Makefile
|
||||||
|
echo -e "\nIGNORE_SUBMODULES += sinqmotor" >> Makefile
|
||||||
|
make install
|
||||||
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
O.*
|
||||||
|
.cvsignore
|
||||||
|
.vscode
|
||||||
|
utils/__pycache__
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
default:
|
|
||||||
image: docker.psi.ch:5000/sinqdev/sinqepics:latest
|
|
||||||
|
|
||||||
stages:
|
|
||||||
- lint
|
|
||||||
- build
|
|
||||||
- test
|
|
||||||
|
|
||||||
cppcheck:
|
|
||||||
stage: lint
|
|
||||||
script:
|
|
||||||
- cppcheck --std=c++17 --addon=cert --addon=misc --suppress=cert-STR07-C --error-exitcode=1 src/*.cpp
|
|
||||||
artifacts:
|
|
||||||
expire_in: 1 week
|
|
||||||
tags:
|
|
||||||
- sinq
|
|
||||||
|
|
||||||
formatting:
|
|
||||||
stage: lint
|
|
||||||
script:
|
|
||||||
- clang-format --style=file --Werror --dry-run src/*.cpp
|
|
||||||
artifacts:
|
|
||||||
expire_in: 1 week
|
|
||||||
tags:
|
|
||||||
- sinq
|
|
||||||
|
|
||||||
build_module:
|
|
||||||
stage: build
|
|
||||||
script:
|
|
||||||
- export SINQMOTOR_VERSION="$(grep 'sinqMotor_VERSION=' Makefile | cut -d= -f2)"
|
|
||||||
- git clone --depth 1 --branch "${SINQMOTOR_VERSION}" https://gitlab-ci-token:${CI_JOB_TOKEN}@git.psi.ch/sinq-epics-modules/sinqmotor.git
|
|
||||||
- pushd sinqmotor
|
|
||||||
- sed -i 's/ARCH_FILTER=.*/ARCH_FILTER=linux%/' Makefile
|
|
||||||
- echo "LIBVERSION=${SINQMOTOR_VERSION}" >> Makefile
|
|
||||||
- make install
|
|
||||||
- popd
|
|
||||||
- sed -i 's/ARCH_FILTER=.*/ARCH_FILTER=linux%/' Makefile
|
|
||||||
- echo "LIBVERSION=${CI_COMMIT_TAG:-0.0.1}" >> Makefile
|
|
||||||
- make install
|
|
||||||
- cp -rT "/ioc/modules/masterMacs/$(ls -U /ioc/modules/masterMacs/ | head -1)" "./masterMacs-${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}"
|
|
||||||
artifacts:
|
|
||||||
name: "masterMacs-${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}"
|
|
||||||
paths:
|
|
||||||
- "masterMacs-${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}/*"
|
|
||||||
expire_in: 1 week
|
|
||||||
when: always
|
|
||||||
tags:
|
|
||||||
- sinq
|
|
||||||
11
Makefile
11
Makefile
@@ -6,9 +6,6 @@ BUILDCLASSES=Linux
|
|||||||
EPICS_VERSIONS=7.0.7
|
EPICS_VERSIONS=7.0.7
|
||||||
ARCH_FILTER=RHEL%
|
ARCH_FILTER=RHEL%
|
||||||
|
|
||||||
# Additional module dependencies
|
|
||||||
REQUIRED+=sinqMotor
|
|
||||||
|
|
||||||
# Specify the version of asynMotor we want to build against
|
# Specify the version of asynMotor we want to build against
|
||||||
motorBase_VERSION=7.2.2
|
motorBase_VERSION=7.2.2
|
||||||
|
|
||||||
@@ -26,9 +23,15 @@ SOURCES += src/masterMacsController.cpp
|
|||||||
# Store the record files
|
# Store the record files
|
||||||
TEMPLATES += sinqMotor/db/asynRecord.db
|
TEMPLATES += sinqMotor/db/asynRecord.db
|
||||||
TEMPLATES += sinqMotor/db/sinqMotor.db
|
TEMPLATES += sinqMotor/db/sinqMotor.db
|
||||||
|
TEMPLATES += db/masterMacs.db
|
||||||
|
|
||||||
# This file registers the motor-specific functions in the IOC shell.
|
# This file registers the motor-specific functions in the IOC shell.
|
||||||
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 -Wpedantic -Wextra -Werror
|
USR_CFLAGS += -Wall -Wextra -Wunused-result -Wextra -Werror
|
||||||
|
USR_CXXFLAGS += -Wall -Wextra -Wunused-result
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|||||||
BIN
MasterMACS_manual.pdf
Normal file
BIN
MasterMACS_manual.pdf
Normal file
Binary file not shown.
73
README.md
73
README.md
@@ -17,23 +17,50 @@ 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:
|
||||||
|
|
||||||
### Usage in IOC shell
|
```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
|
||||||
|
|
||||||
masterMacs exposes the following IOC shell functions (all in masterMacsController.cpp):
|
# 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
|
||||||
|
```
|
||||||
|
|
||||||
|
### IOC startup script
|
||||||
|
|
||||||
|
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:
|
||||||
|
|
||||||
```
|
```bash
|
||||||
# Define the name of the controller and the corresponding port
|
# Define the name of the controller and the corresponding port
|
||||||
epicsEnvSet("NAME","mcu")
|
epicsEnvSet("NAME","mcu")
|
||||||
epicsEnvSet("ASYN_PORT","p$(NAME)")
|
epicsEnvSet("ASYN_PORT","p$(NAME)")
|
||||||
|
|
||||||
# Create the TCP/IP socket used to talk with the controller. The socket can be adressed from within the IOC shell via the port name
|
# Create the TCP/IP socket used to talk with the controller. The socket can be
|
||||||
drvAsynIPPortConfigure("$(ASYN_PORT)","172.28.101.24:1025")
|
# adressed from within the IOC shell via the port name
|
||||||
|
# We do not use the standard asyn port driver here, but a PMAC-specific one
|
||||||
|
# which enables the usage of StreamDevices for
|
||||||
|
# communicating with the controller directly.
|
||||||
|
masterMacsAsynIPPortConfigure("$(ASYN_PORT)","172.28.101.24:1025")
|
||||||
|
|
||||||
# Create the controller object with the defined name and connect it to the socket via the port name.
|
# Create the controller object with the defined name and connect it to the socket via the port name.
|
||||||
# The other parameters are as follows:
|
# The other parameters are as follows:
|
||||||
@@ -57,13 +84,43 @@ setThresholdComTimeout("$(NAME)", 100, 1);
|
|||||||
# Parametrize the EPICS record database with the substitution file named after the MCU.
|
# Parametrize the EPICS record database with the substitution file named after the MCU.
|
||||||
epicsEnvSet("SINQDBPATH","$(masterMacs_DB)/sinqMotor.db")
|
epicsEnvSet("SINQDBPATH","$(masterMacs_DB)/sinqMotor.db")
|
||||||
dbLoadTemplate("$(TOP)/$(NAME).substitutions", "INSTR=$(INSTR)$(NAME):,CONTROLLER=$(NAME)")
|
dbLoadTemplate("$(TOP)/$(NAME).substitutions", "INSTR=$(INSTR)$(NAME):,CONTROLLER=$(NAME)")
|
||||||
|
epicsEnvSet("SINQDBPATH","$(masterMacs_DB)/masterMacs.db")
|
||||||
|
dbLoadTemplate("$(TOP)/$(NAME).substitutions", "INSTR=$(INSTR)$(NAME):,CONTROLLER=$(NAME)")
|
||||||
dbLoadRecords("$(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
|
||||||
|
|
||||||
This driver can be compiled and installed by running `make install` from the same directory where the Makefile is located. However, since it uses the git submodule sinqMotor, make sure that the correct version of the submodule repository is checked out AND the change is commited (`git status` shows no non-committed changes). Please see the section "Usage as static dependency" in https://git.psi.ch/sinq-epics-modules/sinqmotor/-/blob/main/README.md for more details.
|
Please see the documentation for the module sinqMotor: https://git.psi.ch/sinq-epics-modules/sinqmotor/-/blob/main/README.md.
|
||||||
|
|||||||
17
db/masterMacs.db
Executable file
17
db/masterMacs.db
Executable file
@@ -0,0 +1,17 @@
|
|||||||
|
# Call the nodeReset function of the corresponding masterMacsAxis.
|
||||||
|
# This record is coupled to the parameter library via nodeReset_ -> NODE_RESET.
|
||||||
|
record(longout, "$(INSTR)$(M):NodeReset") {
|
||||||
|
field(DTYP, "asynInt32")
|
||||||
|
field(OUT, "@asyn($(CONTROLLER),$(AXIS),1) NODE_RESET")
|
||||||
|
field(PINI, "NO")
|
||||||
|
}
|
||||||
|
|
||||||
|
# Overrides the default value for the "Connected" record provided by sinqMotor.
|
||||||
|
record(longin, "$(INSTR)$(M):Connected")
|
||||||
|
{
|
||||||
|
field(DTYP, "asynInt32")
|
||||||
|
field(INP, "@asyn($(CONTROLLER),$(AXIS)) MOTOR_CONNECTED")
|
||||||
|
field(SCAN, "I/O Intr")
|
||||||
|
field(PINI, "NO")
|
||||||
|
field(VAL, "0")
|
||||||
|
}
|
||||||
Submodule sinqMotor updated: 5689402375...e234d05815
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,12 @@
|
|||||||
#ifndef masterMacsAXIS_H
|
#ifndef masterMacsAXIS_H
|
||||||
#define masterMacsAXIS_H
|
#define masterMacsAXIS_H
|
||||||
|
#include "masterMacsController.h"
|
||||||
#include "sinqAxis.h"
|
#include "sinqAxis.h"
|
||||||
#include <bitset>
|
#include <memory>
|
||||||
|
|
||||||
// Forward declaration of the controller class to resolve the cyclic dependency
|
struct HIDDEN masterMacsAxisImpl;
|
||||||
// between the controller and the axis .h-file. See
|
|
||||||
// https://en.cppreference.com/w/cpp/language/class.
|
|
||||||
class masterMacsController;
|
|
||||||
|
|
||||||
class masterMacsAxis : public sinqAxis {
|
class HIDDEN masterMacsAxis : public sinqAxis {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Construct a new masterMacsAxis
|
* @brief Construct a new masterMacsAxis
|
||||||
@@ -18,6 +16,13 @@ class 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
|
||||||
*
|
*
|
||||||
@@ -52,13 +57,13 @@ class 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
|
||||||
@@ -77,12 +82,27 @@ class masterMacsAxis : public sinqAxis {
|
|||||||
*/
|
*/
|
||||||
asynStatus doReset();
|
asynStatus doReset();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Performs a "node reset" on the axis as defined in the CANopen
|
||||||
|
* standard
|
||||||
|
*
|
||||||
|
* A "node reset" is a factory reset on the axis which completely deletes
|
||||||
|
* all configured information (e.g. limits or speed) from the axis. The
|
||||||
|
* MasterMACS controller then reapplies the initial configuration to this
|
||||||
|
* axis. It can therefore be seen as a "hard" version of the normal error
|
||||||
|
* reset performed by the `doReset` method.
|
||||||
|
*
|
||||||
|
* @return asynStatus
|
||||||
|
*/
|
||||||
|
asynStatus nodeReset();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Readout of some values from the controller at IOC startup
|
* @brief Readout of some values from the controller at IOC startup
|
||||||
*
|
*
|
||||||
* The following steps are performed:
|
* The following steps are performed:
|
||||||
* - Read out the motor status, motor position, velocity and acceleration
|
* - Read out the motor status, motor position, velocity and
|
||||||
* from the MCU and store this information in the parameter library.
|
* acceleration from the MCU and store this information in the parameter
|
||||||
|
* library.
|
||||||
* - Set the enable PV accordint to the initial status of the axis.
|
* - Set the enable PV accordint to the initial status of the axis.
|
||||||
*
|
*
|
||||||
* @return asynStatus
|
* @return asynStatus
|
||||||
@@ -98,191 +118,227 @@ class masterMacsAxis : public sinqAxis {
|
|||||||
asynStatus enable(bool on);
|
asynStatus enable(bool on);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the encoder type (incremental or absolute) for this axis from
|
* @brief Read the encoder type (incremental or absolute) for this axis
|
||||||
* the MCU and store the information in the PV ENCODER_TYPE.
|
* from the MCU and store the information in the PV ENCODER_TYPE.
|
||||||
*
|
*
|
||||||
* @return asynStatus
|
* @return asynStatus
|
||||||
*/
|
*/
|
||||||
asynStatus readEncoderType();
|
asynStatus readEncoderType();
|
||||||
|
|
||||||
protected:
|
/**
|
||||||
masterMacsController *pC_;
|
* @brief Check if the axis needs to run its initialization function
|
||||||
double lastSetSpeed_;
|
*
|
||||||
bool waitForHandshake_;
|
* @return true
|
||||||
time_t timeAtHandshake_;
|
* @return false
|
||||||
|
|
||||||
bool targetReachedUninitialized_;
|
|
||||||
|
|
||||||
asynStatus readConfig();
|
|
||||||
|
|
||||||
/*
|
|
||||||
The axis status and axis error of MasterMACS are given as an integer from
|
|
||||||
the controller. The 16 individual bits contain the actual information.
|
|
||||||
*/
|
*/
|
||||||
std::bitset<16> axisStatus_;
|
bool needInit();
|
||||||
std::bitset<16> axisError_;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the Master MACS status with the xR10 command and store the
|
* @brief Instruct the axis to run its init() function during the next
|
||||||
* result in axisStatus_
|
* poll
|
||||||
|
*
|
||||||
|
* @param needInit
|
||||||
|
*/
|
||||||
|
void setNeedInit(bool needInit);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return a pointer to the axis controller
|
||||||
|
*/
|
||||||
|
virtual masterMacsController *pController() override { return pC_; };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read the Master MACS status with the xR10 command and store
|
||||||
|
* 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() { return axisStatus_[0]; }
|
bool readyToBeSwitchedOn();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the property from axisStatus_
|
* @brief Read the property from axisStatus (see masterMacsAxisImpl
|
||||||
|
* redefinition in masterMacsAxis.cpp)
|
||||||
*/
|
*/
|
||||||
bool switchedOn() { return axisStatus_[1]; }
|
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() { return axisStatus_[3]; }
|
bool faultConditionSet();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the property from axisStatus_
|
* @brief Read the property from axisStatus (see masterMacsAxisImpl
|
||||||
|
* redefinition in masterMacsAxis.cpp)
|
||||||
*/
|
*/
|
||||||
bool voltagePresent() { return axisStatus_[4]; }
|
bool voltagePresent();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the property from axisStatus_
|
* @brief Read the property from axisStatus (see masterMacsAxisImpl
|
||||||
|
* redefinition in masterMacsAxis.cpp)
|
||||||
*/
|
*/
|
||||||
bool quickStopping() { return axisStatus_[5] == 0; }
|
bool quickStopping();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the property from axisStatus_
|
* @brief Read the property from axisStatus (see masterMacsAxisImpl
|
||||||
|
* redefinition in masterMacsAxis.cpp)
|
||||||
*/
|
*/
|
||||||
bool switchOnDisabled() { return axisStatus_[6]; }
|
bool switchOnDisabled();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the property from axisStatus_
|
* @brief Read the property from axisStatus (see masterMacsAxisImpl
|
||||||
|
* redefinition in masterMacsAxis.cpp)
|
||||||
*/
|
*/
|
||||||
bool warning() { return axisStatus_[7]; }
|
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() { return axisStatus_[9]; }
|
bool remoteMode();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the property from axisStatus_
|
* @brief Read the property from axisStatus (see masterMacsAxisImpl
|
||||||
|
* redefinition in masterMacsAxis.cpp)
|
||||||
*/
|
*/
|
||||||
bool targetReached() { return axisStatus_[10]; }
|
bool targetReached();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the property from axisStatus_
|
* @brief Read the property from axisStatus (see masterMacsAxisImpl
|
||||||
|
* redefinition in masterMacsAxis.cpp)
|
||||||
*/
|
*/
|
||||||
bool internalLimitActive() { return axisStatus_[11]; }
|
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() { return axisStatus_[14]; }
|
bool setEventHasOcurred();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the property from axisStatus_
|
* @brief Read the property from axisStatus (see masterMacsAxisImpl
|
||||||
|
* redefinition in masterMacsAxis.cpp)
|
||||||
*/
|
*/
|
||||||
bool powerEnabled() { return axisStatus_[15]; }
|
bool powerEnabled();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the Master MACS status with the xR10 command and store the
|
* @brief Read the Master MACS error with the xR10 command and store
|
||||||
* 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() { return axisError_[1]; }
|
bool shortCircuit();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the property from axisError_
|
* @brief Read the property from axisError (see masterMacsAxisImpl
|
||||||
|
* redefinition in masterMacsAxis.cpp)
|
||||||
*/
|
*/
|
||||||
bool encoderError() { return axisError_[2]; }
|
bool encoderError();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the property from axisError_
|
* @brief Read the property from axisError (see masterMacsAxisImpl
|
||||||
|
* redefinition in masterMacsAxis.cpp)
|
||||||
*/
|
*/
|
||||||
bool followingError() { return axisError_[3]; }
|
bool followingError();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the property from axisError_
|
* @brief Read the property from axisError (see masterMacsAxisImpl
|
||||||
|
* redefinition in masterMacsAxis.cpp)
|
||||||
*/
|
*/
|
||||||
bool communicationError() { return axisError_[4]; }
|
bool communicationError();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the property from axisError_
|
* @brief Read the property from axisError (see masterMacsAxisImpl
|
||||||
|
* redefinition in masterMacsAxis.cpp)
|
||||||
*/
|
*/
|
||||||
bool feedbackError() { return axisError_[5]; }
|
bool feedbackError();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the property from axisError_
|
* @brief Read the property from axisError (see masterMacsAxisImpl
|
||||||
|
* redefinition in masterMacsAxis.cpp)
|
||||||
*/
|
*/
|
||||||
bool positiveLimitSwitch() { return axisError_[6]; }
|
bool positiveLimitSwitch();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the property from axisError_
|
* @brief Read the property from axisError (see masterMacsAxisImpl
|
||||||
|
* redefinition in masterMacsAxis.cpp)
|
||||||
*/
|
*/
|
||||||
bool negativeLimitSwitch() { return axisError_[7]; }
|
bool negativeLimitSwitch();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the property from axisError_
|
* @brief Read the property from axisError (see masterMacsAxisImpl
|
||||||
|
* redefinition in masterMacsAxis.cpp)
|
||||||
*/
|
*/
|
||||||
bool positiveSoftwareLimit() { return axisError_[8]; }
|
bool positiveSoftwareLimit();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the property from axisError_
|
* @brief Read the property from axisError (see masterMacsAxisImpl
|
||||||
|
* redefinition in masterMacsAxis.cpp)
|
||||||
*/
|
*/
|
||||||
bool negativeSoftwareLimit() { return axisError_[9]; }
|
bool negativeSoftwareLimit();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the property from axisError_
|
* @brief Read the property from axisError (see masterMacsAxisImpl
|
||||||
|
* redefinition in masterMacsAxis.cpp)
|
||||||
*/
|
*/
|
||||||
bool overCurrent() { return axisError_[10]; }
|
bool overCurrent();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the property from axisError_
|
* @brief Read the property from axisError (see masterMacsAxisImpl
|
||||||
|
* redefinition in masterMacsAxis.cpp)
|
||||||
*/
|
*/
|
||||||
bool overTemperature() { return axisError_[11]; }
|
bool overTemperature();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the property from axisError_
|
* @brief Read the property from axisError (see masterMacsAxisImpl
|
||||||
|
* redefinition in masterMacsAxis.cpp)
|
||||||
*/
|
*/
|
||||||
bool overVoltage() { return axisError_[12]; }
|
bool overVoltage();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the property from axisError_
|
* @brief Read the property from axisError (see masterMacsAxisImpl
|
||||||
|
* redefinition in masterMacsAxis.cpp)
|
||||||
*/
|
*/
|
||||||
bool underVoltage() { return axisError_[13]; }
|
bool underVoltage();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read the property from axisError_
|
* @brief Read the property from axisError (see masterMacsAxisImpl
|
||||||
|
* redefinition in masterMacsAxis.cpp)
|
||||||
*/
|
*/
|
||||||
bool stoFault() { return axisError_[15]; }
|
bool stoFault();
|
||||||
|
|
||||||
|
private:
|
||||||
|
masterMacsController *pC_;
|
||||||
|
std::unique_ptr<masterMacsAxisImpl> pMasterMacsA_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -12,6 +12,35 @@
|
|||||||
#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 {
|
||||||
|
double comTimeout;
|
||||||
|
|
||||||
|
// Indices of additional ParamLib entries
|
||||||
|
int nodeReset;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Copy src into dst and replace all NULL terminators up to the carriage
|
* @brief Copy src into dst and replace all NULL terminators up to the carriage
|
||||||
* return with spaces. This allows to print *dst with asynPrint.
|
* return with spaces. This allows to print *dst with asynPrint.
|
||||||
@@ -52,15 +81,32 @@ 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};
|
||||||
|
|
||||||
// Initialization of all member variables
|
// =========================================================================
|
||||||
comTimeout_ = comTimeout;
|
// Create additional parameter library entries
|
||||||
|
|
||||||
|
status =
|
||||||
|
createParam("NODE_RESET", asynParamInt32, &pMasterMacsC_->nodeReset);
|
||||||
|
if (status != asynSuccess) {
|
||||||
|
asynPrint(this->pasynUser(), ASYN_TRACE_ERROR,
|
||||||
|
"Controller \"%s\" => %s, line %d\nFATAL ERROR (creating a "
|
||||||
|
"parameter failed with %s).\nTerminating IOC",
|
||||||
|
portName, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
stringifyAsynStatus(status));
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
// =========================================================================
|
// =========================================================================
|
||||||
|
|
||||||
@@ -93,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__);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -114,8 +214,24 @@ masterMacsAxis *masterMacsController::getMasterMacsAxis(int axisNo) {
|
|||||||
return dynamic_cast<masterMacsAxis *>(asynAxis);
|
return dynamic_cast<masterMacsAxis *>(asynAxis);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
asynStatus masterMacsController::writeInt32(asynUser *pasynUser,
|
||||||
|
epicsInt32 value) {
|
||||||
|
int function = pasynUser->reason;
|
||||||
|
|
||||||
|
// =====================================================================
|
||||||
|
|
||||||
|
masterMacsAxis *axis = getMasterMacsAxis(pasynUser);
|
||||||
|
|
||||||
|
// Handle custom PVs
|
||||||
|
if (function == nodeReset()) {
|
||||||
|
return axis->nodeReset();
|
||||||
|
} else {
|
||||||
|
return sinqController::writeInt32(pasynUser, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,7 +246,6 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
|
|||||||
|
|
||||||
// Definition of local variables.
|
// Definition of local variables.
|
||||||
asynStatus status = asynSuccess;
|
asynStatus status = asynSuccess;
|
||||||
asynStatus pl_status = asynSuccess;
|
|
||||||
char fullCommand[MAXBUF_] = {0};
|
char fullCommand[MAXBUF_] = {0};
|
||||||
char fullResponse[MAXBUF_] = {0};
|
char fullResponse[MAXBUF_] = {0};
|
||||||
char drvMessageText[MAXBUF_] = {0};
|
char drvMessageText[MAXBUF_] = {0};
|
||||||
@@ -158,13 +273,7 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
|
|||||||
|
|
||||||
// Check if a custom timeout has been given
|
// Check if a custom timeout has been given
|
||||||
if (comTimeout < 0.0) {
|
if (comTimeout < 0.0) {
|
||||||
comTimeout = 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
|
||||||
@@ -192,7 +301,7 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
|
|||||||
msgPrintControlKey comKey =
|
msgPrintControlKey comKey =
|
||||||
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
if (msgPrintControl_.shouldBePrinted(comKey, true, pasynUserSelf)) {
|
if (getMsgPrintControl().shouldBePrinted(comKey, true, pasynUserSelf)) {
|
||||||
char printableCommand[MAXBUF_] = {0};
|
char printableCommand[MAXBUF_] = {0};
|
||||||
adjustForPrint(printableCommand, fullCommand, MAXBUF_);
|
adjustForPrint(printableCommand, fullCommand, MAXBUF_);
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
@@ -202,7 +311,7 @@ asynStatus masterMacsController::writeRead(int axisNo, int tcpCmd,
|
|||||||
stringifyAsynStatus(status), printableCommand);
|
stringifyAsynStatus(status), printableCommand);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
msgPrintControl_.resetCount(comKey, pasynUserSelf);
|
getMsgPrintControl().resetCount(comKey, pasynUserSelf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create custom error messages for different failure modes
|
// Create custom error messages for different failure modes
|
||||||
@@ -248,48 +357,38 @@ 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) {
|
||||||
pl_status = axis->setIntegerParam(this->motorStatusCommsError_, 0);
|
masterMacsAxis *axis = getMasterMacsAxis(axisNo);
|
||||||
if (pl_status != asynSuccess) {
|
if (axis == nullptr) {
|
||||||
return paramLibAccessFailed(pl_status, "motorStatusCommsError_",
|
// We already did the error logging directly in getAxis
|
||||||
axisNo, __PRETTY_FUNCTION__, __LINE__);
|
return asynError;
|
||||||
}
|
}
|
||||||
} else if (status == asynDisconnected) {
|
|
||||||
// Do nothing
|
|
||||||
} else {
|
|
||||||
// Set the error status bits only if the axis is not disconnected
|
|
||||||
|
|
||||||
// Check if the axis already is in an error communication mode. If
|
if (status == asynSuccess) {
|
||||||
// it is not, upstream the error. This is done to avoid "flooding"
|
setAxisParamChecked(axis, motorStatusCommsError, false);
|
||||||
// the user with different error messages if more than one error
|
} else {
|
||||||
// ocurred before an error-free communication
|
/*
|
||||||
pl_status =
|
Since the communication failed, there is the possibility that the
|
||||||
getIntegerParam(axisNo, motorStatusProblem_, &motorStatusProblem);
|
controller is not connected at all to the network. In that case, we
|
||||||
if (pl_status != asynSuccess) {
|
cannot be sure that the information read out in the init method of
|
||||||
return paramLibAccessFailed(pl_status, "motorStatusProblem_",
|
the axis is still up-to-date the next time we get a connection.
|
||||||
axisNo, __PRETTY_FUNCTION__, __LINE__);
|
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) {
|
if (motorStatusProblem == 0) {
|
||||||
pl_status = axis->setStringParam(motorMessageText_, drvMessageText);
|
setAxisParamChecked(axis, motorMessageText, drvMessageText);
|
||||||
if (pl_status != asynSuccess) {
|
setAxisParamChecked(axis, motorStatusProblem, true);
|
||||||
return paramLibAccessFailed(pl_status, "motorMessageText_",
|
setAxisParamChecked(axis, motorStatusCommsError, false);
|
||||||
axisNo, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
pl_status = axis->setIntegerParam(motorStatusProblem_, 1);
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return paramLibAccessFailed(pl_status, "motorStatusProblem",
|
|
||||||
axisNo, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
|
|
||||||
pl_status = axis->setIntegerParam(motorStatusProblem_, 1);
|
|
||||||
if (pl_status != asynSuccess) {
|
|
||||||
return paramLibAccessFailed(pl_status, "motorStatusCommsError_",
|
|
||||||
axisNo, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -310,24 +409,26 @@ asynStatus masterMacsController::parseResponse(
|
|||||||
const char *fullCommand, const char *fullResponse, char *drvMessageText,
|
const char *fullCommand, const char *fullResponse, char *drvMessageText,
|
||||||
int *valueStart, int *valueStop, int axisNo, int tcpCmd, bool isRead) {
|
int *valueStart, int *valueStop, int axisNo, int tcpCmd, bool isRead) {
|
||||||
|
|
||||||
|
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};
|
||||||
|
|
||||||
msgPrintControlKey parseKey =
|
msgPrintControlKey parseKey =
|
||||||
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||||
|
|
||||||
// Was the motor previously connected?
|
masterMacsAxis *axis = getMasterMacsAxis(axisNo);
|
||||||
status = getIntegerParam(axisNo, motorConnected(), &prevConnected);
|
if (axisNo != 0 && axis == nullptr) {
|
||||||
if (status != asynSuccess) {
|
return asynError;
|
||||||
return paramLibAccessFailed(status, "motorConnected", axisNo,
|
}
|
||||||
__PRETTY_FUNCTION__, __LINE__);
|
|
||||||
|
// Was the motor previously connected?
|
||||||
|
if (axis != nullptr) {
|
||||||
|
getAxisParamChecked(axis, motorConnected, &prevConnected);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't use strlen here since the C string terminator 0x00
|
|
||||||
// occurs in the middle of the char array.
|
|
||||||
for (uint32_t i = 0; i < MAXBUF_; i++) {
|
for (uint32_t i = 0; i < MAXBUF_; i++) {
|
||||||
if (fullResponse[i] == '\x19') {
|
if (fullResponse[i] == '\x19') {
|
||||||
responseStart = i;
|
responseStart = i;
|
||||||
@@ -336,6 +437,7 @@ asynStatus masterMacsController::parseResponse(
|
|||||||
} else if (fullResponse[i] == '\x06') {
|
} else if (fullResponse[i] == '\x06') {
|
||||||
// ACK
|
// ACK
|
||||||
*valueStop = i;
|
*valueStop = i;
|
||||||
|
responseValid = true;
|
||||||
|
|
||||||
// Motor wasn't connected before -> Update the paramLib entry and PV
|
// Motor wasn't connected before -> Update the paramLib entry and PV
|
||||||
// to show it is now connected.
|
// to show it is now connected.
|
||||||
@@ -347,71 +449,21 @@ asynStatus masterMacsController::parseResponse(
|
|||||||
"connected.\n",
|
"connected.\n",
|
||||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||||
|
|
||||||
masterMacsAxis *axis = getMasterMacsAxis(axisNo);
|
if (axis != nullptr) {
|
||||||
if (axis == nullptr) {
|
setAxisParamChecked(axis, motorConnected, true);
|
||||||
return asynError;
|
|
||||||
}
|
|
||||||
status = axis->setIntegerParam(motorConnected(), 1);
|
|
||||||
if (status != asynSuccess) {
|
|
||||||
return paramLibAccessFailed(status, "motorConnected",
|
|
||||||
axisNo, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
status = callParamCallbacks();
|
status = callParamCallbacks();
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line "
|
"Controller \"%s\", axis %d => %s, line "
|
||||||
"%d:\nCould not update parameter library\n",
|
"%d:\nCould not update parameter library\n",
|
||||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
portName, axisNo, __PRETTY_FUNCTION__,
|
||||||
|
__LINE__);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
msgPrintControl_.resetCount(parseKey, pasynUserSelf);
|
|
||||||
|
|
||||||
// Check if the response matches the expectations. Each response
|
|
||||||
// contains the string "axisNo R tcpCmd" (including the spaces)
|
|
||||||
char expectedResponseSubstring[MAXBUF_] = {0};
|
|
||||||
|
|
||||||
// The response does not contain a leading 0 if tcpCmd only has
|
|
||||||
// a single digit!
|
|
||||||
if (isRead) {
|
|
||||||
snprintf(expectedResponseSubstring, MAXBUF_ - 4, "%d R %d",
|
|
||||||
axisNo, tcpCmd);
|
|
||||||
} else {
|
|
||||||
snprintf(expectedResponseSubstring, MAXBUF_ - 4, "%d S %d",
|
|
||||||
axisNo, tcpCmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
msgPrintControlKey responseMatchKey = msgPrintControlKey(
|
break;
|
||||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
|
||||||
|
|
||||||
if (strstr(&fullResponse[responseStart],
|
|
||||||
expectedResponseSubstring) == NULL) {
|
|
||||||
adjustForPrint(printableCommand, fullCommand, MAXBUF_);
|
|
||||||
adjustForPrint(printableResponse, fullResponse, MAXBUF_);
|
|
||||||
|
|
||||||
if (msgPrintControl_.shouldBePrinted(parseKey, true,
|
|
||||||
pasynUserSelf)) {
|
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACEIO_DRIVER,
|
|
||||||
"Controller \"%s\", axis %d => %s, line "
|
|
||||||
"%d:\nMismatched "
|
|
||||||
"response %s to command %s.%s\n",
|
|
||||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
|
||||||
printableResponse, printableCommand,
|
|
||||||
msgPrintControl_.getSuffix());
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(
|
|
||||||
drvMessageText, MAXBUF_,
|
|
||||||
"Mismatched response %s to command %s. Please call the "
|
|
||||||
"support.",
|
|
||||||
printableResponse, printableCommand);
|
|
||||||
return asynError;
|
|
||||||
} else {
|
|
||||||
msgPrintControl_.resetCount(responseMatchKey, pasynUserSelf);
|
|
||||||
}
|
|
||||||
return asynSuccess;
|
|
||||||
} else if (fullResponse[i] == '\x15') {
|
} else if (fullResponse[i] == '\x15') {
|
||||||
/*
|
/*
|
||||||
NAK
|
NAK
|
||||||
@@ -428,33 +480,27 @@ asynStatus masterMacsController::parseResponse(
|
|||||||
"disconnected.\n",
|
"disconnected.\n",
|
||||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||||
|
|
||||||
masterMacsAxis *axis = getMasterMacsAxis(axisNo);
|
if (axis != nullptr) {
|
||||||
if (axis == nullptr) {
|
setAxisParamChecked(axis, motorConnected, false);
|
||||||
return asynError;
|
|
||||||
}
|
|
||||||
status = axis->setIntegerParam(motorConnected(), 0);
|
|
||||||
if (status != asynSuccess) {
|
|
||||||
return paramLibAccessFailed(status, "motorConnected",
|
|
||||||
axisNo, __PRETTY_FUNCTION__,
|
|
||||||
__LINE__);
|
|
||||||
}
|
|
||||||
status = callParamCallbacks();
|
status = callParamCallbacks();
|
||||||
if (status != asynSuccess) {
|
if (status != asynSuccess) {
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||||
"Controller \"%s\", axis %d => %s, line "
|
"Controller \"%s\", axis %d => %s, line "
|
||||||
"%d:\nCould not update parameter library\n",
|
"%d:\nCould not update parameter library\n",
|
||||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
portName, axisNo, __PRETTY_FUNCTION__,
|
||||||
|
__LINE__);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return asynDisconnected;
|
}
|
||||||
|
break;
|
||||||
} else if (fullResponse[i] == '\x18') {
|
} else if (fullResponse[i] == '\x18') {
|
||||||
// CAN
|
// CAN
|
||||||
snprintf(drvMessageText, MAXBUF_,
|
snprintf(drvMessageText, MAXBUF_,
|
||||||
"Tried to write with a read-only command. This is a "
|
"Tried to write with a read-only command. This is a "
|
||||||
"bug, please call the support.");
|
"bug, please call the support.");
|
||||||
|
|
||||||
if (msgPrintControl_.shouldBePrinted(parseKey, true,
|
if (getMsgPrintControl().shouldBePrinted(parseKey, true,
|
||||||
pasynUserSelf)) {
|
pasynUserSelf)) {
|
||||||
adjustForPrint(printableCommand, fullCommand, MAXBUF_);
|
adjustForPrint(printableCommand, fullCommand, MAXBUF_);
|
||||||
asynPrint(
|
asynPrint(
|
||||||
@@ -462,18 +508,65 @@ asynStatus masterMacsController::parseResponse(
|
|||||||
"Controller \"%s\", axis %d => %s, line %d:\nTried to "
|
"Controller \"%s\", axis %d => %s, line %d:\nTried to "
|
||||||
"write with the read-only command %s.%s\n",
|
"write with the read-only command %s.%s\n",
|
||||||
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
||||||
printableCommand, msgPrintControl_.getSuffix());
|
printableCommand, getMsgPrintControl().getSuffix());
|
||||||
}
|
}
|
||||||
|
responseValid = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (responseValid) {
|
||||||
|
getMsgPrintControl().resetCount(parseKey, pasynUserSelf);
|
||||||
|
|
||||||
|
// Check if the response matches the expectations. Each response
|
||||||
|
// contains the string "axisNo R tcpCmd" (including the spaces)
|
||||||
|
char expectedResponseSubstring[MAXBUF_] = {0};
|
||||||
|
|
||||||
|
// The response does not contain a leading 0 if tcpCmd only has
|
||||||
|
// a single digit!
|
||||||
|
if (isRead) {
|
||||||
|
snprintf(expectedResponseSubstring, MAXBUF_ - 4, "%d R %d", axisNo,
|
||||||
|
tcpCmd);
|
||||||
|
} else {
|
||||||
|
snprintf(expectedResponseSubstring, MAXBUF_ - 4, "%d S %d", axisNo,
|
||||||
|
tcpCmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
msgPrintControlKey responseMatchKey =
|
||||||
|
msgPrintControlKey(portName, axisNo, __PRETTY_FUNCTION__, __LINE__);
|
||||||
|
|
||||||
|
if (strstr(&fullResponse[responseStart], expectedResponseSubstring) ==
|
||||||
|
NULL) {
|
||||||
|
adjustForPrint(printableCommand, fullCommand, MAXBUF_);
|
||||||
|
adjustForPrint(printableResponse, fullResponse, MAXBUF_);
|
||||||
|
|
||||||
|
if (getMsgPrintControl().shouldBePrinted(parseKey, true,
|
||||||
|
pasynUserSelf)) {
|
||||||
|
asynPrint(this->pasynUserSelf, ASYN_TRACEIO_DRIVER,
|
||||||
|
"Controller \"%s\", axis %d => %s, line "
|
||||||
|
"%d:\nMismatched "
|
||||||
|
"response %s to command %s.%s\n",
|
||||||
|
portName, axisNo, __PRETTY_FUNCTION__, __LINE__,
|
||||||
|
printableResponse, printableCommand,
|
||||||
|
getMsgPrintControl().getSuffix());
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(drvMessageText, MAXBUF_,
|
||||||
|
"Mismatched response %s to command %s. Please call the "
|
||||||
|
"support.",
|
||||||
|
printableResponse, printableCommand);
|
||||||
return asynError;
|
return asynError;
|
||||||
|
} else {
|
||||||
|
getMsgPrintControl().resetCount(responseMatchKey, pasynUserSelf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return asynError;
|
return asynSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus masterMacsController::readInt32(asynUser *pasynUser,
|
asynStatus masterMacsController::readInt32(asynUser *pasynUser,
|
||||||
epicsInt32 *value) {
|
epicsInt32 *value) {
|
||||||
// masterMacs can be disabled
|
// masterMacs can be disabled
|
||||||
if (pasynUser->reason == motorCanDisable_) {
|
if (pasynUser->reason == motorCanDisable()) {
|
||||||
*value = 1;
|
*value = 1;
|
||||||
return asynSuccess;
|
return asynSuccess;
|
||||||
} else {
|
} else {
|
||||||
@@ -481,6 +574,10 @@ asynStatus masterMacsController::readInt32(asynUser *pasynUser,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double masterMacsController::comTimeout() { return pMasterMacsC_->comTimeout; }
|
||||||
|
|
||||||
|
int masterMacsController::nodeReset() { return pMasterMacsC_->nodeReset; }
|
||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
/** The following functions are C-wrappers, and can be called directly from
|
/** The following functions are C-wrappers, and can be called directly from
|
||||||
* iocsh */
|
* iocsh */
|
||||||
@@ -540,7 +637,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);
|
||||||
|
|||||||
@@ -8,11 +8,18 @@
|
|||||||
|
|
||||||
#ifndef masterMacsController_H
|
#ifndef masterMacsController_H
|
||||||
#define masterMacsController_H
|
#define masterMacsController_H
|
||||||
#include "masterMacsAxis.h"
|
|
||||||
#include "sinqAxis.h"
|
#include "sinqAxis.h"
|
||||||
#include "sinqController.h"
|
#include "sinqController.h"
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
class masterMacsController : public sinqController {
|
// Forward declaration of the controller class to resolve the cyclic dependency
|
||||||
|
// between the controller and the axis .h-file. See
|
||||||
|
// https://en.cppreference.com/w/cpp/language/class.
|
||||||
|
class HIDDEN masterMacsAxis;
|
||||||
|
|
||||||
|
struct HIDDEN masterMacsControllerImpl;
|
||||||
|
|
||||||
|
class HIDDEN masterMacsController : public sinqController {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
@@ -31,6 +38,22 @@ class 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
|
||||||
|
*
|
||||||
|
* @param pasynUser
|
||||||
|
* @param value
|
||||||
|
* @return asynStatus
|
||||||
|
*/
|
||||||
|
asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the axis object
|
* @brief Get the axis object
|
||||||
*
|
*
|
||||||
@@ -49,6 +72,17 @@ class masterMacsController : public sinqController {
|
|||||||
*/
|
*/
|
||||||
masterMacsAxis *getMasterMacsAxis(int axisNo);
|
masterMacsAxis *getMasterMacsAxis(int axisNo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Overloaded function of sinqController
|
||||||
|
*
|
||||||
|
* The function is overloaded to allow resetting the node
|
||||||
|
*
|
||||||
|
* @param pasynUser Specify the axis via the asynUser
|
||||||
|
* @param value New value
|
||||||
|
* @return asynStatus
|
||||||
|
*/
|
||||||
|
virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Send a command to the hardware (S mode)
|
* @brief Send a command to the hardware (S mode)
|
||||||
*
|
*
|
||||||
@@ -123,15 +157,13 @@ class masterMacsController : public sinqController {
|
|||||||
*
|
*
|
||||||
* @return double Timeout in seconds
|
* @return double Timeout in seconds
|
||||||
*/
|
*/
|
||||||
double comTimeout() { return comTimeout_; }
|
double comTimeout();
|
||||||
|
|
||||||
asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value);
|
// Accessors for additional PVs
|
||||||
|
int nodeReset();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*
|
std::unique_ptr<masterMacsControllerImpl> pMasterMacsC_;
|
||||||
Stores the constructor input comTimeout
|
|
||||||
*/
|
|
||||||
double comTimeout_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* masterMacsController_H */
|
#endif /* masterMacsController_H */
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ 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.
|
||||||
@@ -32,50 +34,57 @@ interpretation = [
|
|||||||
("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
|
||||||
|
if platform.system() == "Linux":
|
||||||
interactive()
|
interactive()
|
||||||
else:
|
else:
|
||||||
|
print(help)
|
||||||
|
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)
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ 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.
|
||||||
@@ -23,7 +25,8 @@ interpretation = [
|
|||||||
("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)",
|
||||||
|
"Motor does execute command messages (remote mode)"), # Bit 9
|
||||||
("Target not reached", "Target reached"), # Bit 10
|
("Target not reached", "Target reached"), # Bit 10
|
||||||
("Ok", "Internal limit active (current, voltage, velocity or position)"), # Bit 11
|
("Ok", "Internal limit active (current, voltage, velocity or position)"), # Bit 11
|
||||||
("Not specified", "Not specified"), # Bit 12
|
("Not specified", "Not specified"), # Bit 12
|
||||||
@@ -32,48 +35,55 @@ interpretation = [
|
|||||||
("Not specified", "Not specified"), # Bit 15
|
("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
|
||||||
|
if platform.system() == "Linux":
|
||||||
interactive()
|
interactive()
|
||||||
else:
|
else:
|
||||||
|
print(help)
|
||||||
|
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("============")
|
||||||
|
|||||||
@@ -6,23 +6,47 @@ 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
|
||||||
@@ -33,24 +57,21 @@ def readMasterMacsReply(input):
|
|||||||
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)
|
||||||
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:
|
else:
|
||||||
|
addr = argv[1].split(':')
|
||||||
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
|
s.connect((addr[0], int(addr[1])))
|
||||||
|
|
||||||
try:
|
if len(argv) == 2:
|
||||||
|
|
||||||
|
if platform.system() == "Linux":
|
||||||
|
import curses
|
||||||
|
|
||||||
stdscr = curses.initscr()
|
stdscr = curses.initscr()
|
||||||
curses.noecho()
|
curses.noecho()
|
||||||
@@ -125,7 +146,8 @@ 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])
|
||||||
@@ -134,38 +156,24 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
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()
|
||||||
|
|
||||||
finally:
|
|
||||||
|
|
||||||
# to quit
|
# to quit
|
||||||
curses.nocbreak()
|
curses.nocbreak()
|
||||||
stdscr.keypad(False)
|
stdscr.keypad(False)
|
||||||
curses.echo()
|
curses.echo()
|
||||||
curses.endwin()
|
curses.endwin()
|
||||||
|
else:
|
||||||
except:
|
print(help)
|
||||||
print("""
|
elif len(argv) == 3:
|
||||||
Invalid Arguments
|
buf = packMasterMacsCommand(argv[2])
|
||||||
|
s.send(buf)
|
||||||
Option 1: Single Command
|
reply = readMasterMacsReply(s)
|
||||||
------------------------
|
print(reply.decode('utf-8') + '\n')
|
||||||
|
else:
|
||||||
Usage: writeRead.py pmachost:port command
|
print(help)
|
||||||
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