Compare commits
4 Commits
exploring_
...
amorsim
Author | SHA1 | Date | |
---|---|---|---|
cc88331652 | |||
c445af75c1 | |||
ebc3de1bd2 | |||
73c9c98329 |
125
.gitignore
vendored
125
.gitignore
vendored
@ -1,125 +0,0 @@
|
||||
# Took these from the https://github.com/github/gitignore project on October 21, 2011
|
||||
|
||||
# **** 'Personal' entries don't belong in here - put them in your .git/info/exclude file ****
|
||||
|
||||
# Ignore text editor (e.g. emacs) autosave files
|
||||
*~
|
||||
|
||||
# Build Artifacts
|
||||
O.*_Common/
|
||||
O.*_RHEL8-x86_64/
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
*.d
|
||||
SICServer*
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
|
||||
# Compiled python files
|
||||
*.py[co]
|
||||
|
||||
# Eclipse-generated files
|
||||
*.pydevproject
|
||||
.project
|
||||
.metadata
|
||||
bin/**
|
||||
tmp/**
|
||||
tmp/**/*
|
||||
*.tmp
|
||||
*.bak
|
||||
*.swp
|
||||
*~.nib
|
||||
local.properties
|
||||
.classpath
|
||||
.settings/
|
||||
.loadpath
|
||||
|
||||
# External tool builders
|
||||
.externalToolBuilders/
|
||||
|
||||
# Locally stored "Eclipse launch configurations"
|
||||
*.launch
|
||||
|
||||
# CDT-specific
|
||||
.cproject
|
||||
|
||||
# PDT-specific
|
||||
.buildpath
|
||||
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
*.sln
|
||||
*.vcproj
|
||||
*.exe
|
||||
*.vcxproj
|
||||
*.filters
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.sln.docstates
|
||||
*.sdf
|
||||
.cvsignore
|
||||
|
||||
#Test results
|
||||
*.log
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Rr]elease/
|
||||
*_i.c
|
||||
*_p.c
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.vspscc
|
||||
.builds
|
||||
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*
|
||||
|
||||
|
||||
|
||||
# Others
|
||||
*.autosave
|
||||
|
||||
|
||||
# Windows image file caches
|
||||
Thumbs.db
|
||||
|
||||
|
||||
# Mac OS X Finder
|
||||
.DS_Store
|
||||
._*
|
@ -1 +0,0 @@
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="04b4", ATTR{idProduct}=="1002", MODE="0666" GROUP="plugdev", TAG+="uaccess"
|
@ -1,22 +0,0 @@
|
||||
# This Makefile has to be executed in the synApps-xxx/support/autosave-xxx directory.
|
||||
# It creates a autosave module to load into iocsh
|
||||
include /ioc/tools/driver.makefile
|
||||
|
||||
MODULE=autosave
|
||||
|
||||
BUILDCLASSES=Linux
|
||||
|
||||
USR_DEPENDENCIES=
|
||||
|
||||
SOURCES += asApp/src/dbrestore.c
|
||||
SOURCES += asApp/src/save_restore.c
|
||||
SOURCES += asApp/src/initHooks.c
|
||||
SOURCES += asApp/src/fGetDateStr.c
|
||||
SOURCES += asApp/src/configMenuSub.c
|
||||
SOURCES += asApp/src/verify.c
|
||||
SOURCES += asApp/src/asVerify.c
|
||||
SOURCES += asApp/src/os/Linux/osdNfs.c
|
||||
|
||||
HEADERS += asApp/src/os/Linux/osdNfs.h
|
||||
|
||||
DBDS += asApp/src/asSupport.dbd
|
@ -1,17 +0,0 @@
|
||||
include /ioc/tools/driver.makefile
|
||||
|
||||
MODULE=scaler
|
||||
|
||||
BUILDCLASSES=Linux
|
||||
|
||||
USR_DEPENDENCIES = asyn,427.0.1
|
||||
|
||||
SOURCES += stdApp/src/scalerRecord.c
|
||||
SOURCES += stdApp/src/devScalerAsyn.c
|
||||
SOURCES += stdApp/src/drvScalerSoft.c
|
||||
|
||||
HEADERS += devScaler.h
|
||||
|
||||
|
||||
DBDS += stdApp/src/scalerRecord.dbd
|
||||
DBDS += stdApp/src/scalerSupport.dbd
|
@ -2,13 +2,12 @@
|
||||
include /ioc/tools/driver.makefile
|
||||
|
||||
MODULE=sinq
|
||||
|
||||
BUILDCLASSES=Linux
|
||||
EPICS_VERSIONS=3.14.12 7.0.4.1
|
||||
|
||||
# additional module dependencies
|
||||
REQUIRED+=SynApps
|
||||
REQUIRED+=stream
|
||||
REQUIRED+=scaler
|
||||
|
||||
# using a test version
|
||||
scaler_VERSION=koennecke
|
||||
@ -27,10 +26,8 @@ SOURCES += sinqEPICSApp/src/EL734Driver.cpp
|
||||
SOURCES += sinqEPICSApp/src/NanotecDriver.cpp
|
||||
SOURCES += sinqEPICSApp/src/stptok.cpp
|
||||
SOURCES += sinqEPICSApp/src/PhytronDriver.cpp
|
||||
SOURCES += sinqEPICSApp/src/EuroMoveDriver.cpp
|
||||
SOURCES += sinqEPICSApp/src/pmacAsynIPPort.c
|
||||
SOURCES += sinqEPICSApp/src/pmacAxis.cpp
|
||||
SOURCES += sinqEPICSApp/src/pmacController.cpp
|
||||
SOURCES += sinqEPICSApp/src/drvAsynMasterMACSPort.c
|
||||
SOURCES += sinqEPICSApp/src/MasterMACSDriver.cpp
|
||||
|
||||
# MISCS would be the place to keep the stream device template files
|
||||
|
@ -1,37 +0,0 @@
|
||||
# This build the sinq extensions for the PSI EPICS setup
|
||||
include /ioc/tools/driver.makefile
|
||||
|
||||
MODULE=sinq
|
||||
LIBVERSION=brambilla_m_test
|
||||
BUILDCLASSES=Linux
|
||||
EPICS_VERSIONS=3.14.12 7.0.4.1
|
||||
ARCH_FILTER=RHEL7-x86_64
|
||||
|
||||
# additional module dependencies
|
||||
REQUIRED+=SynApps
|
||||
REQUIRED+=stream
|
||||
REQUIRED+=scaler
|
||||
|
||||
# using a test version
|
||||
scaler_VERSION=koennecke
|
||||
|
||||
TEMPLATES += sinqEPICSApp/Db/dimetix.db
|
||||
TEMPLATES += sinqEPICSApp/Db/slsvme.db
|
||||
TEMPLATES += sinqEPICSApp/Db/spsamor.db
|
||||
|
||||
DBDS += sinqEPICSApp/src/sinq.dbd
|
||||
|
||||
# What we need at SINQ
|
||||
SOURCES += sinqEPICSApp/src/devScalerEL737.c
|
||||
SOURCES += sinqEPICSApp/src/SINQController.cpp
|
||||
SOURCES += sinqEPICSApp/src/SINQAxis.cpp
|
||||
SOURCES += sinqEPICSApp/src/EL734Driver.cpp
|
||||
SOURCES += sinqEPICSApp/src/NanotecDriver.cpp
|
||||
SOURCES += sinqEPICSApp/src/stptok.cpp
|
||||
SOURCES += sinqEPICSApp/src/PhytronDriver.cpp
|
||||
SOURCES += sinqEPICSApp/src/EuroMoveDriver.cpp
|
||||
SOURCES += sinqEPICSApp/src/pmacAsynIPPort.c
|
||||
SOURCES += sinqEPICSApp/src/pmacAxis.cpp
|
||||
SOURCES += sinqEPICSApp/src/pmacController.cpp
|
||||
|
||||
# MISCS would be the place to keep the stream device template files
|
@ -1,43 +0,0 @@
|
||||
# This build the sinq extensions for the PSI EPICS setup
|
||||
include /ioc/tools/driver.makefile
|
||||
|
||||
MODULE=sinq
|
||||
BUILDCLASSES=Linux
|
||||
EPICS_VERSIONS=7.0.7
|
||||
ARCH_FILTER=RHEL%
|
||||
|
||||
# additional module dependencies
|
||||
REQUIRED+=SynApps
|
||||
REQUIRED+=stream
|
||||
REQUIRED+=scaler
|
||||
REQUIRED+=asynMotor
|
||||
|
||||
# Release version
|
||||
LIBVERSION=2024-ed-dev2
|
||||
|
||||
# DB files to include in the release
|
||||
TEMPLATES += sinqEPICSApp/Db/dimetix.db
|
||||
TEMPLATES += sinqEPICSApp/Db/slsvme.db
|
||||
TEMPLATES += sinqEPICSApp/Db/spsamor.db
|
||||
|
||||
# DBD files to include in the release
|
||||
DBDS += sinqEPICSApp/src/sinq.dbd
|
||||
|
||||
# Source files to build
|
||||
SOURCES += sinqEPICSApp/src/devScalerEL737.c
|
||||
SOURCES += sinqEPICSApp/src/SINQController.cpp
|
||||
SOURCES += sinqEPICSApp/src/SINQAxis.cpp
|
||||
SOURCES += sinqEPICSApp/src/EL734Driver.cpp
|
||||
SOURCES += sinqEPICSApp/src/NanotecDriver.cpp
|
||||
SOURCES += sinqEPICSApp/src/stptok.cpp
|
||||
SOURCES += sinqEPICSApp/src/PhytronDriver.cpp
|
||||
SOURCES += sinqEPICSApp/src/EuroMoveDriver.cpp
|
||||
SOURCES += sinqEPICSApp/src/pmacAsynIPPort.c
|
||||
SOURCES += sinqEPICSApp/src/pmacAxis.cpp
|
||||
SOURCES += sinqEPICSApp/src/pmacController.cpp
|
||||
SOURCES += sinqEPICSApp/src/MasterMACSDriver.cpp
|
||||
SOURCES += sinqEPICSApp/src/pollerRegister.cpp
|
||||
|
||||
USR_CFLAGS += -Wall -Wextra # -Werror
|
||||
|
||||
# MISCS would be the place to keep the stream device template files
|
40
README.md
40
README.md
@ -1,40 +0,0 @@
|
||||
# SinqEPICSApp
|
||||
|
||||
This is an IOC application which contains the drivers for SINQ hardware.
|
||||
EPICS purists may find it messy because it contains the drivers for all
|
||||
SINQ stuff in one package rather then in separate modules. This is just
|
||||
for ease of distribution. The idea being that all of SINQ shares one
|
||||
module/IOC application and configures in its startup file what it needs
|
||||
of it.
|
||||
|
||||
Drivers included:
|
||||
|
||||
- EL734 motor controller
|
||||
- SINQ Delta Tau PMAC motor controller. This is a modified version of the Diamond
|
||||
PMAC code. The modification is necessary because PSI runs a different program in
|
||||
the MCU at SINQ then Diamond
|
||||
- Nanotec bus motor driver
|
||||
- Phytron MCU200 motor driver
|
||||
- EL737 counter box driver through the scaler record
|
||||
|
||||
There are some streamdevice protocol files provided:
|
||||
- spss5: for the Siemens SPS5 with the PSI custom RS232 module
|
||||
- slsvme: for the SLS magnet controllers managed by the SINQ special vmemaggi program
|
||||
- el755: the old SINQ magnet controller
|
||||
- dimetix: for the deimetix distance measurement device at AMOR
|
||||
|
||||
There are two main branches here:
|
||||
|
||||
- Of course master from which you can build the PSI RHEL7 module and the EEE module
|
||||
- The amorsim branch in which you can build the IOC application for ESS against the ICS
|
||||
setup. This is needed for the sinq-amorsim simulation. This branch exists because of the
|
||||
political problem to get a module into the ICS EEE setup.
|
||||
|
||||
Those political problems require a special development model:
|
||||
|
||||
1. If you do something, do it in a separate branch
|
||||
2. When reasonably sure that what you did works, merge it both into master and amorsim
|
||||
|
||||
Take care of the sinqEPICsApp/src/sinq.dbd file. This is the one which differs mostly between
|
||||
amorsim and master branches.
|
||||
|
@ -25,20 +25,17 @@ TEMPLATE_TOP=$(EPICS_BASE)/templates/makeBaseApp/top
|
||||
#SNCSEQ=$(EPICS_BASE)/../modules/soft/seq
|
||||
|
||||
# EPICS_BASE usually appears last so other apps can override stuff:
|
||||
|
||||
#EPICS_BASE=
|
||||
#MODULES=/home/epics/modules
|
||||
EPICS_BASE=/opt/epics/bases/base-3.14.12.5
|
||||
|
||||
# Set RULES here if you want to take build rules from somewhere
|
||||
# other than EPICS_BASE:
|
||||
##RULES=/path/to/epics/support/module/rules/x-y
|
||||
#MOTOR=/opt/epics/modules/motor/6.10.0/3.14.12.5
|
||||
#ASYN=/opt/epics/modules/asyn/4.27.0/3.14.12.5
|
||||
#SYNAPPSSTD=/opt/epics/modules/synAppsStd/3.4.1/3.14.12.5/
|
||||
##ANC=/usr/local/epics/anc350v17
|
||||
#STREAMS=/opt/epics/modules/streamdevice/2.6.0/3.14.12.5
|
||||
##LAKESHORE336=/usr/local/epics/support/lakeshore336
|
||||
#BUSY=/opt/epics/modules/busy/1.6.0/3.14.12.5
|
||||
##OXINSTCRYOJET=/usr/local/epics/support/OxInstCryojet-2-18-3
|
||||
#PCRE=/opt/epics/modules/pcre/8.36.0/3.14.12.5
|
||||
|
||||
#RULES=/path/to/epics/support/module/rules/x-y
|
||||
MOTOR=/opt/epics/modules/motor/6.10.0/3.14.12.5
|
||||
ASYN=/opt/epics/modules/asyn/4.27.0/3.14.12.5
|
||||
SYNAPPSSTD=/opt/epics/modules/synAppsStd/3.4.1/3.14.12.5/
|
||||
#ANC=/usr/local/epics/anc350v17
|
||||
STREAMS=/opt/epics/modules/streamdevice/2.6.0/3.14.12.5
|
||||
#LAKESHORE336=/usr/local/epics/support/lakeshore336
|
||||
BUSY=/opt/epics/modules/busy/1.6.0/3.14.12.5
|
||||
#OXINSTCRYOJET=/usr/local/epics/support/OxInstCryojet-2-18-3
|
||||
PCRE=/opt/epics/modules/pcre/8.36.0/3.14.12.5
|
||||
|
@ -1,23 +0,0 @@
|
||||
#!/usr/local/bin/iocsh
|
||||
|
||||
require sinq,koennecke
|
||||
|
||||
epicsEnvSet("TOP","/afs/psi.ch/project/sinqdev/sinqepicsapp/iocBoot/iocsinqEPICS")
|
||||
epicsEnvSet("BASE","/afs/psi.ch/project/sinqdev/sinqepicsapp")
|
||||
|
||||
cd ${TOP}
|
||||
|
||||
|
||||
|
||||
drvAsynIPPortConfigure("serial1", "129.129.195.83:1234",0,0,0)
|
||||
#drvAsynIPPortConfigure("serial1", "amor-ts:3002",0,0,0)
|
||||
#drvAsynIPPortConfigure("serial1", "localhost:9090",0,0,0)
|
||||
EuroMoveCreateController("llb","serial1", 10, 1);
|
||||
|
||||
### Motors
|
||||
|
||||
dbLoadRecords("$(BASE)/sinqEPICSApp/Db/asynRecord.db","P=KM36:,R=serial1,PORT=serial1,ADDR=0,OMAX=80,IMAX=80")
|
||||
dbLoadTemplate "motor.substitutions.eurollb"
|
||||
|
||||
|
||||
iocInit
|
@ -1,4 +1,4 @@
|
||||
qfile "$(MOTOR)/db/basic_asyn_motor.db"
|
||||
file "$(MOTOR)/db/basic_asyn_motor.db"
|
||||
{
|
||||
pattern
|
||||
{P, N, M, DTYP, PORT, ADDR, DESC, EGU, DIR, VELO, VBAS, ACCL, BDST, BVEL, BACC, MRES, PREC, DHLM, DLLM, INIT}
|
||||
|
@ -1,13 +0,0 @@
|
||||
file "$(BASE)/sinqEPICSApp/Db/basic_asyn_motor.db"
|
||||
{
|
||||
pattern
|
||||
{P, N, M, DTYP, PORT, ADDR, DESC, EGU, DIR, VELO, VBAS, ACCL, BDST, BVEL, BACC, MRES, PREC, RDBD, DHLM, DLLM, INIT}
|
||||
{KM36:llb:, 1, "m$(N)", "asynMotor", llb, 1, "m1", mm, Pos, 2.0, 0.1, .2, 0, 1, .2, .01, 3, 0.2, 1000, 0, "1"}
|
||||
}
|
||||
|
||||
file "$(BASE)/sinqEPICSApp/Db/motorMessage.db"
|
||||
{
|
||||
pattern
|
||||
{P,N, M,PORT}
|
||||
{KM36:llb:, 1, "m$(N)",llb}
|
||||
}
|
@ -1,15 +1,7 @@
|
||||
file "$(BASE)/sinqEPICSApp/Db/basic_asyn_motor.db"
|
||||
file "$(MOTOR)/db/basic_asyn_motor.db"
|
||||
{
|
||||
pattern
|
||||
{P, N, M, DTYP, PORT, ADDR, DESC, EGU, DIR, VELO, VBAS, ACCL, BDST, BVEL, BACC, MRES, PREC, RDBD, DHLM, DLLM, INIT}
|
||||
{KM36:phytron:, 1, "m$(N)", "asynMotor", phy, 1, "m1", mm, Pos, 2.0, 0.1, .2, 0, 1, .2, .001, 3, 0.2, 100, -100, "1"}
|
||||
{KM36:phytron:, 2, "m$(N)", "asynMotor", phy, 2, "m2", mm, Pos, 2.0, 0.1, .2, 0, 1, .2, .001, 3, 0.2, 100, -100, "10"}
|
||||
{P, N, M, DTYP, PORT, ADDR, DESC, EGU, DIR, VELO, VBAS, ACCL, BDST, BVEL, BACC, MRES, PREC, DHLM, DLLM, INIT}
|
||||
{KM36:phytron:, 1, "m$(N)", "asynMotor", phy, 1, "m1", mm, Pos, 2.0, 0.1, .2, 0, 1, .2, .001, 3, 100, -100, "1"}
|
||||
{KM36:phytron:, 2, "m$(N)", "asynMotor", phy, 2, "m2", mm, Pos, 2.0, 0.1, .2, 0, 1, .2, .001, 3, 100, -100, "10"}
|
||||
}
|
||||
|
||||
file "$(BASE)/sinqEPICSApp/Db/motorMessage.db"
|
||||
{
|
||||
pattern
|
||||
{P,N, M,PORT}
|
||||
{KM36:phytron:, 1, "m$(N)",phy}
|
||||
{KM36:phytron:, 2, "m$(N)",phy}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
#!/usr/local/bin/iocsh
|
||||
|
||||
require sinq,koennecke
|
||||
|
||||
epicsEnvSet("TOP","/afs/psi.ch/project/sinqdev/sinqepicsapp/iocBoot/iocsinqEPICS")
|
||||
epicsEnvSet("BASE","/afs/psi.ch/project/sinqdev/sinqepicsapp")
|
||||
epicsEnvSet("dbPATH","${EPICS_BASE}/dbd:${ASYN}/dbd:${MOTOR}/dbd")
|
||||
|
||||
cd ${TOP}
|
||||
|
||||
## Register all support components
|
||||
dbLoadDatabase "../../dbd/sinqEPICS.dbd"
|
||||
|
||||
|
||||
drvAsynIPPortConfigure("serial1", "129.129.195.58:22222",0,0,0)
|
||||
#drvAsynIPPortConfigure("serial1", "localhost:9090",0,0,0)
|
||||
PhytronCreateController("phy","serial1","0",1,0);
|
||||
|
||||
### Motors
|
||||
|
||||
dbLoadRecords("$(BASE)/sinqEPICSApp/Db/asynRecord.db","P=KM36:,R=serial1,PORT=serial1,ADDR=0,OMAX=80,IMAX=80")
|
||||
dbLoadTemplate "motor.substitutions.phytron"
|
||||
|
||||
|
||||
iocInit
|
@ -18,16 +18,19 @@ epicsEnvSet("dbPATH","${EPICS_BASE}/dbd::${ASYN}/dbd:${MOTOR}/dbd:${ANC}/dbd")
|
||||
cd ${TOP}
|
||||
|
||||
## Register all support components
|
||||
dbLoadDatabase "../../sinqEPICSApp/src/sinq.dbd"
|
||||
dbLoadDatabase "../../dbd/sinqEPICS.dbd"
|
||||
#dbLoadDatabase "dbd/sinq.dbd"
|
||||
sinqEPICS_registerRecordDeviceDriver pdbbase
|
||||
|
||||
## Load record instances
|
||||
#dbLoadRecords("db/xxx.db","user=koenneckeHost")
|
||||
|
||||
|
||||
#---------- load Nanotec motor controller
|
||||
#drvAsynIPPortConfigure("serial1", "narziss-ts:3002",0,0,0)
|
||||
#drvAsynIPPortConfigure("serial1", "localhost:5050",0,0,0)
|
||||
drvAsynIPPortConfigure("serial1", "localhost:8080",0,0,0)
|
||||
PhytronCreateController("phy","serial1","0",1,1);
|
||||
PhytronCreateController("phy","serial1",1,1);
|
||||
|
||||
### Motors
|
||||
|
||||
|
@ -1,94 +0,0 @@
|
||||
# Database definition for the SLS VME magnets as installed at AMOR
|
||||
|
||||
##
|
||||
## Read the High Limit
|
||||
##
|
||||
record(ai, "$(PREFIX)HighLim") {
|
||||
field(DTYP, "stream")
|
||||
field(DESC, "High Current Limit")
|
||||
field(INP, "@slsvme.proto read($(NO),hl) slsvme 0")
|
||||
field(SCAN, "1 second")
|
||||
field(PREC, "3")
|
||||
field(EGU, "A")
|
||||
}
|
||||
|
||||
##
|
||||
## Read the High Limit
|
||||
##
|
||||
record(ai, "$(PREFIX)LowLim") {
|
||||
field(DTYP, "stream")
|
||||
field(DESC, "Low Current Limit")
|
||||
field(INP, "@slsvme.proto read($(NO),ll) slsvme 0")
|
||||
field(SCAN, "1 second")
|
||||
field(PREC, "3")
|
||||
field(EGU, "A")
|
||||
}
|
||||
|
||||
##
|
||||
## Read the Error code
|
||||
##
|
||||
record(ai, "$(PREFIX)ErrCode") {
|
||||
field(DTYP, "stream")
|
||||
field(DESC, "Error Code")
|
||||
field(INP, "@slsvme.proto read($(NO),err) slsvme 0")
|
||||
field(SCAN, "1 second")
|
||||
field(PREC, "3")
|
||||
field(EGU, "A")
|
||||
}
|
||||
|
||||
##
|
||||
## Read the textual representation of the error.
|
||||
##
|
||||
record(stringin, "$(PREFIX)ErrText") {
|
||||
field(DTYP, "stream")
|
||||
field(INP, "@slsvme.proto readErrTxt($(NO)) slsvme 0")
|
||||
field(SCAN, "1 second")
|
||||
field(PINI, "YES")
|
||||
}
|
||||
|
||||
|
||||
##
|
||||
## Read the Current
|
||||
##
|
||||
record(ai, "$(PREFIX)CurRBV") {
|
||||
field(DTYP, "stream")
|
||||
field(DESC, "Low Current Limit")
|
||||
field(INP, "@slsvme.proto read($(NO),cur) slsvme 0")
|
||||
field(SCAN, "1 second")
|
||||
field(PREC, "3")
|
||||
field(EGU, "A")
|
||||
}
|
||||
|
||||
##
|
||||
## Set the current
|
||||
##
|
||||
record(ao, "$(PREFIX)CurSet") {
|
||||
field(DTYP, "stream")
|
||||
field(DESC, "Setpoint current")
|
||||
field(OUT, "@slsvme.proto write($(NO),cur) slsvme 0")
|
||||
field(PREC, "3")
|
||||
field(EGU, "A")
|
||||
}
|
||||
|
||||
##
|
||||
## Read power status of the magnet
|
||||
##
|
||||
record(bi, "$(PREFIX)PowerStatusRBV") {
|
||||
field(DESC, "Readback of the power status")
|
||||
field(DTYP, "stream")
|
||||
field(INP, "@slsvme.proto readonoff($(NO)) slsvme 0")
|
||||
field(SCAN, "1 second")
|
||||
field(ZNAM, "off")
|
||||
field(ONAM, "on")
|
||||
}
|
||||
|
||||
##
|
||||
## Set the power status
|
||||
##
|
||||
record(bo, "$(PREFIX)PowerStatus") {
|
||||
field(DESC, "Set the power status")
|
||||
field(DTYP, "stream")
|
||||
field(OUT, "@slsvme.proto setpower($(NO)) slsvme 0")
|
||||
field(ZNAM, "on")
|
||||
field(ONAM, "off")
|
||||
}
|
@ -4,4 +4,4 @@ set dir [pwd]
|
||||
|
||||
cd /usr/local/ioc
|
||||
|
||||
exec /usr/bin/tar czvf $dir/sinqepics.tgz modules/scaler modules/sinq modules/anc350 modules/autosave
|
||||
exec /usr/bin/tar czvf $dir/sinqepics.tgz modules/scaler modules/sinq modules/anc350
|
||||
|
@ -1,9 +0,0 @@
|
||||
record(asyn,"$(P)$(R)")
|
||||
{
|
||||
field(DTYP,"asynRecordDevice")
|
||||
field(PORT,"$(PORT)")
|
||||
field(ADDR,"$(ADDR)")
|
||||
field(OMAX,"$(OMAX)")
|
||||
field(IMAX,"$(IMAX)")
|
||||
}
|
||||
|
@ -1,24 +0,0 @@
|
||||
record(motor,"$(P)$(M)")
|
||||
{
|
||||
field(DESC,"$(DESC)")
|
||||
field(DTYP,"$(DTYP)")
|
||||
field(DIR,"$(DIR)")
|
||||
field(VELO,"$(VELO)")
|
||||
field(VMAX,"$(VMAX=0)")
|
||||
field(VBAS,"$(VBAS)")
|
||||
field(ACCL,"$(ACCL)")
|
||||
field(BDST,"$(BDST)")
|
||||
field(BVEL,"$(BVEL)")
|
||||
field(BACC,"$(BACC)")
|
||||
field(OUT,"@asyn($(PORT),$(ADDR))")
|
||||
field(MRES,"$(MRES)")
|
||||
field(PREC,"$(PREC)")
|
||||
field(EGU,"$(EGU)")
|
||||
field(DHLM,"$(DHLM)")
|
||||
field(DLLM,"$(DLLM)")
|
||||
field(INIT,"$(INIT)")
|
||||
field(TWV,"1")
|
||||
field(RDBD,"$(RDBD)")
|
||||
field(RTRY,"0")
|
||||
}
|
||||
|
@ -1,21 +0,0 @@
|
||||
grecord(motor,"$(P)$(M)")
|
||||
{
|
||||
field(DESC,"$(DESC)")
|
||||
field(DTYP,"$(DTYP)")
|
||||
field(DIR,"$(DIR)")
|
||||
field(VELO,"$(VELO)")
|
||||
field(VBAS,"$(VBAS)")
|
||||
field(ACCL,"$(ACCL)")
|
||||
field(BDST,"$(BDST)")
|
||||
field(BVEL,"$(BVEL)")
|
||||
field(BACC,"$(BACC)")
|
||||
field(OUT,"#C$(C) S$(S) @")
|
||||
field(MRES,"$(MRES)")
|
||||
field(PREC,"$(PREC)")
|
||||
field(EGU,"$(EGU)")
|
||||
field(DHLM,"$(DHLM)")
|
||||
field(DLLM,"$(DLLM)")
|
||||
field(INIT,"$(INIT)")
|
||||
field(TWV,"1")
|
||||
}
|
||||
|
@ -6,13 +6,4 @@ record(waveform, "$(P)$(M)-MsgTxt") {
|
||||
field(FTVL, "CHAR")
|
||||
field(NELM, "80")
|
||||
field(SCAN, "I/O Intr")
|
||||
}
|
||||
|
||||
record(ao,"$(P)m$(N)-Resolution"){
|
||||
field(DESC,"m$(N) Resolution")
|
||||
field(DOL,"$(P)m$(N).MRES CP MS")
|
||||
field(OMSL,"closed_loop")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(OUT,"@asyn($(PORT),$(N))MOTOR_RESOLUTION")
|
||||
field(PREC,"3")
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
# workaround over set position
|
||||
record(ao, "$(P)$(M)-SetPosition") {
|
||||
field(DTYP, "asynFloat64")
|
||||
field(OUT, "@asyn($(PORT),$(N),1) SET_MOTOR_POSITION")
|
||||
field(PINI, "YES")
|
||||
}
|
||||
|
||||
# enable axis
|
||||
record(longout, "$(P)$(M):Enable") {
|
||||
field(DTYP, "asynInt32")
|
||||
field(OUT, "@asyn($(PORT),$(N),1) ENABLE_AXIS")
|
||||
field(PINI, "YES")
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
record(motor,"$(P)$(M)")
|
||||
{
|
||||
field(DESC,"$(DESC)")
|
||||
field(DTYP,"$(DTYP)")
|
||||
field(DIR,"$(DIR)")
|
||||
field(VELO,"$(VELO)")
|
||||
field(VMAX,"$(VMAX=$(VELO))")
|
||||
field(VBAS,"$(VBAS)")
|
||||
field(ACCL,"$(ACCL)")
|
||||
field(BDST,"$(BDST)")
|
||||
field(BVEL,"$(BVEL)")
|
||||
field(BACC,"$(BACC)")
|
||||
field(OUT,"@asyn($(PORT),$(ADDR))")
|
||||
field(MRES,"$(MRES)")
|
||||
field(PREC,"$(PREC)")
|
||||
field(EGU,"$(EGU)")
|
||||
field(DHLM,"$(DHLM)")
|
||||
field(DLLM,"$(DLLM)")
|
||||
field(INIT,"$(INIT)")
|
||||
field(TWV,"1")
|
||||
field(RDBD,"$(RDBD)")
|
||||
}
|
||||
|
||||
|
||||
# The message text
|
||||
record(waveform, "$(P)$(M)-MsgTxt") {
|
||||
field(DTYP, "asynOctetRead")
|
||||
field(INP, "@asyn($(PORT),$(N),1) MOTOR_MESSAGE_TEXT")
|
||||
field(FTVL, "CHAR")
|
||||
field(NELM, "80")
|
||||
field(SCAN, "I/O Intr")
|
||||
}
|
||||
|
||||
# enable axis
|
||||
record(longout, "$(P)$(M):Enable") {
|
||||
field(DTYP, "asynInt32")
|
||||
field(OUT, "@asyn($(PORT),$(N),1) ENABLE_AXIS")
|
||||
field(PINI, "YES")
|
||||
}
|
||||
|
||||
# enable axis
|
||||
record(longin, "$(P)$(M):Enable_RBV") {
|
||||
field(DTYP, "asynInt32")
|
||||
field(INP, "@asyn($(PORT),$(N),1) AXIS_ENABLED")
|
||||
field(PINI, "YES")
|
||||
field(SCAN, "1 second")
|
||||
}
|
||||
|
||||
# reread encoder
|
||||
record(longout, "$(P)$(M):Reread_Encoder") {
|
||||
field(DTYP, "asynInt32")
|
||||
field(OUT, "@asyn($(PORT),$(N),1) REREAD_ENCODER_POSITION")
|
||||
field(PINI, "YES")
|
||||
}
|
||||
|
||||
# reread encoder
|
||||
record(longin, "$(P)$(M):Reread_Encoder_RBV") {
|
||||
field(DTYP, "asynInt32")
|
||||
field(INP, "@asyn($(PORT),$(N),1) REREAD_ENCODER_POSITION_RBV")
|
||||
field(PINI, "NO")
|
||||
field(SCAN, "1 second")
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ Mark Koennecke, May, August 2017
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
@ -29,111 +30,115 @@ Mark Koennecke, May, August 2017
|
||||
|
||||
#define IDLEPOLL 60
|
||||
|
||||
|
||||
/** Creates a new EL734Controller object.
|
||||
* \param[in] portName The name of the asyn port that will be created for this driver
|
||||
* \param[in] EL734PortName The name of the drvAsynSerialPort that was created previously to connect to the EL734 controller
|
||||
* \param[in] numAxes The number of axes that this controller supports
|
||||
*/
|
||||
* \param[in] portName The name of the asyn port that will be created for this driver
|
||||
* \param[in] EL734PortName The name of the drvAsynSerialPort that was created previously to connect to the EL734 controller
|
||||
* \param[in] numAxes The number of axes that this controller supports
|
||||
*/
|
||||
EL734Controller::EL734Controller(const char *portName, const char *EL734PortName, int numAxes)
|
||||
: SINQController(portName, EL734PortName, numAxes)
|
||||
: SINQController(portName, EL734PortName, numAxes)
|
||||
{
|
||||
int axis;
|
||||
asynStatus status;
|
||||
EL734Axis *pAxis;
|
||||
static const char *functionName = "EL734Controller::EL734Controller";
|
||||
|
||||
|
||||
/* Connect to EL734 controller */
|
||||
status = pasynOctetSyncIO->connect(EL734PortName, 0, &pasynUserController_, NULL);
|
||||
if (status)
|
||||
{
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s: cannot connect to EL734 controller\n",
|
||||
functionName);
|
||||
if (status) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s: cannot connect to EL734 controller\n",
|
||||
functionName);
|
||||
}
|
||||
pasynOctetSyncIO->setOutputEos(pasynUserController_, "\r", strlen("\r"));
|
||||
pasynOctetSyncIO->setInputEos(pasynUserController_, "\r", strlen("\r"));
|
||||
pasynOctetSyncIO->setOutputEos(pasynUserController_,"\r",strlen("\r"));
|
||||
pasynOctetSyncIO->setInputEos(pasynUserController_,"\r",strlen("\r"));
|
||||
|
||||
switchRemote();
|
||||
|
||||
for (axis = 0; axis < numAxes; axis++)
|
||||
{
|
||||
new EL734Axis(this, axis + 1);
|
||||
for (axis=0; axis<numAxes; axis++) {
|
||||
pAxis = new EL734Axis(this, axis+1);
|
||||
}
|
||||
|
||||
startPoller(1000. / 1000., IDLEPOLL, 2);
|
||||
startPoller(1000./1000., IDLEPOLL, 2);
|
||||
}
|
||||
|
||||
|
||||
/** Creates a new EL734Controller object.
|
||||
* Configuration command, called directly or from iocsh
|
||||
* \param[in] portName The name of the asyn port that will be created for this driver
|
||||
* \param[in] EL734PortName The name of the drvAsynIPPPort that was created previously to connect to the EL734 controller
|
||||
* \param[in] numAxes The number of axes that this controller supports
|
||||
*/
|
||||
* Configuration command, called directly or from iocsh
|
||||
* \param[in] portName The name of the asyn port that will be created for this driver
|
||||
* \param[in] EL734PortName The name of the drvAsynIPPPort that was created previously to connect to the EL734 controller
|
||||
* \param[in] numAxes The number of axes that this controller supports
|
||||
*/
|
||||
extern "C" int EL734CreateController(const char *portName, const char *EL734PortName, int numAxes)
|
||||
{
|
||||
EL734Controller *pEL734Controller = new EL734Controller(portName, EL734PortName, numAxes);
|
||||
EL734Controller *pEL734Controller
|
||||
= new EL734Controller(portName, EL734PortName, numAxes);
|
||||
pEL734Controller = NULL;
|
||||
return (asynSuccess);
|
||||
return(asynSuccess);
|
||||
}
|
||||
|
||||
/** Reports on status of the driver
|
||||
* \param[in] fp The file pointer on which report information will be written
|
||||
* \param[in] level The level of report detail desired
|
||||
*
|
||||
* If details > 0 then information is printed about each axis.
|
||||
* After printing controller-specific information it calls asynMotorController::report()
|
||||
*/
|
||||
* \param[in] fp The file pointer on which report information will be written
|
||||
* \param[in] level The level of report detail desired
|
||||
*
|
||||
* If details > 0 then information is printed about each axis.
|
||||
* After printing controller-specific information it calls asynMotorController::report()
|
||||
*/
|
||||
void EL734Controller::report(FILE *fp, int level)
|
||||
{
|
||||
fprintf(fp, "EL734 motor driver %s, numAxes=%d\n",
|
||||
this->portName, numAxes_);
|
||||
fprintf(fp, "EL734 motor driver %s, numAxes=%d\n",
|
||||
this->portName, numAxes_);
|
||||
|
||||
// Call the base class method
|
||||
asynMotorController::report(fp, level);
|
||||
}
|
||||
|
||||
/** Returns a pointer to an EL734Axis object.
|
||||
* Returns NULL if the axis number encoded in pasynUser is invalid.
|
||||
* \param[in] pasynUser asynUser structure that encodes the axis index number. */
|
||||
EL734Axis *EL734Controller::getAxis(asynUser *pasynUser)
|
||||
* Returns NULL if the axis number encoded in pasynUser is invalid.
|
||||
* \param[in] pasynUser asynUser structure that encodes the axis index number. */
|
||||
EL734Axis* EL734Controller::getAxis(asynUser *pasynUser)
|
||||
{
|
||||
return static_cast<EL734Axis *>(asynMotorController::getAxis(pasynUser));
|
||||
return static_cast<EL734Axis*>(asynMotorController::getAxis(pasynUser));
|
||||
}
|
||||
|
||||
/** Returns a pointer to an EL734Axis object.
|
||||
* Returns NULL if the axis number encoded in pasynUser is invalid.
|
||||
* \param[in] axisNo Axis index number. */
|
||||
EL734Axis *EL734Controller::getAxis(int axisNo)
|
||||
* Returns NULL if the axis number encoded in pasynUser is invalid.
|
||||
* \param[in] axisNo Axis index number. */
|
||||
EL734Axis* EL734Controller::getAxis(int axisNo)
|
||||
{
|
||||
return static_cast<EL734Axis *>(asynMotorController::getAxis(axisNo));
|
||||
return static_cast<EL734Axis*>(asynMotorController::getAxis(axisNo));
|
||||
}
|
||||
|
||||
void EL734Controller::switchRemote()
|
||||
{
|
||||
char command[COMLEN], reply[COMLEN];
|
||||
int status;
|
||||
size_t in, out;
|
||||
int reason;
|
||||
|
||||
strcpy(command, "RMT 1");
|
||||
pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
|
||||
reply, COMLEN, 1., &out, &in, &reason);
|
||||
strcpy(command, "ECHO 0");
|
||||
pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
|
||||
reply, COMLEN, 1., &out, &in, &reason);
|
||||
strcpy(command, "RMT 1");
|
||||
pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
|
||||
reply, COMLEN, 1., &out, &in, &reason);
|
||||
strcpy(command, "ECHO 0");
|
||||
pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
|
||||
reply, COMLEN, 1., &out, &in, &reason);
|
||||
strcpy(command,"RMT 1");
|
||||
status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
|
||||
reply,COMLEN, 1.,&out,&in,&reason);
|
||||
strcpy(command,"ECHO 0");
|
||||
status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
|
||||
reply,COMLEN, 1.,&out,&in,&reason);
|
||||
strcpy(command,"RMT 1");
|
||||
status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
|
||||
reply,COMLEN, 1.,&out,&in,&reason);
|
||||
strcpy(command,"ECHO 0");
|
||||
status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
|
||||
reply,COMLEN, 1.,&out,&in,&reason);
|
||||
}
|
||||
/**
|
||||
* send a command to the EL734 and read the reply. Do some error and controller
|
||||
* send a command to the EL734 and read the reply. Do some error and controller
|
||||
* issue fixing on the way
|
||||
* \param[in] command The command to send
|
||||
* \param[out] reply The controllers reply
|
||||
*/
|
||||
|
||||
asynStatus EL734Controller::transactController(int axisNo, char command[COMLEN], char reply[COMLEN])
|
||||
asynStatus EL734Controller::transactController(int axisNo,char command[COMLEN], char reply[COMLEN])
|
||||
{
|
||||
asynStatus status;
|
||||
size_t in, out, i;
|
||||
@ -142,71 +147,58 @@ asynStatus EL734Controller::transactController(int axisNo, char command[COMLEN],
|
||||
SINQAxis *axis = getAxis(axisNo);
|
||||
|
||||
pasynOctetSyncIO->flush(pasynUserController_);
|
||||
|
||||
|
||||
status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
|
||||
reply, COMLEN, 2., &out, &in, &reason);
|
||||
if (status != asynSuccess)
|
||||
{
|
||||
if (axis != NULL)
|
||||
{
|
||||
reply,COMLEN, 1.,&out,&in,&reason);
|
||||
if(status != asynSuccess){
|
||||
if(axis!= NULL){
|
||||
axis->updateMsgTxtFromDriver("Lost connection to motor controller");
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
/*
|
||||
check for the offline reply
|
||||
*/
|
||||
if (strstr(reply, "?LOC") != NULL)
|
||||
{
|
||||
if(strstr(reply,"?LOC") != NULL){
|
||||
switchRemote();
|
||||
return pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
|
||||
reply, COMLEN, 1., &out, &in, &reason);
|
||||
reply,COMLEN, 1.,&out,&in,&reason);
|
||||
}
|
||||
|
||||
/*
|
||||
check for echos. This means that the thing is offline.
|
||||
*/
|
||||
if (strstr(reply, "p ") != NULL || strstr(reply, "u ") != NULL || strstr(reply, "msr ") != NULL)
|
||||
{
|
||||
if(strstr(reply,"p ") != NULL || strstr(reply,"u ") != NULL || strstr(reply,"msr ") != NULL){
|
||||
switchRemote();
|
||||
return pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
|
||||
reply, COMLEN, 1., &out, &in, &reason);
|
||||
reply,COMLEN, 1.,&out,&in,&reason);
|
||||
}
|
||||
/*
|
||||
check for EL734 errors
|
||||
*/
|
||||
strcpy(myReply, reply);
|
||||
for (i = 0; i < strlen(reply); i++)
|
||||
{
|
||||
for(i = 0; i < strlen(reply); i++){
|
||||
myReply[i] = (char)tolower((int)reply[i]);
|
||||
}
|
||||
if (strstr(myReply, "?cmd") != NULL)
|
||||
{
|
||||
snprintf(errTxt, sizeof(errTxt), "Bad command %s at axis %d", command, axisNo);
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, errTxt);
|
||||
if (axis != NULL)
|
||||
{
|
||||
if(strstr(myReply,"?cmd") != NULL){
|
||||
snprintf(errTxt,sizeof(errTxt), "Bad command %s at axis %d", command, axisNo);
|
||||
errlogSevPrintf(errlogMajor, errTxt);
|
||||
if(axis!= NULL){
|
||||
axis->updateMsgTxtFromDriver(errTxt);
|
||||
}
|
||||
return asynError;
|
||||
}
|
||||
else if (strstr(myReply, "?par") != NULL)
|
||||
{
|
||||
snprintf(errTxt, sizeof(errTxt), "Bad parameter in command %s", command);
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, errTxt);
|
||||
if (axis != NULL)
|
||||
{
|
||||
} else if(strstr(myReply,"?par") != NULL){
|
||||
snprintf(errTxt,sizeof(errTxt), "Bad parameter in command %s", command);
|
||||
errlogSevPrintf(errlogMajor, errTxt);
|
||||
if(axis!= NULL){
|
||||
axis->updateMsgTxtFromDriver(errTxt);
|
||||
}
|
||||
return asynError;
|
||||
}
|
||||
else if (strstr(myReply, "?rng") != NULL)
|
||||
{
|
||||
snprintf(errTxt, sizeof(errTxt), "Parameter out of range in command %s", command);
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, errTxt);
|
||||
if (axis != NULL)
|
||||
{
|
||||
} else if(strstr(myReply,"?rng") != NULL){
|
||||
snprintf(errTxt,sizeof(errTxt), "Parameter out of range in command %s", command);
|
||||
errlogSevPrintf(errlogMajor, errTxt);
|
||||
if(axis!= NULL){
|
||||
axis->updateMsgTxtFromDriver(errTxt);
|
||||
}
|
||||
return asynError;
|
||||
@ -218,99 +210,51 @@ asynStatus EL734Controller::transactController(int axisNo, char command[COMLEN],
|
||||
// These are the EL734Axis methods
|
||||
|
||||
/** Creates a new EL734Axis object.
|
||||
* \param[in] pC Pointer to the EL734Controller to which this axis belongs.
|
||||
* \param[in] axisNo Index number of this axis, range 0 to pC->numAxes_-1.
|
||||
*
|
||||
* Initializes register numbers, etc.
|
||||
*/
|
||||
* \param[in] pC Pointer to the EL734Controller to which this axis belongs.
|
||||
* \param[in] axisNo Index number of this axis, range 0 to pC->numAxes_-1.
|
||||
*
|
||||
* Initializes register numbers, etc.
|
||||
*/
|
||||
EL734Axis::EL734Axis(EL734Controller *pC, int axisNo)
|
||||
: SINQAxis(pC, axisNo), pC_(pC)
|
||||
{
|
||||
char command[COMLEN], reply[COMLEN];
|
||||
asynStatus status;
|
||||
int count = 0;
|
||||
float low, high;
|
||||
|
||||
/*
|
||||
get the hardware limits from the controller
|
||||
*/
|
||||
sprintf(command, "H %d", axisNo_);
|
||||
status = pC_->transactController(axisNo_, command, reply);
|
||||
if (status == asynSuccess)
|
||||
{
|
||||
count = sscanf(reply, "%f %f", &low, &high);
|
||||
if (count >= 2)
|
||||
{
|
||||
pC_->setDoubleParam(axisNo_, pC_->motorLowLimit_, low);
|
||||
pC_->setDoubleParam(axisNo_, pC_->motorHighLimit_, high);
|
||||
callParamCallbacks();
|
||||
}
|
||||
else
|
||||
{
|
||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"Bad response - %s - requesting limits at axis %d", reply, axisNo_);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"Failed to read limits at axis %d", axisNo_);
|
||||
}
|
||||
|
||||
/*
|
||||
oredMSR contains the axis status from the previous poll. The initial value
|
||||
1 means that the axis is not moving and has no errors.
|
||||
*/
|
||||
oredMSR = 1;
|
||||
next_poll = -1;
|
||||
: SINQAxis(pC, axisNo), pC_(pC)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Reports on status of the axis
|
||||
* \param[in] fp The file pointer on which report information will be written
|
||||
* \param[in] level The level of report detail desired
|
||||
*
|
||||
* After printing device-specific information calls asynMotorAxis::report()
|
||||
*/
|
||||
* \param[in] fp The file pointer on which report information will be written
|
||||
* \param[in] level The level of report detail desired
|
||||
*
|
||||
* After printing device-specific information calls asynMotorAxis::report()
|
||||
*/
|
||||
void EL734Axis::report(FILE *fp, int level)
|
||||
{
|
||||
if (level > 0)
|
||||
{
|
||||
if (level > 0) {
|
||||
fprintf(fp, " axis %d\n",
|
||||
axisNo_);
|
||||
}
|
||||
|
||||
// Call the base class method
|
||||
// asynMotorAxis::report(fp, level);
|
||||
//asynMotorAxis::report(fp, level);
|
||||
}
|
||||
|
||||
|
||||
asynStatus EL734Axis::move(double position, int relative, double minVelocity, double maxVelocity, double acceleration)
|
||||
{
|
||||
asynStatus status;
|
||||
// static const char *functionName = "EL734Axis::move";
|
||||
//static const char *functionName = "EL734Axis::move";
|
||||
char command[COMLEN], reply[COMLEN];
|
||||
|
||||
// status = sendAccelAndVelocity(acceleration, maxVelocity);
|
||||
|
||||
errlogPrintf("minVelocity = %f, maxVelocity = %f\n", minVelocity, maxVelocity);
|
||||
|
||||
/*
|
||||
* set speed
|
||||
*/
|
||||
sprintf(command, "J %d %d", axisNo_, (int)maxVelocity);
|
||||
status = pC_->transactController(axisNo_, command, reply);
|
||||
|
||||
if (relative)
|
||||
{
|
||||
|
||||
if (relative) {
|
||||
position += this->position;
|
||||
}
|
||||
oredMSR = 0;
|
||||
homing = 0;
|
||||
errorReported = 0;
|
||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"Starting axis %d with destination %f", axisNo_, position / 1000);
|
||||
sprintf(command, "p %d %.3f", axisNo_, position / 1000.);
|
||||
status = pC_->transactController(axisNo_, command, reply);
|
||||
setIntegerParam(pC_->motorStatusProblem_, false);
|
||||
updateMsgTxtFromDriver("");
|
||||
sprintf(command, "p %d %.3f", axisNo_, position/1000.);
|
||||
status = pC_->transactController(axisNo_,command,reply);
|
||||
next_poll = -1;
|
||||
return status;
|
||||
}
|
||||
@ -318,66 +262,51 @@ asynStatus EL734Axis::move(double position, int relative, double minVelocity, do
|
||||
asynStatus EL734Axis::home(double minVelocity, double maxVelocity, double acceleration, int forwards)
|
||||
{
|
||||
asynStatus status;
|
||||
// static const char *functionName = "EL734Axis::home";
|
||||
//static const char *functionName = "EL734Axis::home";
|
||||
char command[COMLEN], reply[COMLEN];
|
||||
|
||||
// status = sendAccelAndVelocity(acceleration, maxVelocity);
|
||||
|
||||
setIntegerParam(pC_->motorStatusProblem_, false);
|
||||
updateMsgTxtFromDriver("");
|
||||
errorReported = 0;
|
||||
|
||||
sprintf(command, "R %d", axisNo_);
|
||||
homing = 1;
|
||||
next_poll = -1;
|
||||
status = pC_->transactController(axisNo_, command, reply);
|
||||
next_poll= -1;
|
||||
status = pC_->transactController(axisNo_,command,reply);
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus EL734Axis::moveVelocity(double minVelocity, double maxVelocity, double acceleration)
|
||||
{
|
||||
asynStatus status;
|
||||
// static const char *functionName = "EL734Axis::moveVelocity";
|
||||
//static const char *functionName = "EL734Axis::moveVelocity";
|
||||
char command[COMLEN], reply[COMLEN];
|
||||
|
||||
// asynPrint(pasynUser_, ASYN_TRACE_FLOW,
|
||||
// "%s: minVelocity=%f, maxVelocity=%f, acceleration=%f\n",
|
||||
// functionName, minVelocity, maxVelocity, acceleration);
|
||||
|
||||
|
||||
errorReported = 0;
|
||||
if (maxVelocity > 0.)
|
||||
{
|
||||
if (maxVelocity > 0.) {
|
||||
/* This is a positive move */
|
||||
sprintf(command, "FF %d", axisNo_);
|
||||
} else {
|
||||
/* This is a negative move */
|
||||
sprintf(command, "FB %d", axisNo_);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is a negative move */
|
||||
sprintf(command, "FB %d", axisNo_);
|
||||
}
|
||||
status = pC_->transactController(axisNo_, command, reply);
|
||||
setIntegerParam(pC_->motorStatusProblem_, false);
|
||||
updateMsgTxtFromDriver("");
|
||||
status = pC_->transactController(axisNo_,command,reply);
|
||||
next_poll = -1;
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus EL734Axis::stop(double acceleration)
|
||||
asynStatus EL734Axis::stop(double acceleration )
|
||||
{
|
||||
asynStatus status = asynSuccess;
|
||||
// static const char *functionName = "EL734Axis::stop";
|
||||
asynStatus status;
|
||||
//static const char *functionName = "EL734Axis::stop";
|
||||
char command[COMLEN], reply[COMLEN];
|
||||
bool moving = false;
|
||||
|
||||
this->poll(&moving);
|
||||
if (moving && errorReported == 0)
|
||||
{
|
||||
sprintf(command, "S %d", axisNo_);
|
||||
status = pC_->transactController(axisNo_, command, reply);
|
||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR, "Sent STOP on Axis %d\n", axisNo_);
|
||||
updateMsgTxtFromDriver("Axis interrupted");
|
||||
errorReported = 1;
|
||||
}
|
||||
sprintf(command, "S %d", axisNo_);
|
||||
status = pC_->transactController(axisNo_,command,reply);
|
||||
errlogPrintf("Sent STOP on Axis %d\n", axisNo_);
|
||||
updateMsgTxtFromDriver("Axis interrupted");
|
||||
|
||||
return status;
|
||||
}
|
||||
@ -385,11 +314,11 @@ asynStatus EL734Axis::stop(double acceleration)
|
||||
asynStatus EL734Axis::setPosition(double position)
|
||||
{
|
||||
asynStatus status;
|
||||
// static const char *functionName = "EL734Axis::setPosition";
|
||||
//static const char *functionName = "EL734Axis::setPosition";
|
||||
char command[COMLEN], reply[COMLEN];
|
||||
|
||||
sprintf(command, "U %d %f", axisNo_, position / 1000.);
|
||||
status = pC_->transactController(axisNo_, command, reply);
|
||||
sprintf(command, "P %d %f", axisNo_, position/1000.);
|
||||
status = pC_->transactController(axisNo_,command,reply);
|
||||
next_poll = -1;
|
||||
|
||||
return status;
|
||||
@ -397,8 +326,8 @@ asynStatus EL734Axis::setPosition(double position)
|
||||
|
||||
asynStatus EL734Axis::setClosedLoop(bool closedLoop)
|
||||
{
|
||||
// static const char *functionName = "EL734Axis::setClosedLoop";
|
||||
|
||||
//static const char *functionName = "EL734Axis::setClosedLoop";
|
||||
|
||||
/*
|
||||
This belongs into the Kingdom of Electronics.
|
||||
We do not do this.
|
||||
@ -408,188 +337,126 @@ asynStatus EL734Axis::setClosedLoop(bool closedLoop)
|
||||
}
|
||||
|
||||
/** Polls the axis.
|
||||
* This function reads the motor position, the limit status, the home status, the moving status,
|
||||
* and the drive power-on status.
|
||||
* It calls setIntegerParam() and setDoubleParam() for each item that it polls,
|
||||
* and then calls callParamCallbacks() at the end.
|
||||
* \param[out] moving A flag that is set indicating that the axis is moving (true) or done (false). */
|
||||
* This function reads the motor position, the limit status, the home status, the moving status,
|
||||
* and the drive power-on status.
|
||||
* It calls setIntegerParam() and setDoubleParam() for each item that it polls,
|
||||
* and then calls callParamCallbacks() at the end.
|
||||
* \param[out] moving A flag that is set indicating that the axis is moving (true) or done (false). */
|
||||
asynStatus EL734Axis::poll(bool *moving)
|
||||
{
|
||||
{
|
||||
int msr, count;
|
||||
float low, high;
|
||||
asynStatus comStatus = asynSuccess;
|
||||
asynStatus comStatus;
|
||||
char command[COMLEN], reply[COMLEN], errTxt[256];
|
||||
int driverError = 0;
|
||||
|
||||
|
||||
// protect against excessive polling
|
||||
if (time(NULL) < next_poll)
|
||||
{
|
||||
if(time(NULL) < next_poll){
|
||||
*moving = false;
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
// read hardware limits
|
||||
sprintf(command, "H %d", axisNo_);
|
||||
comStatus = pC_->transactController(axisNo_, command, reply);
|
||||
if (comStatus == asynSuccess)
|
||||
{
|
||||
count = sscanf(reply, "%f %f", &low, &high);
|
||||
if (count >= 2)
|
||||
{
|
||||
pC_->setDoubleParam(axisNo_, pC_->motorLowLimit_, low);
|
||||
pC_->setDoubleParam(axisNo_, pC_->motorHighLimit_, high);
|
||||
callParamCallbacks();
|
||||
}
|
||||
}
|
||||
|
||||
// Read the current motor position
|
||||
setIntegerParam(pC_->motorStatusProblem_, false);
|
||||
sprintf(command, "u %d", axisNo_);
|
||||
comStatus = pC_->transactController(axisNo_, command, reply);
|
||||
if (comStatus == asynError)
|
||||
{
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
goto skip;
|
||||
sprintf(command,"u %d", axisNo_);
|
||||
comStatus = pC_->transactController(axisNo_,command,reply);
|
||||
if(comStatus == asynError){
|
||||
driverError = 1;
|
||||
}
|
||||
if (strstr(reply, "*ES") != NULL)
|
||||
{
|
||||
if(comStatus) goto skip;
|
||||
if(strstr(reply,"*ES") != NULL){
|
||||
*moving = false;
|
||||
setIntegerParam(pC_->motorStatusDone_, true);
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
errorReported = 1;
|
||||
updateMsgTxtFromDriver("Emergency Stop Engaged");
|
||||
comStatus = asynError;
|
||||
driverError = 1;
|
||||
goto skip;
|
||||
}
|
||||
else if (strstr(reply, "?BSY") != NULL)
|
||||
{
|
||||
} else if(strstr(reply,"?BSY") != NULL){
|
||||
*moving = true;
|
||||
setIntegerParam(pC_->motorStatusDone_, false);
|
||||
updateMsgTxtFromDriver(NULL);
|
||||
goto skip;
|
||||
}
|
||||
count = sscanf(reply, "%lf", &position);
|
||||
if (count != 1)
|
||||
{
|
||||
if (!homing)
|
||||
{
|
||||
snprintf(errTxt, sizeof(errTxt), "Bad reply %s when reading position for %d", reply, axisNo_);
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
errorReported = 1;
|
||||
updateMsgTxtFromDriver(errTxt);
|
||||
comStatus = asynError;
|
||||
goto skip;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"Axis %d, reply %s, position %lf\n", axisNo_, reply, position);
|
||||
setDoubleParam(pC_->motorPosition_, position * 1000);
|
||||
// setDoubleParam(pC_->motorEncoderPosition_, position);
|
||||
count = sscanf(reply,"%lf", &position);
|
||||
if(count != 1) {
|
||||
snprintf(errTxt,sizeof(errTxt),"Bad reply %s when reading position for %d", reply, axisNo_);
|
||||
updateMsgTxtFromDriver(errTxt);
|
||||
comStatus = asynError;
|
||||
driverError =1;
|
||||
goto skip;
|
||||
}
|
||||
//errlogPrintf("Axis %d, reply %s, position %lf\n", axisNo_, reply, position);
|
||||
setDoubleParam(pC_->motorPosition_, position*1000);
|
||||
//setDoubleParam(pC_->motorEncoderPosition_, position);
|
||||
|
||||
|
||||
// Read the moving status of this motor
|
||||
sprintf(command, "msr %d", axisNo_);
|
||||
comStatus = pC_->transactController(axisNo_, command, reply);
|
||||
if (comStatus == asynError)
|
||||
{
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
goto skip;
|
||||
}
|
||||
sscanf(reply, "%x", &msr);
|
||||
|
||||
// errlogPrintf("Axis %d, reply %s, msr %d, oredmsr = %d, position = %lf\n",
|
||||
// axisNo_, reply, msr, oredMSR, position);
|
||||
|
||||
sprintf(command,"msr %d",axisNo_);
|
||||
comStatus = pC_->transactController(axisNo_,command,reply);
|
||||
if(comStatus) goto skip;
|
||||
sscanf(reply,"%x",&msr);
|
||||
// errlogPrintf("Axis %d, reply %s, msr %d, position = %lf\n",
|
||||
// axisNo_, reply, msr, position);
|
||||
oredMSR |= msr;
|
||||
if ((msr & 0x1) == 0)
|
||||
{
|
||||
if( (msr & 0x1) == 0){
|
||||
// done: check for trouble
|
||||
// errlogPrintf("Axis %d finished\n", axisNo_);
|
||||
*moving = false;
|
||||
setIntegerParam(pC_->motorStatusDone_, true);
|
||||
|
||||
next_poll = time(NULL) + IDLEPOLL;
|
||||
if (oredMSR & 0x10)
|
||||
{
|
||||
//errlogPrintf("Axis %d finished\n", axisNo_);
|
||||
next_poll = time(NULL)+IDLEPOLL;
|
||||
if(oredMSR & 0x10){
|
||||
setIntegerParam(pC_->motorStatusLowLimit_, true);
|
||||
updateMsgTxtFromDriver("Lower Limit Hit");
|
||||
errorReported = 1;
|
||||
comStatus = asynError;
|
||||
goto skip;
|
||||
}
|
||||
else
|
||||
{
|
||||
driverError = 1;
|
||||
} else {
|
||||
setIntegerParam(pC_->motorStatusLowLimit_, false);
|
||||
}
|
||||
if (oredMSR & 0x20)
|
||||
{
|
||||
if(oredMSR & 0x20){
|
||||
setIntegerParam(pC_->motorStatusHighLimit_, true);
|
||||
updateMsgTxtFromDriver("Upper Limit Hit");
|
||||
errorReported = 1;
|
||||
comStatus = asynError;
|
||||
goto skip;
|
||||
}
|
||||
else
|
||||
{
|
||||
driverError = 1;
|
||||
} else {
|
||||
setIntegerParam(pC_->motorStatusHighLimit_, false);
|
||||
}
|
||||
if (homing)
|
||||
{
|
||||
if(homing){
|
||||
setIntegerParam(pC_->motorStatusAtHome_, true);
|
||||
}
|
||||
if (oredMSR & 0x1000)
|
||||
{
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
// errlogPrintf("Detected air cushion error on %d", axisNo_);
|
||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR, "Air cushion problem on %d", axisNo_);
|
||||
updateMsgTxtFromDriver("Air cushion error");
|
||||
errorReported = 1;
|
||||
comStatus = asynError;
|
||||
goto skip;
|
||||
}
|
||||
if (oredMSR & 0x100)
|
||||
{
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR, "Run failure at %d", axisNo_);
|
||||
updateMsgTxtFromDriver("Run failure");
|
||||
comStatus = asynError;
|
||||
errorReported = 1;
|
||||
goto skip;
|
||||
}
|
||||
if (oredMSR & 0x400)
|
||||
{
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR, "Positioning failure at %d", axisNo_);
|
||||
updateMsgTxtFromDriver("Positioning failure");
|
||||
comStatus = asynError;
|
||||
errorReported = 1;
|
||||
goto skip;
|
||||
}
|
||||
if (oredMSR & 0x200 || oredMSR & 0x80)
|
||||
{
|
||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_WARNING, "Positioning fault at %d", axisNo_);
|
||||
}
|
||||
setIntegerParam(pC_->motorStatusProblem_, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(oredMSR &0x1000){
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
errlogSevPrintf(errlogMajor, "Air cushion problem on %d", axisNo_);
|
||||
updateMsgTxtFromDriver("Air cushion error");
|
||||
driverError = 1;
|
||||
}
|
||||
if(oredMSR &0x80){
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
errlogSevPrintf(errlogMajor, "Positioning fault at %d", axisNo_);
|
||||
updateMsgTxtFromDriver("Positioning fault");
|
||||
driverError = 1;
|
||||
}
|
||||
*moving = false;
|
||||
setIntegerParam(pC_->motorStatusDone_, true);
|
||||
//updateMsgTxtFromDriver("Believed to be on position");
|
||||
} else {
|
||||
*moving = true;
|
||||
next_poll = -1;
|
||||
setIntegerParam(pC_->motorStatusDone_, false);
|
||||
//updateMsgTxtFromDriver("Creeping");
|
||||
}
|
||||
|
||||
skip:
|
||||
skip:
|
||||
if(driverError == 0){
|
||||
updateMsgTxtFromDriver(NULL);
|
||||
}
|
||||
setIntegerParam(pC_->motorStatusProblem_, comStatus ? 1:0);
|
||||
callParamCallbacks();
|
||||
return comStatus;
|
||||
return comStatus ? asynError : asynSuccess;
|
||||
}
|
||||
|
||||
/** Code for iocsh registration */
|
||||
static const iocshArg EL734CreateControllerArg0 = {"Port name", iocshArgString};
|
||||
static const iocshArg EL734CreateControllerArg1 = {"EL734 port name", iocshArgString};
|
||||
static const iocshArg EL734CreateControllerArg2 = {"Number of axes", iocshArgInt};
|
||||
static const iocshArg *const EL734CreateControllerArgs[] = {&EL734CreateControllerArg0,
|
||||
&EL734CreateControllerArg1,
|
||||
&EL734CreateControllerArg2};
|
||||
static const iocshArg * const EL734CreateControllerArgs[] = {&EL734CreateControllerArg0,
|
||||
&EL734CreateControllerArg1,
|
||||
&EL734CreateControllerArg2};
|
||||
static const iocshFuncDef EL734CreateControllerDef = {"EL734CreateController", 3, EL734CreateControllerArgs};
|
||||
static void EL734CreateContollerCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
@ -601,7 +468,6 @@ static void EL734Register(void)
|
||||
iocshRegister(&EL734CreateControllerDef, EL734CreateContollerCallFunc);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
epicsExportRegistrar(EL734Register);
|
||||
extern "C" {
|
||||
epicsExportRegistrar(EL734Register);
|
||||
}
|
||||
|
@ -28,32 +28,33 @@ public:
|
||||
asynStatus setClosedLoop(bool closedLoop);
|
||||
|
||||
private:
|
||||
EL734Controller *pC_; /**< Pointer to the asynMotorController to which this axis belongs.
|
||||
* Abbreviated because it is used very frequently */
|
||||
EL734Controller *pC_; /**< Pointer to the asynMotorController to which this axis belongs.
|
||||
* Abbreviated because it is used very frequently */
|
||||
int oredMSR;
|
||||
double position;
|
||||
int homing;
|
||||
time_t next_poll;
|
||||
int errorReported;
|
||||
int ErrTxtIdx;
|
||||
|
||||
friend class EL734Controller;
|
||||
void forwardErrorTxt(EL734Axis *axis);
|
||||
|
||||
friend class EL734Controller;
|
||||
};
|
||||
|
||||
class EL734Controller : public SINQController
|
||||
{
|
||||
class EL734Controller : public SINQController {
|
||||
public:
|
||||
EL734Controller(const char *portName, const char *EL734PortName, int numAxes);
|
||||
|
||||
void report(FILE *fp, int level);
|
||||
EL734Axis *getAxis(asynUser *pasynUser);
|
||||
EL734Axis *getAxis(int axisNo);
|
||||
EL734Axis* getAxis(asynUser *pasynUser);
|
||||
EL734Axis* getAxis(int axisNo);
|
||||
|
||||
friend class EL734Axis;
|
||||
friend class EL734Axis;
|
||||
private:
|
||||
asynUser *pasynUserController_;
|
||||
|
||||
private:
|
||||
asynUser *pasynUserController_;
|
||||
asynStatus transactController(int axis, char command[COMLEN], char reply[COMLEN]);
|
||||
|
||||
asynStatus transactController(int axis, char command[COMLEN], char reply[COMLEN]);
|
||||
void switchRemote();
|
||||
|
||||
void switchRemote();
|
||||
};
|
||||
|
@ -1,679 +0,0 @@
|
||||
/*
|
||||
FILENAME... EuroMoveDriver.cpp
|
||||
USAGE... Motor driver support for the EuroMove motor controller from LLB.
|
||||
|
||||
This is a driver for the EuroMove motor controller from LLB. This device talks to us either via
|
||||
GPIB or USB. The controller is fairly simple. It can control quite a number of motors.
|
||||
|
||||
Reworked in 06/2021 to work with the Prologix GPIV-Ethernet converter
|
||||
|
||||
mark.koennecke@psi.ch
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <iocsh.h>
|
||||
#include <epicsThread.h>
|
||||
#include <errlog.h>
|
||||
|
||||
#include <asynOctetSyncIO.h>
|
||||
|
||||
#include "EuroMoveDriver.h"
|
||||
#include <epicsExport.h>
|
||||
|
||||
#define IDLEPOLL 60
|
||||
|
||||
/** Creates a new EuroMoveController object.
|
||||
* \param[in] portName The name of the asyn port that will be created for this driver
|
||||
* \param[in] EuroMovePortName The name of the drvAsynSerialPort that was created previously to connect to the EuroMove controller
|
||||
* \param[in] numAxes The number of axes that this controller supports
|
||||
*/
|
||||
EuroMoveController::EuroMoveController(const char *portName, const char *EuroMovePortName, int gpibAddr, int numAxis)
|
||||
: SINQController(portName, EuroMovePortName,numAxis+1)
|
||||
{
|
||||
asynStatus status;
|
||||
static const char *functionName = "EuroMoveController::EuroMoveController";
|
||||
size_t out, in;
|
||||
int reason;
|
||||
char command[80], reply[80];
|
||||
|
||||
/* Connect to EuroMove controller */
|
||||
status = pasynOctetSyncIO->connect(EuroMovePortName, 0, &pasynUserController_, NULL);
|
||||
if (status) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s: cannot connect to EuroMove controller\n",
|
||||
functionName);
|
||||
}
|
||||
const char *terminator = "\r\n";
|
||||
pasynOctetSyncIO->setOutputEos(pasynUserController_,terminator,strlen(terminator));
|
||||
const char *repTerminator = "\r";
|
||||
pasynOctetSyncIO->setInputEos(pasynUserController_,repTerminator,strlen(repTerminator));
|
||||
|
||||
/* Save gpib address and prepare addr string */
|
||||
this->gpibAddr = gpibAddr;
|
||||
snprintf(this->addrCommand,sizeof(addrCommand), "++addr %d", gpibAddr);
|
||||
|
||||
/*
|
||||
Configure the Prologix interface to our liking
|
||||
The thing sends no response on configuration commands
|
||||
*/
|
||||
strcpy(command,"++mode 1"); /* Make it a controller */
|
||||
status = pasynOctetSyncIO->write(pasynUserController_, command, strlen(command), 2, &out);
|
||||
strcpy(command,"++auto 1"); /* ask for response automatically */
|
||||
status = pasynOctetSyncIO->write(pasynUserController_, command, strlen(command), 2, &out);
|
||||
strcpy(command,"++eos 1"); /* CR */
|
||||
status = pasynOctetSyncIO->write(pasynUserController_, command, strlen(command), 2, &out);
|
||||
|
||||
|
||||
|
||||
for(int i = 0; i < numAxis; i++){
|
||||
new EuroMoveAxis(this, i+1);
|
||||
}
|
||||
startPoller(1000./1000., IDLEPOLL, 2);
|
||||
}
|
||||
|
||||
|
||||
/** Creates a new EuroMoveController object.
|
||||
* Configuration command, called directly or from iocsh
|
||||
* \param[in] portName The name of the asyn port that will be created for this driver
|
||||
* \param[in] EuroMovePortName The name of the drvAsynIPPPort that was created previously to connect to the EuroMove controller
|
||||
* \param[in] gpibAddr The address of the controller on the GPIB bus
|
||||
* \param[in] numAxes The number of axes that this controller supports
|
||||
*/
|
||||
extern "C" int EuroMoveCreateController(const char *portName, const char *EuroMovePortName, const int gpibAddr, const int numAxis)
|
||||
{
|
||||
new EuroMoveController(portName, EuroMovePortName, gpibAddr, numAxis);
|
||||
return(asynSuccess);
|
||||
}
|
||||
|
||||
/** Reports on status of the driver
|
||||
* \param[in] fp The file pointer on which report information will be written
|
||||
* \param[in] level The level of report detail desired
|
||||
*
|
||||
* If details > 0 then information is printed about each axis.
|
||||
* After printing controller-specific information it calls asynMotorController::report()
|
||||
*/
|
||||
void EuroMoveController::report(FILE *fp, int level)
|
||||
{
|
||||
fprintf(fp, "EuroMove motor driver %s, numAxes=%d\n",
|
||||
this->portName, numAxes_);
|
||||
|
||||
// Call the base class method
|
||||
asynMotorController::report(fp, level);
|
||||
}
|
||||
|
||||
/** Returns a pointer to an EuroMoveAxis object.
|
||||
* Returns NULL if the axis number encoded in pasynUser is invalid.
|
||||
* \param[in] pasynUser asynUser structure that encodes the axis index number. */
|
||||
EuroMoveAxis* EuroMoveController::getAxis(asynUser *pasynUser)
|
||||
{
|
||||
return static_cast<EuroMoveAxis*>(asynMotorController::getAxis(pasynUser));
|
||||
}
|
||||
|
||||
/** Returns a pointer to an EuroMoveAxis object.
|
||||
* Returns NULL if the axis number encoded in pasynUser is invalid.
|
||||
* \param[in] axisNo Axis index number. */
|
||||
EuroMoveAxis* EuroMoveController::getAxis(int axisNo)
|
||||
{
|
||||
return static_cast<EuroMoveAxis*>(asynMotorController::getAxis(axisNo));
|
||||
}
|
||||
|
||||
/**
|
||||
* send a command to the EuroMove and read the reply. Do test for errors.
|
||||
* \param[in] command The command to send
|
||||
* \param[out] reply The controllers reply
|
||||
*/
|
||||
|
||||
asynStatus EuroMoveController::transactController(int axisNo,char command[COMLEN], char reply[COMLEN])
|
||||
{
|
||||
asynStatus status;
|
||||
SINQAxis *axis = getAxis(axisNo);
|
||||
size_t out, in;
|
||||
int reason, errCode, lCode;
|
||||
char pDummy[50], lReply[50];
|
||||
const char *lCommand = {"L"};
|
||||
|
||||
|
||||
|
||||
pasynOctetSyncIO->flush(pasynUserController_);
|
||||
|
||||
/* set address first */
|
||||
status = pasynOctetSyncIO->write(pasynUserController_, this->addrCommand, strlen(this->addrCommand), 2, &out);
|
||||
if(status != asynSuccess){
|
||||
if(axis!= NULL){
|
||||
axis->updateMsgTxtFromDriver("Lost connection to motor controller");
|
||||
errlogPrintf("Lost connection to motor controller\n");
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/* now the actual command */
|
||||
status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
|
||||
reply,sizeof(reply), 10.,&out,&in,&reason);
|
||||
if(status != asynSuccess){
|
||||
if(axis!= NULL){
|
||||
axis->updateMsgTxtFromDriver("Lost connection to motor controller");
|
||||
errlogPrintf("Lost connection to motor controller\n");
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
if(strstr(reply,"ERROR") != NULL){
|
||||
sscanf((const char *)reply, "%s %d", pDummy, &errCode);
|
||||
switch(errCode){
|
||||
case 0:
|
||||
axis->updateMsgTxtFromDriver("Syntax error or parameter out of range");
|
||||
errlogPrintf("Syntax error or parameter out or range on %d\n", axisNo);
|
||||
break;
|
||||
case 1:
|
||||
axis->updateMsgTxtFromDriver("Timeout communicating with daughter board");
|
||||
errlogPrintf("Timeout communicating with daughter board on %d\n", axisNo);
|
||||
break;
|
||||
case 2:
|
||||
axis->updateMsgTxtFromDriver("This is not a drivable motor");
|
||||
errlogPrintf("This is not a drivable motor on %d\n", axisNo);
|
||||
break;
|
||||
case 3:
|
||||
axis->updateMsgTxtFromDriver("Encoder anomaly");
|
||||
errlogPrintf("Encoder anomaly on %d\n", axisNo);
|
||||
break;
|
||||
case 4:
|
||||
axis->updateMsgTxtFromDriver("Attempt to move across limit switch");
|
||||
errlogPrintf("Attempt to move across limit switch on %d\n", axisNo);
|
||||
break;
|
||||
case 5:
|
||||
axis->updateMsgTxtFromDriver("Badly configured relay system");
|
||||
errlogPrintf("Badly configured relay system on %d\n", axisNo);
|
||||
break;
|
||||
case 6:
|
||||
axis->updateMsgTxtFromDriver("Non valid backup");
|
||||
errlogPrintf("Invalid backup on %d\n", axisNo);
|
||||
break;
|
||||
case 7:
|
||||
axis->updateMsgTxtFromDriver("Backup failed");
|
||||
errlogPrintf("Backup failed on %d\n", axisNo);
|
||||
break;
|
||||
}
|
||||
return asynError;
|
||||
}
|
||||
|
||||
/*
|
||||
Test system status
|
||||
*/
|
||||
status = pasynOctetSyncIO->writeRead(pasynUserController_, lCommand, strlen(lCommand),
|
||||
lReply,sizeof(lReply), 1.,&out,&in,&reason);
|
||||
if(status != asynSuccess){
|
||||
if(axis!= NULL){
|
||||
axis->updateMsgTxtFromDriver("Lost connection to motor controller");
|
||||
errlogPrintf("Lost connection to motor controller\n");
|
||||
}
|
||||
return status;
|
||||
}
|
||||
sscanf(lReply, "%x", &lCode);
|
||||
//errlogPrintf("System status returned %s, converted to %d\n", lReply, lCode);
|
||||
if((lCode & 1) > 0){
|
||||
axis->updateMsgTxtFromDriver("Syntax error or impossible to execute");
|
||||
errlogPrintf("Syntax error or impossible to execute for %s on %d\n", command, axisNo);
|
||||
return asynError;
|
||||
}
|
||||
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
asynStatus EuroMoveController::writeFloat64(asynUser *pasynUser, epicsFloat64 value)
|
||||
{
|
||||
int function = pasynUser->reason;
|
||||
asynStatus status = asynError;
|
||||
EuroMoveAxis *pAxis = NULL;
|
||||
|
||||
static const char *functionName = "EuroMoveController::writeFloat64";
|
||||
|
||||
|
||||
pAxis = (EuroMoveAxis *)this->getAxis(pasynUser);
|
||||
if (!pAxis) {
|
||||
return asynError;
|
||||
}
|
||||
|
||||
|
||||
/* Set the parameter and readback in the parameter library. */
|
||||
status = pAxis->setDoubleParam(function, value);
|
||||
|
||||
errlogPrintf("%s, reason %d, value %f\n", functionName, function, value);
|
||||
|
||||
// TODO: somethign is really shitty here: lowLimit and highLimit cannot be on the command
|
||||
if (function == motorResolution_) {
|
||||
if(value > .0){
|
||||
pAxis->resolution = (int)(1./value);
|
||||
} else {
|
||||
pAxis->resolution = 1;
|
||||
}
|
||||
}
|
||||
|
||||
//Call base class method
|
||||
//This will handle callCallbacks even if the function was handled here.
|
||||
status = asynMotorController::writeFloat64(pasynUser, value);
|
||||
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
// These are the EuroMoveAxis methods
|
||||
|
||||
/** Creates a new EuroMoveAxis object.
|
||||
* \param[in] pC Pointer to the EuroMoveController to which this axis belongs.
|
||||
* \param[in] axisNo Index number of this axis, range 0 to pC->numAxes_-1.
|
||||
*
|
||||
* Initializes register numbers, etc.
|
||||
*/
|
||||
EuroMoveAxis::EuroMoveAxis(EuroMoveController *pC, int axisNo)
|
||||
: SINQAxis(pC, axisNo),
|
||||
pC_(pC)
|
||||
{
|
||||
motNo = axisNo;
|
||||
next_poll = -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Reports on status of the axis
|
||||
* \param[in] fp The file pointer on which report information will be written
|
||||
* \param[in] level The level of report detail desired
|
||||
*
|
||||
* After printing device-specific information calls asynMotorAxis::report()
|
||||
*/
|
||||
void EuroMoveAxis::report(FILE *fp, int level)
|
||||
{
|
||||
if (level > 0) {
|
||||
fprintf(fp, " axis %d\n",
|
||||
axisNo_);
|
||||
}
|
||||
asynMotorAxis::report(fp, level);
|
||||
}
|
||||
|
||||
|
||||
asynStatus EuroMoveAxis::move(double position, int relative, double minVelocity, double maxVelocity, double acceleration)
|
||||
{
|
||||
asynStatus status;
|
||||
//static const char *functionName = "EuroMoveAxis::move";
|
||||
char command[COMLEN], reply[COMLEN];
|
||||
|
||||
updateMsgTxtFromDriver("");
|
||||
|
||||
if (relative) {
|
||||
position += this->position;
|
||||
}
|
||||
homingStatus = HomeIdle;
|
||||
sprintf(command,"G%d=%d", motNo, (int)position);
|
||||
status = pC_->transactController(motNo,command,reply);
|
||||
next_poll = -1;
|
||||
targetPosition = (int)position;
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus EuroMoveAxis::home(double minVelocity, double maxVelocity, double acceleration, int forwards)
|
||||
{
|
||||
asynStatus status = asynSuccess;
|
||||
//static const char *functionName = "EuroMoveAxis::home";
|
||||
char command[COMLEN], reply[COMLEN];
|
||||
|
||||
/*
|
||||
The EuroMove controller does not have a built in homing mechanism. We simulate it by:
|
||||
|
||||
1). Running the motor in the appropriate end swicth at high speed
|
||||
2) Stepping back three units
|
||||
3) Run the motor again in the end switch at low speed for better accuracy
|
||||
4) Set the limit position with the <I> command
|
||||
|
||||
The state of this operation is maintained in the homingStatus variable
|
||||
*/
|
||||
homingDirection = forwards;
|
||||
homingStatus = HomeFastRun;
|
||||
if(homingDirection){
|
||||
sprintf(command,"H%d=03", motNo);
|
||||
} else {
|
||||
sprintf(command,"H%d=07", motNo);
|
||||
}
|
||||
|
||||
status = pC_->transactController(motNo,command,reply);
|
||||
next_poll = -1;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus EuroMoveAxis::moveVelocity(double minVelocity, double maxVelocity, double acceleration)
|
||||
{
|
||||
asynStatus status;
|
||||
double target;
|
||||
|
||||
//static const char *functionName = "EuroMoveAxis::moveVelocity";
|
||||
|
||||
// asynPrint(pasynUser_, ASYN_TRACE_FLOW,
|
||||
// "%s: minVelocity=%f, maxVelocity=%f, acceleration=%f\n",
|
||||
// functionName, minVelocity, maxVelocity, acceleration);
|
||||
|
||||
updateMsgTxtFromDriver("");
|
||||
|
||||
if (maxVelocity > 0.) {
|
||||
/* This is a positive move */
|
||||
pC_->getDoubleParam(axisNo_,pC_->motorHighLimit_,&target);
|
||||
} else {
|
||||
/* This is a negative move */
|
||||
pC_->getDoubleParam(axisNo_,pC_->motorLowLimit_,&target);
|
||||
}
|
||||
status = move(target,0,0,0,0);
|
||||
next_poll = -1;
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus EuroMoveAxis::sendStop()
|
||||
{
|
||||
asynStatus status;
|
||||
char command[COMLEN], reply[COMLEN];
|
||||
|
||||
sprintf(command, "B%d", motNo);
|
||||
status = pC_->transactController(axisNo_,command,reply);
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus EuroMoveAxis::stop(double acceleration )
|
||||
{
|
||||
asynStatus status;
|
||||
// static const char *functionName = "EuroMoveAxis::stop";
|
||||
|
||||
status = sendStop();
|
||||
errlogPrintf("Sent STOP on Axis %d\n", axisNo_);
|
||||
updateMsgTxtFromDriver("Axis interrupted");
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus EuroMoveAxis::setPosition(double position)
|
||||
{
|
||||
asynStatus status;
|
||||
//static const char *functionName = "EuroMoveAxis::setPosition";
|
||||
char command[COMLEN], reply[COMLEN];
|
||||
|
||||
errlogPrintf("EuroMoveAxis::setPosition called with %lf\n", position);
|
||||
|
||||
sprintf(command, "I%d=%d",motNo,(int)position);
|
||||
status = pC_->transactController(axisNo_,command,reply);
|
||||
next_poll = -1;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus EuroMoveAxis::setClosedLoop(bool closedLoop)
|
||||
{
|
||||
//static const char *functionName = "EuroMoveAxis::setClosedLoop";
|
||||
|
||||
/*
|
||||
This belongs into the Kingdom of Electronics.
|
||||
We do not do this.
|
||||
*/
|
||||
|
||||
return asynError;
|
||||
}
|
||||
|
||||
/** Polls the axis.
|
||||
* This function reads the motor position, the limit status, the home status, the moving status,
|
||||
* and the drive power-on status.
|
||||
* It calls setIntegerParam() and setDoubleParam() for each item that it polls,
|
||||
* and then calls callParamCallbacks() at the end.
|
||||
* \param[out] moving A flag that is set indicating that the axis is moving (true) or done (false). */
|
||||
asynStatus EuroMoveAxis::poll(bool *moving)
|
||||
{
|
||||
asynStatus comStatus = asynSuccess;
|
||||
char command[COMLEN], reply[COMLEN];
|
||||
unsigned int axStatus;
|
||||
double backStep, backPos, limit;
|
||||
|
||||
// protect against excessive polling
|
||||
if(time(NULL) < next_poll){
|
||||
*moving = false;
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
setIntegerParam(pC_->motorStatusProblem_, false);
|
||||
|
||||
/*
|
||||
read the current position
|
||||
*/
|
||||
sprintf(command,"A%d",motNo);
|
||||
comStatus = pC_->transactController(axisNo_,command,reply);
|
||||
if(comStatus == asynError) {
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
goto skip;
|
||||
}
|
||||
sscanf(reply,"%d",&position);
|
||||
setDoubleParam(pC_->motorPosition_,(double)position);
|
||||
|
||||
// Read the moving status of this motor
|
||||
sprintf(command,"E%d",motNo);
|
||||
comStatus = pC_->transactController(axisNo_,command,reply);
|
||||
if(comStatus == asynError){
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
goto skip;
|
||||
}
|
||||
|
||||
/* errlogPrintf("Axis %d, status reply %s, position %d\n", axisNo_, reply, position); */
|
||||
sscanf(reply, "%x", &axStatus);
|
||||
|
||||
if(homingStatus == HomeIdle){
|
||||
if((axStatus & 128) > 0) { // test bit 8
|
||||
*moving = true;
|
||||
next_poll = -1;
|
||||
setIntegerParam(pC_->motorStatusDone_, false);
|
||||
} else {
|
||||
*moving = false;
|
||||
next_poll = time(NULL)+IDLEPOLL;
|
||||
setIntegerParam(pC_->motorStatusDone_, true);
|
||||
}
|
||||
|
||||
/* Testing limit switches */
|
||||
if((axStatus & 2) > 0){ // bit 2
|
||||
if(targetPosition > position) {
|
||||
/*
|
||||
Error codition only when we wish to move further
|
||||
*/
|
||||
setIntegerParam(pC_->motorStatusHighLimit_, true);
|
||||
errlogPrintf("HighLimit detected on %d\n", motNo);
|
||||
updateMsgTxtFromDriver("On high limit switch");
|
||||
sendStop();
|
||||
}
|
||||
} else {
|
||||
setIntegerParam(pC_->motorStatusHighLimit_, false);
|
||||
}
|
||||
if((axStatus & 1) > 0){ // bit 1
|
||||
setIntegerParam(pC_->motorStatusLowLimit_, true);
|
||||
if(targetPosition < position) {
|
||||
/*
|
||||
Error treatment onlly when we want to go below the limits
|
||||
*/
|
||||
errlogPrintf("LowLimit detected on %d\n", motNo);
|
||||
sendStop();
|
||||
updateMsgTxtFromDriver("On low limit switch");
|
||||
}
|
||||
} else {
|
||||
setIntegerParam(pC_->motorStatusLowLimit_, false);
|
||||
}
|
||||
|
||||
/* there could be errors reported in the motor status */
|
||||
if((axStatus & 8) > 0){ // bit 4
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
updateMsgTxtFromDriver("Internal timeout detected");
|
||||
errlogPrintf("Internal timeout detected on %d\n", motNo);
|
||||
comStatus = asynError;
|
||||
}
|
||||
if((axStatus & 4) > 0){ // bit 3
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
updateMsgTxtFromDriver("Encoding anomaly");
|
||||
errlogPrintf("Encoding anomaly on %d\n", motNo);
|
||||
comStatus = asynError;
|
||||
}
|
||||
} else {
|
||||
next_poll = -1;
|
||||
setIntegerParam(pC_->motorStatusDone_, false);
|
||||
*moving = true;
|
||||
switch(homingStatus){
|
||||
case HomeIdle:
|
||||
// handled above: this is here to silence the compiler
|
||||
break;
|
||||
case HomeFastRun:
|
||||
// errlogPrintf("HomeFastRun\n");
|
||||
if(axStatus & 2 || axStatus & 1){
|
||||
sendStop();
|
||||
homingStatus = HomeFastStop;
|
||||
}
|
||||
break;
|
||||
case HomeFastStop:
|
||||
// errlogPrintf("HomeFastStop\n");
|
||||
if((axStatus & 128) == 0){
|
||||
backStep = 3 * resolution;
|
||||
if(homingDirection){
|
||||
backPos = position - backStep;
|
||||
} else {
|
||||
backPos = position + backStep;
|
||||
}
|
||||
sprintf(command,"G%d=%d", motNo, (int)backPos);
|
||||
comStatus = pC_->transactController(motNo,command,reply);
|
||||
if(comStatus == asynError){
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
updateMsgTxtFromDriver("Homing problem when back stepping");
|
||||
errlogPrintf("Homing problem when back stepping: %s not accepted\n", command);
|
||||
*moving = false;
|
||||
setIntegerParam(pC_->motorStatusAtHome_, true);
|
||||
homingStatus = HomeIdle;
|
||||
setIntegerParam(pC_->motorStatusDone_, true);
|
||||
goto skip;
|
||||
}
|
||||
usleep(200);
|
||||
homingStatus = HomeBackStep;
|
||||
}
|
||||
break;
|
||||
case HomeBackStep:
|
||||
//errlogPrintf("HomeBackStep\n");
|
||||
if((axStatus & 128) == 0){
|
||||
homingStatus = HomeSlowRun;
|
||||
if(homingDirection){
|
||||
sprintf(command,"H%d=01", motNo);
|
||||
} else {
|
||||
sprintf(command,"H%d=05", motNo);
|
||||
}
|
||||
comStatus = pC_->transactController(motNo,command,reply);
|
||||
if(comStatus == asynError){
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
updateMsgTxtFromDriver("Homing problem slow running");
|
||||
errlogPrintf("Homing problem when slow running: %s not accepted\n", command);
|
||||
*moving = false;
|
||||
setIntegerParam(pC_->motorStatusAtHome_, true);
|
||||
homingStatus = HomeIdle;
|
||||
setIntegerParam(pC_->motorStatusDone_, true);
|
||||
goto skip;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case HomeSlowRun:
|
||||
//errlogPrintf("HomeSlowRun\n");
|
||||
if(axStatus & 2 || axStatus & 1){
|
||||
sendStop();
|
||||
homingStatus = HomeSlowStop;
|
||||
}
|
||||
break;
|
||||
case HomeSlowStop:
|
||||
//errlogPrintf("HomeSlowStop\n");
|
||||
if((axStatus & 128) == 0) {
|
||||
if(homingDirection) {
|
||||
pC_->getDoubleParam(axisNo_,pC_->motorHighLimit_,&limit);
|
||||
} else {
|
||||
pC_->getDoubleParam(axisNo_,pC_->motorLowLimit_,&limit);
|
||||
}
|
||||
setPosition(limit);
|
||||
*moving = false;
|
||||
setIntegerParam(pC_->motorStatusDone_, true);
|
||||
next_poll = time(NULL)+IDLEPOLL;
|
||||
setIntegerParam(pC_->motorStatusDone_, true);
|
||||
setIntegerParam(pC_->motorStatusAtHome_, true);
|
||||
homingStatus = HomeIdle;
|
||||
setDoubleParam(pC_->motorPosition_,(double)limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
skip:
|
||||
callParamCallbacks();
|
||||
return comStatus;
|
||||
}
|
||||
|
||||
/** Code for configuring the motNo on axis **/
|
||||
extern "C" {
|
||||
asynStatus EuroMoveConfigureAxis(const char *euroMoveName, unsigned int axisNo, unsigned int motNo)
|
||||
{
|
||||
EuroMoveController *pC = NULL;
|
||||
EuroMoveAxis *pAxis = NULL;
|
||||
|
||||
pC = (EuroMoveController *)findAsynPortDriver(euroMoveName);
|
||||
if(!pC){
|
||||
errlogPrintf("%s driver not found", euroMoveName);
|
||||
return asynError;
|
||||
}
|
||||
pC->unlock();
|
||||
|
||||
pAxis = (EuroMoveAxis *)pC->getAxis(axisNo);
|
||||
if(!pAxis){
|
||||
errlogPrintf("axis %d driver not found on %s", axisNo, euroMoveName);
|
||||
return asynError;
|
||||
}
|
||||
pAxis->setMotNo(motNo);
|
||||
|
||||
return asynSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
static const iocshArg EuroMoveConfigArg0 = {"Port name", iocshArgString};
|
||||
static const iocshArg EuroMoveConfigArg1 = {"Axis Index", iocshArgInt};
|
||||
static const iocshArg EuroMoveConfigArg2 = {"Motor number in EuroMove", iocshArgInt};
|
||||
static const iocshArg * const EuroMoveConfigArgs[] = {&EuroMoveConfigArg0,
|
||||
&EuroMoveConfigArg1,
|
||||
&EuroMoveConfigArg2
|
||||
};
|
||||
static const iocshFuncDef EuroMoveConfigDef = {"EuroMoveConfigureAxis", 3, EuroMoveConfigArgs};
|
||||
static void EuroMoveConfigCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
EuroMoveConfigureAxis(args[0].sval, (unsigned int)args[1].ival, (unsigned int)args[2].ival);
|
||||
}
|
||||
|
||||
|
||||
/** Code for iocsh registration */
|
||||
static const iocshArg EuroMoveCreateControllerArg0 = {"Port name", iocshArgString};
|
||||
static const iocshArg EuroMoveCreateControllerArg1 = {"EuroMove port name", iocshArgString};
|
||||
static const iocshArg EuroMoveCreateControllerArg2 = {"GPIB Address", iocshArgInt};
|
||||
static const iocshArg EuroMoveCreateControllerArg3 = {"Number of axis", iocshArgInt};
|
||||
static const iocshArg * const EuroMoveCreateControllerArgs[] = {&EuroMoveCreateControllerArg0,
|
||||
&EuroMoveCreateControllerArg1,
|
||||
&EuroMoveCreateControllerArg2,
|
||||
&EuroMoveCreateControllerArg3
|
||||
};
|
||||
static const iocshFuncDef EuroMoveCreateControllerDef = {"EuroMoveCreateController", 4, EuroMoveCreateControllerArgs};
|
||||
static void EuroMoveCreateControllerCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
EuroMoveCreateController(args[0].sval, args[1].sval, args[2].ival, args[3].ival);
|
||||
}
|
||||
|
||||
static void EuroMoveRegister(void)
|
||||
{
|
||||
iocshRegister(&EuroMoveCreateControllerDef, EuroMoveCreateControllerCallFunc);
|
||||
iocshRegister(&EuroMoveConfigDef, EuroMoveConfigCallFunc);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
epicsExportRegistrar(EuroMoveRegister);
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
/*
|
||||
FILENAME... EuroMoveDriver.h
|
||||
USAGE... Motor driver support for the LLB EuroMove controller
|
||||
|
||||
Mark Koennecke
|
||||
January 2020
|
||||
|
||||
*/
|
||||
|
||||
#include "SINQController.h"
|
||||
#include "SINQAxis.h"
|
||||
|
||||
#define COMLEN 80
|
||||
|
||||
typedef enum {
|
||||
HomeIdle,
|
||||
HomeFastRun,
|
||||
HomeFastStop,
|
||||
HomeBackStep,
|
||||
HomeSlowRun,
|
||||
HomeSlowStop,
|
||||
} HomingStatus;
|
||||
|
||||
class EuroMoveAxis : public SINQAxis
|
||||
{
|
||||
public:
|
||||
/* These are the methods we override from the base class */
|
||||
EuroMoveAxis(class EuroMoveController *pC, int axis);
|
||||
void report(FILE *fp, int level);
|
||||
asynStatus move(double position, int relative, double min_velocity, double max_velocity, double acceleration);
|
||||
asynStatus moveVelocity(double min_velocity, double max_velocity, double acceleration);
|
||||
asynStatus home(double min_velocity, double max_velocity, double acceleration, int forwards);
|
||||
asynStatus stop(double acceleration);
|
||||
asynStatus poll(bool *moving);
|
||||
asynStatus setPosition(double position);
|
||||
asynStatus setClosedLoop(bool closedLoop);
|
||||
void setMotNo(unsigned int no){
|
||||
motNo = no;
|
||||
}
|
||||
|
||||
private:
|
||||
EuroMoveController *pC_; /**< Pointer to the asynMotorController to which this axis belongs.
|
||||
* Abbreviated because it is used very frequently */
|
||||
time_t next_poll;
|
||||
int motNo; // motor number in the EuroMove controller
|
||||
int position;
|
||||
HomingStatus homingStatus;
|
||||
int homingDirection; // 1 = forward, 0 backwards
|
||||
asynStatus sendStop();
|
||||
int resolution;
|
||||
friend class EuroMoveController;
|
||||
int targetPosition;
|
||||
};
|
||||
|
||||
class EuroMoveController : public SINQController {
|
||||
public:
|
||||
EuroMoveController(const char *portName, const char *EuroMovePortName, const int gpibAddr, const int nAxis);
|
||||
|
||||
void report(FILE *fp, int level);
|
||||
EuroMoveAxis* getAxis(asynUser *pasynUser);
|
||||
EuroMoveAxis* getAxis(int axisNo);
|
||||
asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value);
|
||||
|
||||
friend class EuroMoveAxis;
|
||||
private:
|
||||
asynUser *pasynUserController_;
|
||||
unsigned int gpibAddr;
|
||||
char addrCommand[50];
|
||||
|
||||
asynStatus transactController(int axisNo, char command[COMLEN], char reply[COMLEN]);
|
||||
|
||||
};
|
@ -28,7 +28,6 @@ sinqEPICS_SRCS += EL734Driver.cpp devScalerEL737.c pmacAsynIPPort.c SINQAxis.cpp
|
||||
sinqEPICS_SRCS += pmacController.cpp pmacAxis.cpp
|
||||
sinqEPICS_SRCS += NanotecDriver.cpp stptok.cpp
|
||||
sinqEPICS_SRCS += PhytronDriver.cpp
|
||||
sinqEPICS_SRCS += EuroMoveDriver.cpp
|
||||
|
||||
|
||||
# Build the main IOC entry point on workstation OSs.
|
||||
|
@ -1,954 +0,0 @@
|
||||
/*
|
||||
Driver for the MasterMACS motor controller used at SINQ
|
||||
For documentation see the standard SINQ place for hardware documentation or
|
||||
Marcel Schildt
|
||||
|
||||
Mark Koennecke, March-August 2023
|
||||
Mark Koenencke, More fixes in June 2024
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <iocsh.h>
|
||||
#include <epicsThread.h>
|
||||
#include <errlog.h>
|
||||
|
||||
#include <asynOctetSyncIO.h>
|
||||
|
||||
#include "MasterMACSDriver.h"
|
||||
#include <epicsExport.h>
|
||||
|
||||
#define CHECK_BIT(var,pos) ((var) & (1 << pos))
|
||||
#define ABS(x) (x < 0 ? -(x) : (x))
|
||||
|
||||
#define debug 0
|
||||
#define timeDebug 0
|
||||
|
||||
double DoubleTime(void)
|
||||
{
|
||||
struct timeval now;
|
||||
/* the resolution of this function is usec, if the machine supports this
|
||||
and the mantissa of a double is 51 bits or more (31 bits for seconds
|
||||
and 20 for microseconds)
|
||||
*/
|
||||
gettimeofday(&now, NULL);
|
||||
return now.tv_sec + now.tv_usec / 1e6;
|
||||
}
|
||||
|
||||
/** Creates a new MasterMACSController object.
|
||||
* \param[in] portName The name of the asyn port that will be created for this driver
|
||||
* \param[in] MasterMACSPortName The name of the drvAsynSerialPort that was created previously to connect to the MasterMACS controller
|
||||
* \param[in] numAxes The number of axes that this controller supports
|
||||
*/
|
||||
MasterMACSController::MasterMACSController(const char *portName,
|
||||
const char *MasterMACSPortName,
|
||||
int numAxes,
|
||||
int idlePoll, int busyPoll):SINQController
|
||||
(portName, MasterMACSPortName, numAxes)
|
||||
{
|
||||
asynStatus status;
|
||||
static const char *functionName =
|
||||
"MasterMACSController::MasterMACSController";
|
||||
char terminator[2] = "\x03";
|
||||
|
||||
|
||||
/* Connect to MasterMACS controller */
|
||||
status =
|
||||
pasynOctetSyncIO->connect(MasterMACSPortName, 0,
|
||||
&pasynUserController_, NULL);
|
||||
if (status) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s: cannot connect to MasterMACS controller\n",
|
||||
functionName);
|
||||
}
|
||||
pasynOctetSyncIO->setOutputEos(pasynUserController_, terminator,
|
||||
strlen(terminator));
|
||||
pasynOctetSyncIO->setInputEos(pasynUserController_, terminator,
|
||||
strlen(terminator));
|
||||
|
||||
|
||||
pAxes_ = (MasterMACSAxis **) (asynMotorController::pAxes_);
|
||||
createParam(EnableAxisString, asynParamInt32, &enableAxis_);
|
||||
createParam(AxisEnabledString, asynParamInt32, &axisEnabled_);
|
||||
callParamCallbacks();
|
||||
|
||||
startPoller(busyPoll/1000., idlePoll/1000., 1);
|
||||
setIdlePollPeriod(idlePoll/1000.);
|
||||
setMovingPollPeriod(busyPoll/1000.);
|
||||
}
|
||||
|
||||
|
||||
/** Creates a new MasterMACSController object.
|
||||
* Configuration command, called directly or from iocsh
|
||||
* \param[in] portName The name of the asyn port that will be created for this driver
|
||||
* \param[in] MasterMACSPortName The name of the drvAsynIPPPort that was created previously to connect to the MasterMACS controller
|
||||
* \param[in] numAxes The number of axes that this controller supports
|
||||
* \param[in] idlePoll Poll interval when idle in microseconds
|
||||
* \param[in] busyPoll Poll interval when moving in microSeconds
|
||||
*/
|
||||
extern "C" int
|
||||
MasterMACSCreateController(const char *portName,
|
||||
const char *MasterMACSPortName, int numAxes, int idlePoll, int busyPoll)
|
||||
{
|
||||
MasterMACSController *pMasterMACSController
|
||||
= new MasterMACSController(portName, MasterMACSPortName, numAxes, idlePoll, busyPoll);
|
||||
pMasterMACSController = NULL;
|
||||
return (asynSuccess);
|
||||
}
|
||||
|
||||
/** Reports on status of the driver
|
||||
* \param[in] fp The file pointer on which report information will be written
|
||||
* \param[in] level The level of report detail desired
|
||||
*
|
||||
* If details > 0 then information is printed about each axis.
|
||||
* After printing controller-specific information it calls asynMotorController::report()
|
||||
*/
|
||||
void
|
||||
MasterMACSController::report(FILE * fp, int level)
|
||||
{
|
||||
fprintf(fp, "MasterMACS motor driver %s, numAxes=%d\n",
|
||||
this->portName, numAxes_);
|
||||
|
||||
// Call the base class method
|
||||
asynMotorController::report(fp, level);
|
||||
}
|
||||
|
||||
/** Returns a pointer to an MasterMACSAxis object.
|
||||
* Returns NULL if the axis number encoded in pasynUser is invalid.
|
||||
* \param[in] pasynUser asynUser structure that encodes the axis index number. */
|
||||
MasterMACSAxis *MasterMACSController::getAxis(asynUser * pasynUser)
|
||||
{
|
||||
return static_cast <
|
||||
MasterMACSAxis * >(asynMotorController::getAxis(pasynUser));
|
||||
}
|
||||
|
||||
/** Returns a pointer to an MasterMACSAxis object.
|
||||
* Returns NULL if the axis number encoded in pasynUser is invalid.
|
||||
* \param[in] axisNo Axis index number. */
|
||||
MasterMACSAxis *MasterMACSController::getAxis(int axisNo)
|
||||
{
|
||||
return static_cast <
|
||||
MasterMACSAxis * >(asynMotorController::getAxis(axisNo));
|
||||
}
|
||||
|
||||
/**
|
||||
* send a command to the MasterMACS and read the reply. Do some error and controller
|
||||
* issue fixing on the way
|
||||
* \param[in] command The command to send
|
||||
* \param[out] reply The controllers reply
|
||||
*/
|
||||
|
||||
asynStatus
|
||||
MasterMACSController::transactController(int axisNo,
|
||||
char command[COMLEN],
|
||||
char reply[COMLEN])
|
||||
{
|
||||
asynStatus status;
|
||||
size_t in, out;
|
||||
int reason, len, idx, lenPayload;
|
||||
unsigned int i;
|
||||
double startTime, now;
|
||||
char *mmacsData =
|
||||
NULL, ackchar, mmacsResponse[COMLEN], hexResponse[256];
|
||||
SINQAxis *axis = getAxis(axisNo);
|
||||
|
||||
pasynOctetSyncIO->flush(pasynUserController_);
|
||||
|
||||
/* read with a short timeout in order to remove duplicate messages
|
||||
* from the line. This also serves to slow down communication
|
||||
*/
|
||||
pasynOctetSyncIO->read(pasynUserController_, mmacsResponse, 35, interMessageSleep/1000., &in, &reason);
|
||||
|
||||
/* pack data for MasterMACS */
|
||||
len = strlen(command) + 6;
|
||||
mmacsData = (char *) malloc(len * sizeof(char));
|
||||
if (!mmacsData) {
|
||||
errlogSevPrintf(errlogMajor,
|
||||
"Failed to allocate memory in MasterMACSController::transactController");
|
||||
return asynError;
|
||||
}
|
||||
mmacsData[0] = 0x05;
|
||||
mmacsData[1] = (char) (len - 2);
|
||||
mmacsData[2] = 0;
|
||||
mmacsData[3] = 0x19;
|
||||
memcpy(mmacsData + 4, command, strlen(command) * sizeof(char));
|
||||
mmacsData[len - 2] = 0x0D;
|
||||
/* 0x03 is appended by asyn */
|
||||
|
||||
/* send the stuff away ... */
|
||||
if(debug) {
|
||||
errlogSevPrintf(errlogMajor,"Sending command: %s\n", command);
|
||||
}
|
||||
|
||||
startTime = DoubleTime();
|
||||
status =
|
||||
pasynOctetSyncIO->writeRead(pasynUserController_, mmacsData,
|
||||
len - 1, mmacsResponse, 35, 20., &out,
|
||||
&in, &reason);
|
||||
|
||||
if(timeDebug) {
|
||||
now = DoubleTime();
|
||||
if((now - startTime) > 1.) {
|
||||
errlogSevPrintf(errlogMajor, "Unusual long response time %lf to command %s\n", (now - startTime), command);
|
||||
}
|
||||
}
|
||||
|
||||
if (status != asynSuccess) {
|
||||
if (axis != NULL) {
|
||||
errlogSevPrintf(errlogMajor,
|
||||
"Lost connection to motor controller,a axis %d, reason %d",
|
||||
axisNo, reason);
|
||||
axis->updateMsgTxtFromDriver
|
||||
("Lost connection to motor controller");
|
||||
return status;
|
||||
}
|
||||
errlogSevPrintf(errlogMajor,
|
||||
"Lost connection to motor controller without axis, reason %d",
|
||||
reason);
|
||||
return status;
|
||||
}
|
||||
free(mmacsData);
|
||||
|
||||
/* format and print the response in hex for debugging purposes */
|
||||
if(debug) {
|
||||
for(i = 0, idx = 0; i < in; i++){
|
||||
sprintf(hexResponse + idx, "%02x ", (unsigned int)mmacsResponse[i]);
|
||||
idx = strlen(hexResponse);
|
||||
}
|
||||
errlogSevPrintf(errlogMajor,"Reply in hex: %s\n", hexResponse);
|
||||
}
|
||||
|
||||
/* Here we have read the data from the MasterMACS. We proceed to extract
|
||||
* the payload and the state of the ACK byte and place that reply into data
|
||||
*/
|
||||
if ((in < 33)) {
|
||||
errlogSevPrintf(errlogMajor,
|
||||
"MasterMACS only sent %d bytes, 34 expected",
|
||||
(int) in);
|
||||
return asynError;
|
||||
}
|
||||
/*
|
||||
* Unpack the MasterMACS message, start by finding <CR>
|
||||
*/
|
||||
for (i = 4, idx = 0; i < 34; i++) {
|
||||
if (mmacsResponse[i] == 0x0d) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//errlogSevPrintf(errlogMajor, "Found <CR> at %d", idx);
|
||||
|
||||
/* one character before <CR> is the ACK, if it is there */
|
||||
ackchar = mmacsResponse[idx - 1];
|
||||
if (ackchar == 0x06) {
|
||||
strcpy(reply, "ACK:");
|
||||
} else if (ackchar == 0x15) {
|
||||
strcpy(reply, "NAK:");
|
||||
errlogSevPrintf(errlogMajor,
|
||||
"MasterMACS responded with NAK to %s\n", command);
|
||||
status = asynError;
|
||||
} else {
|
||||
/* the MasterMACS does not always send a ACK/NAK on read */
|
||||
strcpy(reply, "NON:");
|
||||
}
|
||||
//errlogSevPrintf(errlogMajor, "Reply after testing ACK byte: %s ", reply);
|
||||
|
||||
/* copy data */
|
||||
lenPayload = idx - 4;
|
||||
memcpy(reply + 4, mmacsResponse + 4, lenPayload);
|
||||
reply[4 + lenPayload] = (char) 0;
|
||||
if(debug) {
|
||||
errlogSevPrintf(errlogMajor, "Completed reply at end of transactController: %s ", reply);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------------------------*/
|
||||
asynStatus
|
||||
MasterMACSController::readInt32(asynUser * pasynUser,
|
||||
epicsInt32 * value)
|
||||
{
|
||||
|
||||
int function = pasynUser->reason;
|
||||
MasterMACSAxis *pAxis = NULL;
|
||||
int devStatus, isOn;
|
||||
|
||||
pAxis = (MasterMACSAxis *) (this->getAxis(pasynUser));
|
||||
if (!pAxis) {
|
||||
return asynError;
|
||||
}
|
||||
if (function == axisEnabled_) {
|
||||
devStatus = pAxis->readStatus();
|
||||
isOn = pAxis->isOn(devStatus);
|
||||
// errlogPrintf("isOn in readInt32: %d, devStatus = %d\n", isOn, devStatus);
|
||||
pAxis->setIntegerParam(enableAxis_, isOn);
|
||||
pAxis->setIntegerParam(axisEnabled_, isOn);
|
||||
*value = isOn;
|
||||
callParamCallbacks();
|
||||
return asynSuccess;
|
||||
}
|
||||
return asynMotorController::readInt32(pasynUser, value);
|
||||
}
|
||||
/*------------------------------------------------------------------------------------------*/
|
||||
|
||||
asynStatus
|
||||
MasterMACSController::writeInt32(asynUser * pasynUser,
|
||||
epicsInt32 value)
|
||||
{
|
||||
int function = pasynUser->reason;
|
||||
asynStatus status = asynSuccess;
|
||||
MasterMACSAxis *pAxis = NULL;
|
||||
char command[64] = { 0 };
|
||||
char response[64] = { 0 };
|
||||
int devStatus;
|
||||
bool moving;
|
||||
time_t startTime;
|
||||
|
||||
pAxis = (MasterMACSAxis *) this->getAxis(pasynUser);
|
||||
if (!pAxis) {
|
||||
return asynError;
|
||||
}
|
||||
|
||||
/* Set the parameter and readback in the parameter library. This may be
|
||||
* overwritten when we read back the status at the end, but that's OK */
|
||||
pAxis->setIntegerParam(function, value);
|
||||
|
||||
if(function == motorStop_){
|
||||
errlogPrintf("Stop called with value %d\n", value);
|
||||
double accel;
|
||||
getDoubleParam(pAxis->axisNo_, motorAccel_, &accel);
|
||||
status = pAxis->stop(accel);
|
||||
return status;
|
||||
}
|
||||
if (function == enableAxis_) {
|
||||
/*
|
||||
* Read the status in order to prevent execssive commands
|
||||
*/
|
||||
devStatus = pAxis->readStatus();
|
||||
if (value == 1 && !pAxis->isOn(devStatus) ) {
|
||||
/* download parameters, does not work as of now */
|
||||
/*
|
||||
sprintf(command, "%dS85=1.", pAxis->axisNo_);
|
||||
status = transactController(pAxis->axisNo_, command, response);
|
||||
*/
|
||||
|
||||
/* actually enable */
|
||||
sprintf(command, "%dS04=1", pAxis->axisNo_);
|
||||
status = transactController(pAxis->axisNo_, command, response);
|
||||
} else if(pAxis->isOn(devStatus)) {
|
||||
// only send command when necessary
|
||||
sprintf(command, "%dS04=0", pAxis->axisNo_);
|
||||
status = transactController(pAxis->axisNo_, command, response);
|
||||
} else {
|
||||
// nothing to do
|
||||
return status;
|
||||
}
|
||||
if (status == asynSuccess) {
|
||||
pAxis->updateMsgTxtFromDriver("");
|
||||
} else {
|
||||
errlogPrintf("MMACS: Failure to enable or disable axis %d",
|
||||
pAxis->axisNo_);
|
||||
}
|
||||
/*
|
||||
* wait max 2 seconds for success of the operation
|
||||
*/
|
||||
startTime = time(NULL);
|
||||
while(time(NULL) < startTime + 2.){
|
||||
// wait for the change to happen
|
||||
devStatus = pAxis->readStatus();
|
||||
// errlogPrintf("MMACS: switching enable: target, devStatus, isOn: %d, %d, %d\n", value, devStatus, pAxis->isOn(devStatus));
|
||||
if(pAxis->isOn(devStatus) == value){
|
||||
pAxis->active = true;
|
||||
pAxis->poll(&moving); // to update the Enable_RBV field
|
||||
pAxis->active = false;
|
||||
return asynSuccess;
|
||||
}
|
||||
usleep(200);
|
||||
}
|
||||
errlogPrintf("MMACS: Failed to dis/enable motor %d within 2 seconds\n", pAxis->axisNo_);
|
||||
}
|
||||
return asynMotorController::writeInt32(pasynUser, value);
|
||||
}
|
||||
|
||||
|
||||
// These are the MasterMACSAxis methods
|
||||
|
||||
/** Creates a new MasterMACSAxis object.
|
||||
* \param[in] pC Pointer to the MasterMACSController to which this axis belongs.
|
||||
* \param[in] axisNo Index number of this axis, range 0 to pC->numAxes_-1.
|
||||
*
|
||||
* Initializes register numbers, etc.
|
||||
*/
|
||||
MasterMACSAxis::MasterMACSAxis(MasterMACSController * pC, int axisNo):SINQAxis(pC, axisNo),
|
||||
pC_(pC)
|
||||
{
|
||||
hasStarted = false;
|
||||
active = false;
|
||||
errorCodeFound = 0;
|
||||
/*
|
||||
* Try to read the initial enable status of the motor
|
||||
*/
|
||||
int devStatus = readStatus();
|
||||
setIntegerParam(pC_->enableAxis_, isOn(devStatus));
|
||||
setIntegerParam(pC_->axisEnabled_, isOn(devStatus));
|
||||
lastPoll = -1;
|
||||
}
|
||||
|
||||
/** Reports on status of the axis
|
||||
* \param[in] fp The file pointer on which report information will be written
|
||||
* \param[in] level The level of report detail desired
|
||||
*
|
||||
* After printing device-specific information calls asynMotorAxis::report()
|
||||
*/
|
||||
void MasterMACSAxis::report(FILE * fp, int level)
|
||||
{
|
||||
if (level > 0) {
|
||||
fprintf(fp, " axis %d\n", axisNo_);
|
||||
}
|
||||
}
|
||||
|
||||
int MasterMACSAxis::readStatus()
|
||||
{
|
||||
char command[COMLEN], reply[COMLEN], *pPtr;
|
||||
float fval;
|
||||
int status;
|
||||
|
||||
/*
|
||||
* The MasterMACS sends invalid responses with a low frequency.
|
||||
* Therefore I send cached status responses in such a case in order
|
||||
* to help the logic everywhere else in the code.
|
||||
*/
|
||||
sprintf(command, "%dR10", axisNo_);
|
||||
status = pC_->transactController(axisNo_, command, reply);
|
||||
if (status == asynError) {
|
||||
return oldStatus;
|
||||
}
|
||||
pPtr = strstr(reply, "=");
|
||||
if(pPtr) {
|
||||
sscanf(pPtr + 1, "%f", &fval);
|
||||
oldStatus = (int) fval;
|
||||
return oldStatus;
|
||||
} else {
|
||||
errlogPrintf("MMACS: invalid status reponse %s on axis %d\n", reply, axisNo_);
|
||||
return oldStatus;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int MasterMACSAxis::isOn(int axisStatus)
|
||||
{
|
||||
if (CHECK_BIT(axisStatus, 0) && CHECK_BIT(axisStatus, 1)) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
asynStatus
|
||||
MasterMACSAxis::move(double position, int relative, double minVelocity,
|
||||
double maxVelocity, double acceleration)
|
||||
{
|
||||
asynStatus status = asynSuccess;
|
||||
char command[COMLEN], reply[COMLEN];
|
||||
int devStatus;
|
||||
|
||||
//errlogPrintf("minVelocity = %f, maxVelocity = %f\n", minVelocity, maxVelocity);
|
||||
memset(command, 0, COMLEN * sizeof(char));
|
||||
|
||||
/* clear motor error message */
|
||||
updateMsgTxtFromDriver("");
|
||||
|
||||
/*
|
||||
* reset error code
|
||||
*/
|
||||
if(errorCodeFound){
|
||||
sprintf(command, "%dS17=0", axisNo_);
|
||||
status = pC_->transactController(axisNo_, command, reply);
|
||||
errorCodeFound = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* only start if the thing is On
|
||||
*/
|
||||
devStatus = readStatus();
|
||||
|
||||
/*
|
||||
* set speed
|
||||
*/
|
||||
/* temporarily disabled in order to get the basic logic right
|
||||
sprintf(command, "%dS05=%f", axisNo_, maxVelocity / 1000);
|
||||
status = pC_->transactController(axisNo_, command, reply);
|
||||
*/
|
||||
|
||||
if (relative) {
|
||||
position += this->position;
|
||||
}
|
||||
|
||||
if(isOn(devStatus) && active == false) {
|
||||
errlogPrintf("Starting axis %d with destination %f\n", axisNo_,
|
||||
position / 1000.);
|
||||
|
||||
/* send target position */
|
||||
sprintf(command, "%dS02= %.3f", axisNo_, position / 1000.);
|
||||
status = pC_->transactController(axisNo_, command, reply);
|
||||
if (status == asynError) {
|
||||
errlogPrintf("MMACS: failed to set target on %d\n", axisNo_);
|
||||
updateMsgTxtFromDriver("Failed to send target position");
|
||||
return status;
|
||||
}
|
||||
|
||||
/* send move command */
|
||||
sprintf(command, "%dS00=1", axisNo_);
|
||||
status = pC_->transactController(axisNo_, command, reply);
|
||||
if (status == asynError) {
|
||||
errlogPrintf("MMACS: failed to start axis %d\n", axisNo_);
|
||||
updateMsgTxtFromDriver("Failed to start axis");
|
||||
return status;
|
||||
}
|
||||
hasStarted = true;
|
||||
homing = 0;
|
||||
active = true;
|
||||
usleep(500);
|
||||
lastPositionUpdate = time(NULL);
|
||||
} else {
|
||||
errlogPrintf("MMACS: axis %d disabled, cannot start\n", axisNo_);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus
|
||||
MasterMACSAxis::home(double minVelocity, double maxVelocity,
|
||||
double acceleration, int forwards)
|
||||
{
|
||||
asynStatus status;
|
||||
char command[COMLEN], reply[COMLEN];
|
||||
int devStatus;
|
||||
|
||||
memset(command, 0, COMLEN * sizeof(char));
|
||||
|
||||
/*
|
||||
* test if the thing is On
|
||||
*/
|
||||
devStatus = readStatus();
|
||||
updateMsgTxtFromDriver("");
|
||||
|
||||
if(isOn(devStatus)){
|
||||
sprintf(command, "%dS00=9", axisNo_);
|
||||
homing = 1;
|
||||
status = pC_->transactController(axisNo_, command, reply);
|
||||
hasStarted = true;
|
||||
active = true;
|
||||
lastPositionUpdate = time(NULL);
|
||||
return status;
|
||||
} else {
|
||||
errlogPrintf("MMACS: cannot home disabled axis %d\n", axisNo_);
|
||||
return asynError;
|
||||
}
|
||||
}
|
||||
|
||||
asynStatus
|
||||
MasterMACSAxis::moveVelocity(double minVelocity, double maxVelocity,
|
||||
double acceleration)
|
||||
{
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
errlogSevPrintf(errlogMajor,
|
||||
"This controller does not support the jog feature");
|
||||
return asynError;
|
||||
}
|
||||
|
||||
asynStatus MasterMACSAxis::stop(double acceleration)
|
||||
{
|
||||
asynStatus status = asynSuccess;
|
||||
char command[COMLEN], reply[COMLEN];
|
||||
int devStatus;
|
||||
|
||||
memset(command, 0, COMLEN * sizeof(char));
|
||||
|
||||
devStatus = readStatus();
|
||||
if(!CHECK_BIT(devStatus, 10)) {
|
||||
// only try to stop when running ...
|
||||
sprintf(command, "%dS00=8", axisNo_);
|
||||
status = pC_->transactController(axisNo_, command, reply);
|
||||
errlogPrintf("Sent STOP on Axis %d\n", axisNo_);
|
||||
updateMsgTxtFromDriver("Axis interrupted");
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus MasterMACSAxis::setPosition(double position)
|
||||
{
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
errlogSevPrintf(errlogMajor,
|
||||
"This controller does not support setting position");
|
||||
updateMsgTxtFromDriver("Controller does not support setPosition");
|
||||
return asynError;
|
||||
}
|
||||
|
||||
asynStatus MasterMACSAxis::setClosedLoop(bool closedLoop)
|
||||
{
|
||||
/*
|
||||
This belongs into the Kingdom of Electronics.
|
||||
We do not do this.
|
||||
*/
|
||||
|
||||
return asynError;
|
||||
}
|
||||
|
||||
/** Polls the axis.
|
||||
* This function reads the motor position, the limit status, the home status, the moving status,
|
||||
* and the drive power-on status.
|
||||
* It calls setIntegerParam() and setDoubleParam() for each item that it polls,
|
||||
* and then calls callParamCallbacks() at the end.
|
||||
* \param[out] moving A flag that is set indicating that the axis is moving (true) or done (false). */
|
||||
asynStatus MasterMACSAxis::poll(bool * moving)
|
||||
{
|
||||
asynStatus comStatus = asynSuccess;
|
||||
char command[COMLEN], reply[COMLEN], *pPtr, buffer[80];
|
||||
unsigned int errCode, derCode, devStatus = 0;
|
||||
float errStatus;
|
||||
struct tm* tm_info;
|
||||
time_t timer;
|
||||
|
||||
/*
|
||||
* EPICS always polls all motors on a controller when one motor is active.
|
||||
* In order to reduce load on the controller we check if we are active and
|
||||
* if not return old stuff
|
||||
*/
|
||||
if(active == false && time(NULL) < lastPoll + pC_->idlePollPeriod_) {
|
||||
*moving = false;
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
timer = time(NULL);
|
||||
tm_info = localtime(&timer);
|
||||
|
||||
strftime(buffer, 26, "%Y-%m-%d %H:%M:%S", tm_info);
|
||||
errlogPrintf("poll called at %s on axis %d \n",
|
||||
buffer, axisNo_ );
|
||||
lastPoll = time(NULL);
|
||||
|
||||
setIntegerParam(pC_->motorStatusProblem_, false);
|
||||
memset(command, 0, COMLEN * sizeof(char));
|
||||
|
||||
// Read the current motor position
|
||||
sprintf(command, "%dR12", axisNo_);
|
||||
comStatus = pC_->transactController(axisNo_, command, reply);
|
||||
if(comStatus != asynError) {
|
||||
pPtr = strstr(reply, "=");
|
||||
if(pPtr) {
|
||||
sscanf(pPtr + 1, "%lf", &position);
|
||||
setDoubleParam(pC_->motorPosition_, position * 1000.);
|
||||
setDoubleParam(pC_->motorEncoderPosition_, position * 1000.);
|
||||
/*
|
||||
* keep track of position in order to check for a stuck motor later
|
||||
*/
|
||||
if(ABS(position - oldPosition) > 1){
|
||||
oldPosition = position;
|
||||
lastPositionUpdate = time(NULL);
|
||||
}
|
||||
} else {
|
||||
errlogPrintf("MMACS: Invalid response asking position on %d\n", axisNo_);
|
||||
}
|
||||
} else {
|
||||
errlogPrintf("MMACS: communication problem reading axis %d position\n", axisNo_);
|
||||
*moving = false;
|
||||
comStatus = asynError;
|
||||
goto skip;
|
||||
}
|
||||
|
||||
// Read the overall status of this motor */
|
||||
devStatus = readStatus();
|
||||
if(debug || timeDebug) {
|
||||
errlogPrintf("Axis %d, position %lf, devStatus %d\n", axisNo_,
|
||||
position, devStatus);
|
||||
}
|
||||
|
||||
// Check for the thing being in a bad state
|
||||
if(CHECK_BIT(devStatus, 6)) {
|
||||
*moving = false;
|
||||
active = false;
|
||||
setIntegerParam(pC_->motorStatusDone_, true);
|
||||
updateMsgTxtFromDriver("AXIS dead");
|
||||
goto skip;
|
||||
}
|
||||
|
||||
|
||||
setIntegerParam(pC_->enableAxis_, isOn(devStatus));
|
||||
setIntegerParam(pC_->axisEnabled_, isOn(devStatus));
|
||||
|
||||
// Check if the motor is disabled
|
||||
if (!isOn(devStatus)) {
|
||||
updateMsgTxtFromDriver("Axis disabled");
|
||||
*moving = false;
|
||||
active = false;
|
||||
setIntegerParam(pC_->motorStatusDone_, true);
|
||||
goto skip;
|
||||
}
|
||||
|
||||
/*
|
||||
* if the motor has never run, the status bit 10 is invalid
|
||||
*/
|
||||
if (!hasStarted) {
|
||||
*moving = false;
|
||||
setIntegerParam(pC_->motorStatusDone_, true);
|
||||
active = false;
|
||||
goto skip;
|
||||
}
|
||||
|
||||
/*
|
||||
* We may have a valid status bit...
|
||||
*/
|
||||
if (!CHECK_BIT(devStatus, 10)) {
|
||||
/* we are still creeping along .... */
|
||||
*moving = true;
|
||||
setIntegerParam(pC_->motorStatusDone_, false);
|
||||
if(time(NULL) > lastPositionUpdate + 120) {
|
||||
// we are detecting a stuck motor
|
||||
errlogPrintf("MMACS: axis %d is STUCK!!\n", axisNo_);
|
||||
updateMsgTxtFromDriver("Axis STUCK!!");
|
||||
setIntegerParam(pC_->motorStatusDone_, true);
|
||||
*moving = false;
|
||||
active = false;
|
||||
}
|
||||
goto skip;
|
||||
}
|
||||
|
||||
|
||||
/*we are done moving */
|
||||
*moving = false;
|
||||
active = false;
|
||||
setIntegerParam(pC_->motorStatusDone_, true);
|
||||
updateMsgTxtFromDriver("");
|
||||
|
||||
/* when homing, set the proper flag */
|
||||
if (homing) {
|
||||
setIntegerParam(pC_->motorStatusAtHome_, true);
|
||||
}
|
||||
|
||||
/* check for limit switches*/
|
||||
setIntegerParam(pC_->motorStatusLowLimit_, false);
|
||||
setIntegerParam(pC_->motorStatusHighLimit_, false);
|
||||
if (CHECK_BIT(devStatus, 11)) {
|
||||
errlogSevPrintf(errlogMajor, "Limit bit in status code %d", axisNo_);
|
||||
/* guessing which limit has been hit ... */
|
||||
if (position > 0) {
|
||||
updateMsgTxtFromDriver("Hit positive limit switch");
|
||||
setIntegerParam(pC_->motorStatusHighLimit_, true);
|
||||
} else {
|
||||
updateMsgTxtFromDriver("Hit negative limit switch");
|
||||
setIntegerParam(pC_->motorStatusLowLimit_, true);
|
||||
}
|
||||
goto skip;
|
||||
}
|
||||
|
||||
/* check for error conditions */
|
||||
if (CHECK_BIT(devStatus, 3)) {
|
||||
/* read error codes */
|
||||
sprintf(command, "%dR11", axisNo_);
|
||||
comStatus = pC_->transactController(axisNo_, command, reply);
|
||||
if (comStatus != asynError) {
|
||||
pPtr = strstr(reply, "=");
|
||||
if(pPtr) {
|
||||
sscanf(pPtr + 1, "%f", &errStatus);
|
||||
errCode = (unsigned int) errStatus;
|
||||
|
||||
} else {
|
||||
errlogPrintf("MMACS: axis %d received invalid reply asking for error code \n", axisNo_);
|
||||
errCode = 0;
|
||||
goto skip;
|
||||
}
|
||||
} else {
|
||||
errlogPrintf("MMACS: axis %d failed reading error code \n", axisNo_);
|
||||
goto skip;
|
||||
}
|
||||
|
||||
sprintf(command, "%dR18", axisNo_);
|
||||
comStatus = pC_->transactController(axisNo_, command, reply);
|
||||
if (comStatus != asynError) {
|
||||
pPtr = strstr(reply, "=");
|
||||
if(pPtr) {
|
||||
sscanf(pPtr + 1, "%f", &errStatus);
|
||||
derCode = (unsigned int) errStatus;
|
||||
} else {
|
||||
errlogPrintf("MMACS: malformed reply for R18: %s, on axis %d\n", reply, axisNo_);
|
||||
derCode = 0;
|
||||
goto skip;
|
||||
}
|
||||
} else {
|
||||
errlogPrintf("MMACS: axis %d failed reading extended error code R18 \n", axisNo_);
|
||||
goto skip;
|
||||
}
|
||||
|
||||
if(debug) {
|
||||
errlogPrintf("Axis %d, errCode(R11) %d, derCode(R18) %d\n", axisNo_,
|
||||
errCode, derCode);
|
||||
}
|
||||
|
||||
if (errCode == 0) {
|
||||
errlogSevPrintf(errlogMajor,
|
||||
"Fault bit in status code, but no error code on %d\n", axisNo_);
|
||||
updateMsgTxtFromDriver ("Fault bit in status code without error code");
|
||||
goto skip;
|
||||
}
|
||||
errorCodeFound = 1;
|
||||
|
||||
if (CHECK_BIT(errCode, 0)) {
|
||||
errlogSevPrintf(errlogMajor, "CAN error on %d", axisNo_);
|
||||
updateMsgTxtFromDriver("CAN error");
|
||||
} else if (CHECK_BIT(errCode, 1)) {
|
||||
errlogSevPrintf(errlogMajor, "Short circuit on %d", axisNo_);
|
||||
updateMsgTxtFromDriver("Short circuit");
|
||||
} else if (CHECK_BIT(errCode, 2)) {
|
||||
errlogSevPrintf(errlogMajor, "Invalide Setup on %d", axisNo_);
|
||||
updateMsgTxtFromDriver("Invalid Setup");
|
||||
} else if (CHECK_BIT(errCode, 3)) {
|
||||
errlogSevPrintf(errlogMajor, "Control error on %d", axisNo_);
|
||||
updateMsgTxtFromDriver("Control error");
|
||||
} else if (CHECK_BIT(errCode, 4)) {
|
||||
errlogSevPrintf(errlogMajor, "CAN communication error on %d",
|
||||
axisNo_);
|
||||
updateMsgTxtFromDriver("CAN communication error");
|
||||
} else if (CHECK_BIT(errCode, 5)) {
|
||||
errlogSevPrintf(errlogMajor, "Feedback error on %d", axisNo_);
|
||||
updateMsgTxtFromDriver("Feedback error");
|
||||
} else if (CHECK_BIT(errCode, 6)) {
|
||||
updateMsgTxtFromDriver("Hit positive limit switch");
|
||||
setIntegerParam(pC_->motorStatusHighLimit_, true);
|
||||
setIntegerParam(pC_->motorStatusProblem_, false);
|
||||
} else if (CHECK_BIT(errCode, 7)) {
|
||||
updateMsgTxtFromDriver("Hit negative limit switch");
|
||||
setIntegerParam(pC_->motorStatusLowLimit_, true);
|
||||
setIntegerParam(pC_->motorStatusProblem_, false);
|
||||
} else if (CHECK_BIT(errCode, 8)) {
|
||||
errlogSevPrintf(errlogMajor, "Over current %d", axisNo_);
|
||||
updateMsgTxtFromDriver("Over current");
|
||||
} else if (CHECK_BIT(errCode, 9)) {
|
||||
errlogSevPrintf(errlogMajor, "I2T protection on %d", axisNo_);
|
||||
updateMsgTxtFromDriver("I2t protection");
|
||||
} else if (CHECK_BIT(errCode, 10)) {
|
||||
errlogSevPrintf(errlogMajor, "Over heated motor on %d", axisNo_);
|
||||
updateMsgTxtFromDriver("Motor overheated");
|
||||
} else if (CHECK_BIT(errCode, 11)) {
|
||||
errlogSevPrintf(errlogMajor, "Over temperature drive on %d",
|
||||
axisNo_);
|
||||
updateMsgTxtFromDriver("Over temperature drive");
|
||||
} else if (CHECK_BIT(errCode, 12)) {
|
||||
errlogSevPrintf(errlogMajor, "Over voltage on %d", axisNo_);
|
||||
updateMsgTxtFromDriver("Over voltage");
|
||||
} else if (CHECK_BIT(errCode, 13)) {
|
||||
errlogSevPrintf(errlogMajor, "Under voltage on %d", axisNo_);
|
||||
updateMsgTxtFromDriver("Under voltage");
|
||||
} else if (CHECK_BIT(errCode, 14)) {
|
||||
errlogSevPrintf(errlogMajor, "Command error on %d", axisNo_);
|
||||
updateMsgTxtFromDriver("Command error");
|
||||
} else if (CHECK_BIT(errCode, 15)) {
|
||||
errlogSevPrintf(errlogMajor, "Motor disabled on %d", axisNo_);
|
||||
updateMsgTxtFromDriver("Motor disabled");
|
||||
}
|
||||
}
|
||||
|
||||
skip:
|
||||
callParamCallbacks();
|
||||
return comStatus;
|
||||
}
|
||||
|
||||
/** Code for iocsh registration */
|
||||
static const iocshArg
|
||||
MasterMACSCreateControllerArg0 = { "Port name", iocshArgString };
|
||||
|
||||
static const iocshArg
|
||||
MasterMACSCreateControllerArg1 =
|
||||
{ "MasterMACS port name", iocshArgString };
|
||||
|
||||
static const iocshArg
|
||||
MasterMACSCreateControllerArg2 = { "Number of axes", iocshArgInt };
|
||||
|
||||
static const iocshArg
|
||||
MasterMACSCreateControllerArg3 = { "idlePoll", iocshArgInt };
|
||||
|
||||
static const iocshArg
|
||||
MasterMACSCreateControllerArg4 = { "busyPoll", iocshArgInt };
|
||||
|
||||
|
||||
static const iocshArg *const
|
||||
MasterMACSCreateControllerArgs[] = { &MasterMACSCreateControllerArg0,
|
||||
&MasterMACSCreateControllerArg1,
|
||||
&MasterMACSCreateControllerArg2,
|
||||
&MasterMACSCreateControllerArg3,
|
||||
&MasterMACSCreateControllerArg4
|
||||
};
|
||||
|
||||
static const iocshFuncDef
|
||||
MasterMACSCreateControllerDef =
|
||||
{ "MasterMACSCreateController", 5, MasterMACSCreateControllerArgs };
|
||||
static void MasterMACSCreateContollerCallFunc(const iocshArgBuf * args)
|
||||
{
|
||||
MasterMACSCreateController(args[0].sval, args[1].sval, args[2].ival,
|
||||
args[3].ival, args[4].ival);
|
||||
}
|
||||
|
||||
/**
|
||||
* C wrapper for the MasterMACSAxis constructor.
|
||||
* See MasterMAXSAxis::MasterMACSAxis.
|
||||
*
|
||||
*/
|
||||
asynStatus MasterMACSCreateAxis(const char *MasterMACSPort, /* specify which controller by port name */
|
||||
int axis)
|
||||
{ /* axis number (start from 1). */
|
||||
MasterMACSController *pC;
|
||||
MasterMACSAxis *pAxis;
|
||||
|
||||
static const char *functionName = "MasterMACSCreateAxis";
|
||||
|
||||
pC = (MasterMACSController *) findAsynPortDriver(MasterMACSPort);
|
||||
if (!pC) {
|
||||
printf("%s:%s: Error port %s not found\n", "MasterMACSDriver",
|
||||
functionName, MasterMACSPort);
|
||||
return asynError;
|
||||
}
|
||||
|
||||
pC->lock();
|
||||
pAxis = new MasterMACSAxis(pC, axis);
|
||||
pAxis = NULL;
|
||||
pC->unlock();
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
/* MasterMACSCreateAxis */
|
||||
static const iocshArg
|
||||
MasterMACSCreateAxisArg0 = { "Controller port name", iocshArgString };
|
||||
|
||||
static const iocshArg
|
||||
MasterMACSCreateAxisArg1 = { "Axis number", iocshArgInt };
|
||||
|
||||
static const iocshArg *const
|
||||
MasterMACSCreateAxisArgs[] = { &MasterMACSCreateAxisArg0,
|
||||
&MasterMACSCreateAxisArg1
|
||||
};
|
||||
|
||||
static const iocshFuncDef
|
||||
configMasterMACSAxis =
|
||||
{ "MasterMACSCreateAxis", 2, MasterMACSCreateAxisArgs };
|
||||
|
||||
static void configMasterMACSAxisCallFunc(const iocshArgBuf * args)
|
||||
{
|
||||
MasterMACSCreateAxis(args[0].sval, args[1].ival);
|
||||
}
|
||||
|
||||
static void MasterMACSRegister(void)
|
||||
{
|
||||
iocshRegister(&MasterMACSCreateControllerDef,
|
||||
MasterMACSCreateContollerCallFunc);
|
||||
iocshRegister(&configMasterMACSAxis, configMasterMACSAxisCallFunc);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
epicsExportRegistrar(MasterMACSRegister);
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
/*
|
||||
Driver for the MasterMACS motor controllers used at SINQ.
|
||||
For documentation see the standard manuals area for SINQ or
|
||||
Marcel Schildt.
|
||||
|
||||
The MasterMACS has a special line protocol which is implemented in
|
||||
drvAsynMMACSPort.c. The driver will not work with a standard asyn IPPort,
|
||||
only with the special one.
|
||||
|
||||
Mark Koennecke, March, August, 2023
|
||||
*/
|
||||
|
||||
#include "SINQController.h"
|
||||
#include "SINQAxis.h"
|
||||
|
||||
#define COMLEN 50
|
||||
|
||||
class MasterMACSAxis : public SINQAxis
|
||||
{
|
||||
public:
|
||||
/* These are the methods we override from the base class */
|
||||
MasterMACSAxis(class MasterMACSController *pC, int axis);
|
||||
void report(FILE *fp, int level);
|
||||
asynStatus move(double position, int relative, double min_velocity, double max_velocity, double acceleration);
|
||||
asynStatus moveVelocity(double min_velocity, double max_velocity, double acceleration);
|
||||
asynStatus home(double min_velocity, double max_velocity, double acceleration, int forwards);
|
||||
asynStatus stop(double acceleration);
|
||||
asynStatus poll(bool *moving);
|
||||
asynStatus setPosition(double position);
|
||||
asynStatus setClosedLoop(bool closedLoop);
|
||||
|
||||
private:
|
||||
MasterMACSController *pC_; /**< Pointer to the asynMotorController to which this axis belongs.
|
||||
* Abbreviated because it is used very frequently */
|
||||
double position;
|
||||
double oldPosition;
|
||||
time_t lastPositionUpdate;
|
||||
int homing;
|
||||
int hasStarted; /* The motor status is invalid if the thing has not run once */
|
||||
int isOn(int axisStatus);
|
||||
int readStatus();
|
||||
int errorCodeFound;
|
||||
int oldStatus;
|
||||
|
||||
bool active;
|
||||
time_t lastPoll;
|
||||
|
||||
friend class MasterMACSController;
|
||||
};
|
||||
|
||||
|
||||
#define EnableAxisString "ENABLE_AXIS"
|
||||
#define AxisEnabledString "AXIS_ENABLED"
|
||||
|
||||
class MasterMACSController : public SINQController {
|
||||
public:
|
||||
MasterMACSController(const char *portName, const char *MasterMACSPortName,
|
||||
int numAxes, int idlePoll, int busyPoll);
|
||||
|
||||
void report(FILE *fp, int level);
|
||||
MasterMACSAxis* getAxis(asynUser *pasynUser);
|
||||
MasterMACSAxis* getAxis(int axisNo);
|
||||
|
||||
// overloaded because we want to enable/disable the motor
|
||||
asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value);
|
||||
asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
|
||||
|
||||
friend class MasterMACSAxis;
|
||||
private:
|
||||
asynUser *pasynUserController_;
|
||||
MasterMACSAxis **pAxes_; /**< Array of pointers to axis objects */
|
||||
|
||||
|
||||
asynStatus transactController(int axis, char command[COMLEN], char reply[COMLEN]);
|
||||
int enableAxis_;
|
||||
int axisEnabled_;
|
||||
};
|
@ -14,9 +14,6 @@ list to the motor controller constructor.
|
||||
Mark Koennecke
|
||||
July 2015
|
||||
|
||||
Modified to use the MsgTxt field for SINQ
|
||||
|
||||
Mark Koennecke, January 2019
|
||||
*/
|
||||
|
||||
|
||||
@ -46,7 +43,12 @@ Mark Koennecke, January 2019
|
||||
* \param[in] NanotecPortName The name of the drvAsynSerialPort that was created previously to connect to the Nanotec controller
|
||||
*/
|
||||
NanotecController::NanotecController(const char *portName, const char *NanotecPortName, int motCount, const char *bus)
|
||||
: SINQController(portName, NanotecPortName, motCount+1)
|
||||
: asynMotorController(portName, motCount+1, 0,
|
||||
0, // No additional interfaces beyond those in base class
|
||||
0, // No additional callback interfaces beyond those in base class
|
||||
ASYN_CANBLOCK | ASYN_MULTIDEVICE,
|
||||
1, // autoconnect
|
||||
0, 0) // Default priority and stack size
|
||||
{
|
||||
int axis, busAddress;
|
||||
asynStatus status;
|
||||
@ -134,11 +136,11 @@ NanotecAxis* NanotecController::getAxis(int axisNo)
|
||||
* Initializes register numbers, etc.
|
||||
*/
|
||||
NanotecAxis::NanotecAxis(NanotecController *pC, int axisNo, int busAddress)
|
||||
: SINQAxis(pC, axisNo),
|
||||
: asynMotorAxis(pC, axisNo),
|
||||
pC_(pC)
|
||||
{
|
||||
this->busAddress = busAddress;
|
||||
next_poll = -1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -160,21 +162,17 @@ void NanotecAxis::report(FILE *fp, int level)
|
||||
//asynMotorAxis::report(fp, level);
|
||||
}
|
||||
|
||||
asynStatus NanotecController::transactController(int axisNo, char command[COMLEN], char reply[COMLEN])
|
||||
asynStatus NanotecController::transactController(char command[COMLEN], char reply[COMLEN])
|
||||
{
|
||||
asynStatus status;
|
||||
size_t in, out;
|
||||
int reason;
|
||||
SINQAxis *axis = getAxis(axisNo);
|
||||
|
||||
pasynOctetSyncIO->flush(pasynUserController_);
|
||||
|
||||
status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
|
||||
reply,COMLEN, 1.,&out,&in,&reason);
|
||||
if(status != asynSuccess){
|
||||
if(axis != NULL){
|
||||
axis->updateMsgTxtFromDriver("Lost connection to motor controller");
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -202,8 +200,6 @@ asynStatus NanotecAxis::move(double position, int relative, double minVelocity,
|
||||
size_t in, out;
|
||||
int reason;
|
||||
|
||||
updateMsgTxtFromDriver("");
|
||||
|
||||
// status = sendAccelAndVelocity(acceleration, maxVelocity);
|
||||
|
||||
if (relative) {
|
||||
@ -219,7 +215,7 @@ asynStatus NanotecAxis::move(double position, int relative, double minVelocity,
|
||||
set mode
|
||||
*/
|
||||
snprintf(command,sizeof(command),"#%dp2",busAddress);
|
||||
status = pC_->transactController(axisNo_,command,reply);
|
||||
status = pC_->transactController(command,reply);
|
||||
if(status != asynSuccess){
|
||||
return status;
|
||||
}
|
||||
@ -228,7 +224,7 @@ asynStatus NanotecAxis::move(double position, int relative, double minVelocity,
|
||||
set target
|
||||
*/
|
||||
snprintf(command,sizeof(command),"#%ds%d",busAddress, (int)position);
|
||||
status = pC_->transactController(axisNo_,command,reply);
|
||||
status = pC_->transactController(command,reply);
|
||||
if(status != asynSuccess){
|
||||
return status;
|
||||
}
|
||||
@ -237,7 +233,7 @@ asynStatus NanotecAxis::move(double position, int relative, double minVelocity,
|
||||
and start..
|
||||
*/
|
||||
snprintf(command,sizeof(command),"#%dA",busAddress);
|
||||
status = pC_->transactController(axisNo_,command,reply);
|
||||
status = pC_->transactController(command,reply);
|
||||
if(status != asynSuccess){
|
||||
return status;
|
||||
}
|
||||
@ -254,13 +250,11 @@ asynStatus NanotecAxis::home(double minVelocity, double maxVelocity, double acce
|
||||
|
||||
setIntegerParam(pC_->motorStatusAtHome_, false);
|
||||
|
||||
updateMsgTxtFromDriver("");
|
||||
|
||||
/*
|
||||
reset positioning errors
|
||||
*/
|
||||
snprintf(command,sizeof(command),"#%dD",busAddress);
|
||||
status = pC_->transactController(axisNo_,command,reply);
|
||||
status = pC_->transactController(command,reply);
|
||||
if(status != asynSuccess){
|
||||
return status;
|
||||
}
|
||||
@ -269,7 +263,7 @@ asynStatus NanotecAxis::home(double minVelocity, double maxVelocity, double acce
|
||||
set mode
|
||||
*/
|
||||
snprintf(command,sizeof(command),"#%dp4",busAddress);
|
||||
status = pC_->transactController(axisNo_,command,reply);
|
||||
status = pC_->transactController(command,reply);
|
||||
if(status != asynSuccess){
|
||||
return status;
|
||||
}
|
||||
@ -279,7 +273,7 @@ asynStatus NanotecAxis::home(double minVelocity, double maxVelocity, double acce
|
||||
set direction
|
||||
*/
|
||||
snprintf(command,sizeof(command),"#%dd0",busAddress);
|
||||
status = pC_->transactController(axisNo_,command,reply);
|
||||
status = pC_->transactController(command,reply);
|
||||
if(status != asynSuccess){
|
||||
return status;
|
||||
}
|
||||
@ -289,7 +283,7 @@ asynStatus NanotecAxis::home(double minVelocity, double maxVelocity, double acce
|
||||
and start..
|
||||
*/
|
||||
snprintf(command,sizeof(command),"#%dA",busAddress);
|
||||
status = pC_->transactController(axisNo_,command,reply);
|
||||
status = pC_->transactController(command,reply);
|
||||
if(status != asynSuccess){
|
||||
return status;
|
||||
}
|
||||
@ -310,7 +304,6 @@ asynStatus NanotecAxis::moveVelocity(double minVelocity, double maxVelocity, dou
|
||||
// "%s: minVelocity=%f, maxVelocity=%f, acceleration=%f\n",
|
||||
// functionName, minVelocity, maxVelocity, acceleration);
|
||||
|
||||
updateMsgTxtFromDriver("");
|
||||
|
||||
|
||||
if (maxVelocity > 0.) {
|
||||
@ -333,7 +326,7 @@ asynStatus NanotecAxis::stop(double acceleration )
|
||||
char command[COMLEN], reply[COMLEN];
|
||||
|
||||
sprintf(command, "#%dS1", busAddress);
|
||||
status = pC_->transactController(axisNo_,command,reply);
|
||||
status = pC_->transactController(command,reply);
|
||||
errlogPrintf("Sent STOP on Axis %d\n", axisNo_);
|
||||
|
||||
return status;
|
||||
@ -345,10 +338,8 @@ asynStatus NanotecAxis::setPosition(double position)
|
||||
//static const char *functionName = "NanotecAxis::setPosition";
|
||||
char command[COMLEN], reply[COMLEN];
|
||||
|
||||
updateMsgTxtFromDriver("");
|
||||
|
||||
sprintf(command, "#%dD%d", busAddress, (int)position);
|
||||
status = pC_->transactController(axisNo_,command,reply);
|
||||
status = pC_->transactController(command,reply);
|
||||
next_poll = -1;
|
||||
|
||||
return status;
|
||||
@ -377,7 +368,7 @@ asynStatus NanotecAxis::poll(bool *moving)
|
||||
asynStatus comStatus;
|
||||
char command[COMLEN], reply[COMLEN];
|
||||
char *pPtr;
|
||||
int posVal, statVal, count = 0;
|
||||
int posVal, statVal;
|
||||
double lowLim, highLim;
|
||||
|
||||
|
||||
@ -389,40 +380,28 @@ asynStatus NanotecAxis::poll(bool *moving)
|
||||
|
||||
// Read the current motor position
|
||||
sprintf(command,"#%dC", busAddress);
|
||||
comStatus = pC_->transactController(axisNo_,command,reply);
|
||||
comStatus = pC_->transactController(command,reply);
|
||||
if(comStatus) goto skip;
|
||||
|
||||
pPtr = strchr(reply,'C');
|
||||
if(pPtr){
|
||||
pPtr++;
|
||||
count = sscanf(pPtr,"%d", &posVal);
|
||||
}
|
||||
if(pPtr == NULL || count < 1) {
|
||||
errlogPrintf("Invalid response %s for #C received for axis %d, address %d\n", reply, axisNo_, busAddress);
|
||||
return asynError;
|
||||
}
|
||||
pPtr++;
|
||||
posVal = atoi(pPtr);
|
||||
|
||||
//errlogPrintf("Axis %d, reply %s, position %d\n", axisNo_, reply, posVal);
|
||||
errlogPrintf("Axis %d, reply %s, position %d\n", axisNo_, reply, posVal);
|
||||
setDoubleParam(pC_->motorPosition_, (double)posVal);
|
||||
//setDoubleParam(pC_->motorEncoderPosition_, position);
|
||||
|
||||
|
||||
// Read the moving status of this motor
|
||||
sprintf(command,"#%d$",busAddress);
|
||||
comStatus = pC_->transactController(axisNo_,command,reply);
|
||||
comStatus = pC_->transactController(command,reply);
|
||||
if(comStatus) goto skip;
|
||||
|
||||
pPtr = strchr(reply,'$');
|
||||
if(pPtr) {
|
||||
pPtr++;
|
||||
count = sscanf(pPtr, "%d", &statVal);
|
||||
}
|
||||
if(pPtr == NULL || count < 1) {
|
||||
errlogPrintf("Invalid response %s for #$ received for axis %d busAddress %d\n", reply, axisNo_, busAddress);
|
||||
return asynError;
|
||||
}
|
||||
//errlogPrintf("Axis %d, reply %s, statVal = %d\n",
|
||||
// axisNo_, reply, statVal);
|
||||
pPtr++;
|
||||
statVal = atoi(pPtr);
|
||||
errlogPrintf("Axis %d, reply %s, statVal = %d\n",
|
||||
axisNo_, reply, statVal);
|
||||
|
||||
setIntegerParam(pC_->motorStatusDone_, false);
|
||||
*moving = true;
|
||||
@ -459,13 +438,10 @@ asynStatus NanotecAxis::poll(bool *moving)
|
||||
setIntegerParam(pC_->motorStatusDone_, true);
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
errlogSevPrintf(errlogMajor, "Limit or other positioning problem at %d", axisNo_);
|
||||
updateMsgTxtFromDriver("Positioning problem");
|
||||
if(ABS(posVal - lowLim) < ABS(posVal - highLim)){
|
||||
setIntegerParam(pC_->motorStatusLowLimit_, true);
|
||||
updateMsgTxtFromDriver("Low Limit Hit");
|
||||
} else {
|
||||
setIntegerParam(pC_->motorStatusHighLimit_, true);
|
||||
updateMsgTxtFromDriver("High Limit Hit");
|
||||
}
|
||||
*moving = false;
|
||||
}
|
||||
|
@ -5,18 +5,15 @@ USAGE... Motor driver support for the Nanotec SMCI controller.
|
||||
Mark Koennecke
|
||||
July 2015
|
||||
|
||||
Modified to use the MsgTxt field for SINQ
|
||||
|
||||
Mark Koennecke, January 2019
|
||||
*/
|
||||
|
||||
#include "SINQController.h"
|
||||
#include "SINQAxis.h"
|
||||
#include "asynMotorController.h"
|
||||
#include "asynMotorAxis.h"
|
||||
|
||||
#define COMLEN 80
|
||||
#define MAXMOT 99
|
||||
|
||||
class NanotecAxis : public SINQAxis
|
||||
class NanotecAxis : public asynMotorAxis
|
||||
{
|
||||
public:
|
||||
/* These are the methods we override from the base class */
|
||||
@ -41,7 +38,7 @@ private:
|
||||
friend class NanotecController;
|
||||
};
|
||||
|
||||
class NanotecController : public SINQController {
|
||||
class NanotecController : public asynMotorController {
|
||||
public:
|
||||
NanotecController(const char *portName, const char *NanotecPortName, int numMot, const char *busAddresses);
|
||||
|
||||
@ -53,7 +50,7 @@ friend class NanotecAxis;
|
||||
private:
|
||||
asynUser *pasynUserController_;
|
||||
|
||||
asynStatus transactController(int axisNo, char command[COMLEN], char reply[COMLEN]);
|
||||
asynStatus transactController(char command[COMLEN], char reply[COMLEN]);
|
||||
|
||||
|
||||
|
||||
|
@ -23,12 +23,6 @@ Though this driver has been written in 2016, the MCC-2 version used is probably
|
||||
Mark Koennecke
|
||||
September 2016
|
||||
|
||||
Updated to use the new MsgTxt field through SINQAxis
|
||||
Added a selector to support multiple phytrons on a connection
|
||||
|
||||
Mark Koennecke
|
||||
January 2019
|
||||
|
||||
*/
|
||||
|
||||
|
||||
@ -55,16 +49,19 @@ January 2019
|
||||
* \param[in] PhytronPortName The name of the drvAsynSerialPort that was created previously to connect to the Phytron controller
|
||||
* \param[in] numAxes The number of axes that this controller supports
|
||||
*/
|
||||
PhytronController::PhytronController(const char *portName, const char *PhytronPortName, const char *sel ,
|
||||
int encX, int encY)
|
||||
: SINQController(portName, PhytronPortName,2)
|
||||
PhytronController::PhytronController(const char *portName, const char *PhytronPortName, int encX, int encY)
|
||||
: asynMotorController(portName, 3, 0,
|
||||
0, // No additional interfaces beyond those in base class
|
||||
0, // No additional callback interfaces beyond those in base class
|
||||
ASYN_CANBLOCK | ASYN_MULTIDEVICE,
|
||||
1, // autoconnect
|
||||
0, 0) // Default priority and stack size
|
||||
{
|
||||
asynStatus status;
|
||||
PhytronAxis *pAxis;
|
||||
static const char *functionName = "PhytronController::PhytronController";
|
||||
char etx[2];
|
||||
|
||||
selector = strdup(sel);
|
||||
|
||||
/* Connect to Phytron controller */
|
||||
status = pasynOctetSyncIO->connect(PhytronPortName, 0, &pasynUserController_, NULL);
|
||||
if (status) {
|
||||
@ -77,27 +74,12 @@ PhytronController::PhytronController(const char *portName, const char *PhytronPo
|
||||
pasynOctetSyncIO->setOutputEos(pasynUserController_,etx,strlen(etx));
|
||||
pasynOctetSyncIO->setInputEos(pasynUserController_,etx,strlen(etx));
|
||||
|
||||
/* The special selector D selects the dose controlled axis version */
|
||||
if(strcmp(sel, (const char *)"D") == 0) {
|
||||
new PhytronDoseAxis(this, 1, encX);
|
||||
new PhytronDoseAxis(this, 2, encY);
|
||||
} else {
|
||||
new PhytronAxis(this, 1, encX);
|
||||
new PhytronAxis(this, 2, encY);
|
||||
}
|
||||
|
||||
pAxis = new PhytronAxis(this, 1, encX);
|
||||
pAxis = new PhytronAxis(this, 2, encY);
|
||||
|
||||
startPoller(1000./1000., IDLEPOLL, 2);
|
||||
}
|
||||
|
||||
PhytronDoseController::PhytronDoseController(const char *portName, const char *PhytronPortName, const char *sel ,
|
||||
int encX, int encY)
|
||||
: PhytronController(portName, PhytronPortName, sel, encX, encY)
|
||||
{
|
||||
new PhytronDoseAxis(this, 1, encX);
|
||||
new PhytronDoseAxis(this, 2, encY);
|
||||
}
|
||||
|
||||
|
||||
/** Creates a new PhytronController object.
|
||||
* Configuration command, called directly or from iocsh
|
||||
@ -105,21 +87,14 @@ PhytronDoseController::PhytronDoseController(const char *portName, const char *P
|
||||
* \param[in] PhytronPortName The name of the drvAsynIPPPort that was created previously to connect to the Phytron controller
|
||||
* \param[in] numAxes The number of axes that this controller supports
|
||||
*/
|
||||
extern "C" int PhytronCreateController(const char *portName, const char *PhytronPortName, const char *selector,
|
||||
int encX, int encY)
|
||||
extern "C" int PhytronCreateController(const char *portName, const char *PhytronPortName, int encX, int encY)
|
||||
{
|
||||
new PhytronController(portName, PhytronPortName,selector, encX, encY);
|
||||
PhytronController *pPhytronController
|
||||
= new PhytronController(portName, PhytronPortName, encX, encY);
|
||||
pPhytronController = NULL;
|
||||
return(asynSuccess);
|
||||
}
|
||||
|
||||
extern "C" int PhytronDoseCreateController(const char *portName, const char *PhytronPortName, const char *selector,
|
||||
int encX, int encY)
|
||||
{
|
||||
new PhytronDoseController(portName, PhytronPortName,selector, encX, encY);
|
||||
return(asynSuccess);
|
||||
}
|
||||
|
||||
|
||||
/** Reports on status of the driver
|
||||
* \param[in] fp The file pointer on which report information will be written
|
||||
* \param[in] level The level of report detail desired
|
||||
@ -152,23 +127,6 @@ PhytronAxis* PhytronController::getAxis(int axisNo)
|
||||
return static_cast<PhytronAxis*>(asynMotorController::getAxis(axisNo));
|
||||
}
|
||||
|
||||
/** Returns a pointer to an PhytronDoseAxis object.
|
||||
* Returns NULL if the axis number encoded in pasynUser is invalid.
|
||||
* \param[in] pasynUser asynUser structure that encodes the axis index number. */
|
||||
PhytronDoseAxis* PhytronDoseController::getAxis(asynUser *pasynUser)
|
||||
{
|
||||
return static_cast<PhytronDoseAxis*>(asynMotorController::getAxis(pasynUser));
|
||||
}
|
||||
|
||||
/** Returns a pointer to an PhytronDoseAxis object.
|
||||
* Returns NULL if the axis number encoded in pasynUser is invalid.
|
||||
* \param[in] axisNo Axis index number. */
|
||||
PhytronDoseAxis* PhytronDoseController::getAxis(int axisNo)
|
||||
{
|
||||
return static_cast<PhytronDoseAxis*>(asynMotorController::getAxis(axisNo));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* send a command to the Phytron and read the reply. Do some error and controller
|
||||
* issue fixing on the way
|
||||
@ -176,16 +134,14 @@ PhytronDoseAxis* PhytronDoseController::getAxis(int axisNo)
|
||||
* \param[out] reply The controllers reply
|
||||
*/
|
||||
|
||||
asynStatus PhytronController::transactController(int axisNo,char command[COMLEN], char reply[COMLEN])
|
||||
asynStatus PhytronController::transactController(char command[COMLEN], char reply[COMLEN])
|
||||
{
|
||||
asynStatus status;
|
||||
size_t in, out;
|
||||
int reason;
|
||||
char myReply[COMLEN+10], myCommand[COMLEN+10], *pPtr;
|
||||
SINQAxis *axis = getAxis(axisNo);
|
||||
|
||||
|
||||
/* pasynOctetSyncIO->flush(pasynUserController_); */
|
||||
pasynOctetSyncIO->flush(pasynUserController_);
|
||||
|
||||
|
||||
memset(myCommand,0,sizeof(myCommand));
|
||||
@ -199,9 +155,6 @@ asynStatus PhytronController::transactController(int axisNo,char command[COMLEN]
|
||||
status = pasynOctetSyncIO->writeRead(pasynUserController_, myCommand, strlen(myCommand),
|
||||
myReply,sizeof(myReply), 1.,&out,&in,&reason);
|
||||
if(status != asynSuccess){
|
||||
if(axis!= NULL){
|
||||
axis->updateMsgTxtFromDriver("Lost connection to motor controller");
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -223,7 +176,7 @@ asynStatus PhytronController::transactController(int axisNo,char command[COMLEN]
|
||||
I may need to replace the ETX. But I am not sure if asyn did
|
||||
not remove it for me.
|
||||
*/
|
||||
strncat(reply,pPtr,COMLEN-1);
|
||||
strncat(reply,pPtr,sizeof(reply));
|
||||
|
||||
|
||||
return status;
|
||||
@ -238,7 +191,7 @@ asynStatus PhytronController::transactController(int axisNo,char command[COMLEN]
|
||||
* Initializes register numbers, etc.
|
||||
*/
|
||||
PhytronAxis::PhytronAxis(PhytronController *pC, int axisNo, int enc)
|
||||
: SINQAxis(pC, axisNo),
|
||||
: asynMotorAxis(pC, axisNo),
|
||||
pC_(pC)
|
||||
{
|
||||
encoder = enc;
|
||||
@ -247,21 +200,10 @@ PhytronAxis::PhytronAxis(PhytronController *pC, int axisNo, int enc)
|
||||
} else {
|
||||
phytronChar = 'Y';
|
||||
}
|
||||
haveBrake = 0;
|
||||
brakeIO = -1;
|
||||
next_poll = -1;
|
||||
|
||||
}
|
||||
|
||||
int PhytronAxis::setBrake(int brakeNO)
|
||||
{
|
||||
if(brakeNO < 1 || brakeNO > 8) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
haveBrake = 1;
|
||||
brakeIO = brakeNO;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/** Reports on status of the axis
|
||||
* \param[in] fp The file pointer on which report information will be written
|
||||
@ -287,46 +229,15 @@ asynStatus PhytronAxis::move(double position, int relative, double minVelocity,
|
||||
//static const char *functionName = "PhytronAxis::move";
|
||||
char command[COMLEN], reply[COMLEN];
|
||||
|
||||
updateMsgTxtFromDriver("");
|
||||
|
||||
/*
|
||||
deal with brake
|
||||
*/
|
||||
if(haveBrake) {
|
||||
sprintf(command,"%sA%dS", pC_->selector, brakeIO);
|
||||
status = pC_->transactController(axisNo_,command,reply);
|
||||
if(strstr(reply,"NACK") != NULL){
|
||||
errlogSevPrintf(errlogMajor, "Failed to release brake on %d", axisNo_);
|
||||
updateMsgTxtFromDriver("Failed to release brake");
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
return asynError;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
set speed
|
||||
*/
|
||||
sprintf(command, "%s%cP14S%f", pC_->selector, phytronChar, maxVelocity);
|
||||
status = pC_->transactController(axisNo_,command,reply);
|
||||
if(strstr(reply,"NACK") != NULL){
|
||||
errlogSevPrintf(errlogMajor, "Speed not accepted on %d", axisNo_);
|
||||
updateMsgTxtFromDriver("Invalid speed");
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
return asynError;
|
||||
}
|
||||
|
||||
/*
|
||||
actually send a move command
|
||||
*/
|
||||
if (relative) {
|
||||
position += this->position;
|
||||
}
|
||||
homing = 0;
|
||||
sprintf(command, "%s%cA%f", pC_->selector,phytronChar,position/1000.);
|
||||
status = pC_->transactController(axisNo_,command,reply);
|
||||
sprintf(command, "0%cA%f", phytronChar,position/1000.);
|
||||
status = pC_->transactController(command,reply);
|
||||
if(strstr(reply,"NACK") != NULL){
|
||||
errlogSevPrintf(errlogMajor, "Drive command not acknowledged on %d", axisNo_);
|
||||
updateMsgTxtFromDriver("Drive command not acknowledged");
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
return asynError;
|
||||
}
|
||||
@ -340,47 +251,13 @@ asynStatus PhytronAxis::home(double minVelocity, double maxVelocity, double acce
|
||||
//static const char *functionName = "PhytronAxis::home";
|
||||
char command[COMLEN], reply[COMLEN];
|
||||
|
||||
updateMsgTxtFromDriver("");
|
||||
|
||||
/*
|
||||
handle the fucking brake
|
||||
*/
|
||||
if(haveBrake) {
|
||||
sprintf(command,"%sA%dS", pC_->selector, brakeIO);
|
||||
status = pC_->transactController(axisNo_,command,reply);
|
||||
if(strstr(reply,"NACK") != NULL){
|
||||
errlogSevPrintf(errlogMajor, "Failed to release brake on %d", axisNo_);
|
||||
updateMsgTxtFromDriver("Failed to release brake");
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
return asynError;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
set speed
|
||||
*/
|
||||
sprintf(command, "%s%cP14S%f", pC_->selector, phytronChar, maxVelocity);
|
||||
status = pC_->transactController(axisNo_,command,reply);
|
||||
if(strstr(reply,"NACK") != NULL){
|
||||
errlogSevPrintf(errlogMajor, "Speed not accepted on %d", axisNo_);
|
||||
updateMsgTxtFromDriver("Invalid speed");
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
return asynError;
|
||||
}
|
||||
|
||||
homing_direction = forwards;
|
||||
if(forwards){
|
||||
sprintf(command, "%s%c0+",pC_->selector,phytronChar);
|
||||
} else {
|
||||
sprintf(command, "%s%c0-",pC_->selector,phytronChar);
|
||||
}
|
||||
sprintf(command, "0%cO-",phytronChar);
|
||||
homing = 1;
|
||||
next_poll= -1;
|
||||
status = pC_->transactController(axisNo_,command,reply);
|
||||
status = pC_->transactController(command,reply);
|
||||
if(strstr(reply,"NACK") != NULL){
|
||||
errlogSevPrintf(errlogMajor, "Home command not acknowledged on %d", axisNo_);
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
updateMsgTxtFromDriver("Home command not acknowledged");
|
||||
return asynError;
|
||||
}
|
||||
return status;
|
||||
@ -397,7 +274,6 @@ asynStatus PhytronAxis::moveVelocity(double minVelocity, double maxVelocity, dou
|
||||
// "%s: minVelocity=%f, maxVelocity=%f, acceleration=%f\n",
|
||||
// functionName, minVelocity, maxVelocity, acceleration);
|
||||
|
||||
updateMsgTxtFromDriver("");
|
||||
|
||||
|
||||
if (maxVelocity > 0.) {
|
||||
@ -418,10 +294,9 @@ asynStatus PhytronAxis::stop(double acceleration )
|
||||
//static const char *functionName = "PhytronAxis::stop";
|
||||
char command[COMLEN], reply[COMLEN];
|
||||
|
||||
sprintf(command, "%s%cSN", pC_->selector,phytronChar);
|
||||
status = pC_->transactController(axisNo_,command,reply);
|
||||
sprintf(command, "0%cSN", phytronChar);
|
||||
status = pC_->transactController(command,reply);
|
||||
errlogPrintf("Sent STOP on Axis %d\n", axisNo_);
|
||||
updateMsgTxtFromDriver("Axis interrupted");
|
||||
|
||||
return status;
|
||||
}
|
||||
@ -432,12 +307,10 @@ asynStatus PhytronAxis::setPosition(double position)
|
||||
//static const char *functionName = "PhytronAxis::setPosition";
|
||||
char command[COMLEN], reply[COMLEN];
|
||||
|
||||
errlogPrintf("PhytronAxis::setPosition called with %lf\n", position);
|
||||
|
||||
sprintf(command, "%s%cP22S%f", pC_->selector,phytronChar, position/1000.);
|
||||
status = pC_->transactController(axisNo_,command,reply);
|
||||
sprintf(command, "%s%cP20S%f", pC_->selector,phytronChar, position/1000.);
|
||||
status = pC_->transactController(axisNo_,command,reply);
|
||||
sprintf(command, "0%cP22S%f", phytronChar, position/1000.);
|
||||
status = pC_->transactController(command,reply);
|
||||
sprintf(command, "0%cP20S%f", phytronChar, position/1000.);
|
||||
status = pC_->transactController(command,reply);
|
||||
next_poll = -1;
|
||||
|
||||
return status;
|
||||
@ -463,7 +336,7 @@ asynStatus PhytronAxis::setClosedLoop(bool closedLoop)
|
||||
* \param[out] moving A flag that is set indicating that the axis is moving (true) or done (false). */
|
||||
asynStatus PhytronAxis::poll(bool *moving)
|
||||
{
|
||||
asynStatus comStatus = asynSuccess;
|
||||
asynStatus comStatus;
|
||||
char command[COMLEN], reply[COMLEN];
|
||||
double lowlim;
|
||||
|
||||
@ -474,24 +347,19 @@ asynStatus PhytronAxis::poll(bool *moving)
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
setIntegerParam(pC_->motorStatusProblem_, false);
|
||||
// Read the current motor position
|
||||
if(encoder) {
|
||||
sprintf(command,"%s%cP22R",pC_->selector,phytronChar);
|
||||
sprintf(command,"0%cP22R",phytronChar);
|
||||
} else {
|
||||
sprintf(command,"%s%cP20R",pC_->selector,phytronChar);
|
||||
sprintf(command,"0%cP20R",phytronChar);
|
||||
}
|
||||
|
||||
comStatus = pC_->transactController(axisNo_,command,reply);
|
||||
if(comStatus == asynError) {
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
updateMsgTxtFromDriver("No connection to phytron controller");
|
||||
goto skip;
|
||||
}
|
||||
comStatus = pC_->transactController(command,reply);
|
||||
if(comStatus) goto skip;
|
||||
|
||||
if(strstr(reply,"NACK") != NULL){
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
errlogSevPrintf(errlogMajor, "Bad reply for position on %d", axisNo_);
|
||||
updateMsgTxtFromDriver("Bad reply reading position");
|
||||
goto skip;
|
||||
}
|
||||
/*
|
||||
@ -504,13 +372,9 @@ asynStatus PhytronAxis::poll(bool *moving)
|
||||
|
||||
|
||||
// Read the moving status of this motor
|
||||
sprintf(command,"%s%c=H",pC_->selector,phytronChar);
|
||||
comStatus = pC_->transactController(axisNo_,command,reply);
|
||||
if(comStatus == asynError){
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
updateMsgTxtFromDriver("No connection to phytron controller");
|
||||
goto skip;
|
||||
}
|
||||
sprintf(command,"0%c=H",phytronChar);
|
||||
comStatus = pC_->transactController(command,reply);
|
||||
if(comStatus) goto skip;
|
||||
/* errlogPrintf("Axis %d, status reply %s, position %lf\n", axisNo_, reply, position); */
|
||||
if(strstr(reply,"ACKN") != NULL){
|
||||
*moving = true;
|
||||
@ -520,45 +384,23 @@ asynStatus PhytronAxis::poll(bool *moving)
|
||||
*moving = false;
|
||||
next_poll = time(NULL)+IDLEPOLL;
|
||||
setIntegerParam(pC_->motorStatusDone_, true);
|
||||
|
||||
if(haveBrake) {
|
||||
sprintf(command,"%sA%dR", pC_->selector, brakeIO);
|
||||
comStatus = pC_->transactController(axisNo_,command,reply);
|
||||
if(strstr(reply,"NACK") != NULL){
|
||||
errlogSevPrintf(errlogMajor, "Failed to set brake on %d", axisNo_);
|
||||
updateMsgTxtFromDriver("Failed to set brake");
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
return asynError;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!*moving) {
|
||||
if(homing){
|
||||
if(homing_direction) {
|
||||
pC_->getDoubleParam(axisNo_,pC_->motorHighLimit_,&lowlim);
|
||||
} else {
|
||||
pC_->getDoubleParam(axisNo_,pC_->motorLowLimit_,&lowlim);
|
||||
}
|
||||
pC_->getDoubleParam(axisNo_,pC_->motorLowLimit_,&lowlim);
|
||||
setPosition(lowlim);
|
||||
setIntegerParam(pC_->motorStatusAtHome_, true);
|
||||
} else {
|
||||
/*
|
||||
check limits and errors, upper
|
||||
*/
|
||||
sprintf(command,"%s%c=I+",pC_->selector,phytronChar);
|
||||
comStatus = pC_->transactController(axisNo_,command,reply);
|
||||
if(comStatus == asynError) {
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
updateMsgTxtFromDriver("No connection to phytron controller");
|
||||
goto skip;
|
||||
}
|
||||
sprintf(command,"0%c=I+",phytronChar);
|
||||
comStatus = pC_->transactController(command,reply);
|
||||
if(comStatus) goto skip;
|
||||
if(strstr(reply,"ACKE") != NULL){
|
||||
setIntegerParam(pC_->motorStatusHighLimit_, true);
|
||||
updateMsgTxtFromDriver("Hit High Limit");
|
||||
comStatus = asynError;
|
||||
goto skip;
|
||||
} else {
|
||||
setIntegerParam(pC_->motorStatusHighLimit_, false);
|
||||
}
|
||||
@ -566,18 +408,11 @@ asynStatus PhytronAxis::poll(bool *moving)
|
||||
/*
|
||||
lower limit
|
||||
*/
|
||||
sprintf(command,"%s%c=I-",pC_->selector,phytronChar);
|
||||
comStatus = pC_->transactController(axisNo_,command,reply);
|
||||
if(comStatus == asynError){
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
updateMsgTxtFromDriver("No connection to phytron controller");
|
||||
goto skip;
|
||||
}
|
||||
sprintf(command,"0%c=I-",phytronChar);
|
||||
comStatus = pC_->transactController(command,reply);
|
||||
if(comStatus) goto skip;
|
||||
if(strstr(reply,"ACKE") != NULL){
|
||||
setIntegerParam(pC_->motorStatusLowLimit_, true);
|
||||
updateMsgTxtFromDriver("Low Limit Hit");
|
||||
comStatus = asynError;
|
||||
goto skip;
|
||||
} else {
|
||||
setIntegerParam(pC_->motorStatusLowLimit_, false);
|
||||
}
|
||||
@ -585,19 +420,12 @@ asynStatus PhytronAxis::poll(bool *moving)
|
||||
/*
|
||||
error
|
||||
*/
|
||||
sprintf(command,"%s%c=E",pC_->selector,phytronChar);
|
||||
comStatus = pC_->transactController(axisNo_,command,reply);
|
||||
if(comStatus == asynError) {
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
updateMsgTxtFromDriver("No connection to phytron controller");
|
||||
goto skip;
|
||||
}
|
||||
sprintf(command,"0%c=E",phytronChar);
|
||||
comStatus = pC_->transactController(command,reply);
|
||||
if(comStatus) goto skip;
|
||||
if(strstr(reply,"ACKE") != NULL){
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
errlogSevPrintf(errlogMajor, "Electronics on %d", axisNo_);
|
||||
updateMsgTxtFromDriver("Electronics error");
|
||||
comStatus = asynError;
|
||||
goto skip;
|
||||
} else {
|
||||
setIntegerParam(pC_->motorStatusProblem_, false);
|
||||
}
|
||||
@ -606,165 +434,29 @@ asynStatus PhytronAxis::poll(bool *moving)
|
||||
|
||||
|
||||
skip:
|
||||
setIntegerParam(pC_->motorStatusProblem_, comStatus ? 1:0);
|
||||
callParamCallbacks();
|
||||
return comStatus;
|
||||
}
|
||||
|
||||
/* The special PhytronDoseAxis code used when the speed is controlled through the neutron flux
|
||||
*/
|
||||
|
||||
PhytronDoseAxis::PhytronDoseAxis(PhytronController *pC, int axisNo, int enc)
|
||||
: PhytronAxis(pC, axisNo, enc)
|
||||
{
|
||||
if(axisNo == 1){
|
||||
doseChar = '3';
|
||||
} else {
|
||||
doseChar = '4';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
asynStatus PhytronDoseAxis::move(double position, int relative, double minVelocity, double maxVelocity, double acceleration)
|
||||
{
|
||||
asynStatus status;
|
||||
//static const char *functionName = "PhytronDoseAxis::move";
|
||||
char command[COMLEN], reply[COMLEN];
|
||||
float realTarget;
|
||||
|
||||
updateMsgTxtFromDriver("");
|
||||
|
||||
/*
|
||||
set conversion factor from neutron rate to speed
|
||||
*/
|
||||
sprintf(command, "R%c3S%f", doseChar, maxVelocity);
|
||||
status = pC_->transactController(axisNo_,command,reply);
|
||||
if(strstr(reply,"NACK") != NULL){
|
||||
errlogSevPrintf(errlogMajor, "Speed not accepted on %d", axisNo_);
|
||||
updateMsgTxtFromDriver("Invalid speed");
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
return asynError;
|
||||
}
|
||||
|
||||
/*
|
||||
actually send a move command
|
||||
*/
|
||||
if (relative) {
|
||||
position += this->position;
|
||||
}
|
||||
homing = 0;
|
||||
|
||||
/* set target */
|
||||
realTarget = position/1000.;
|
||||
if(realTarget > this->position) {
|
||||
sprintf(command, "R%c1S%f", doseChar,realTarget);
|
||||
} else {
|
||||
sprintf(command, "R%c2S%f", doseChar,realTarget);
|
||||
}
|
||||
status = pC_->transactController(axisNo_,command,reply);
|
||||
if(strstr(reply,"NACK") != NULL){
|
||||
errlogSevPrintf(errlogMajor, "Drive command not acknowledged on %d", axisNo_);
|
||||
updateMsgTxtFromDriver("Drive command not acknowledged");
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
return asynError;
|
||||
}
|
||||
|
||||
/* really start the move */
|
||||
sprintf(command, "R%c01S", doseChar);
|
||||
status = pC_->transactController(axisNo_,command,reply);
|
||||
if(strstr(reply,"NACK") != NULL){
|
||||
errlogSevPrintf(errlogMajor, "Drive start command not acknowledged on %d", axisNo_);
|
||||
updateMsgTxtFromDriver("Drive command not acknowledged");
|
||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||
return asynError;
|
||||
}
|
||||
|
||||
next_poll = -1;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
extern "C" asynStatus PhytronConfBrake(const char *port, /* specify which controller by port name */
|
||||
int axis, /* axis: 0, 1 */
|
||||
int brakeNO) /* brakeIO No, 1-8 */
|
||||
{
|
||||
PhytronController *pC;
|
||||
PhytronAxis *pAxis;
|
||||
int status;
|
||||
|
||||
static const char *functionName = "PhytronConfBrake";
|
||||
|
||||
pC = (PhytronController*) findAsynPortDriver(port);
|
||||
if (!pC) {
|
||||
printf("%s:%s: Error port %s not found\n",
|
||||
"PhytronDriver", functionName, port);
|
||||
return asynError;
|
||||
}
|
||||
|
||||
pC->lock();
|
||||
pAxis = pC->getAxis(axis);
|
||||
status = pAxis->setBrake(brakeNO);
|
||||
pC->unlock();
|
||||
if(!status) {
|
||||
printf("%s:%s:%s requested brake IO out of range\n",
|
||||
"PhytronDriver", functionName, port);
|
||||
return asynError;
|
||||
}
|
||||
return asynSuccess;
|
||||
return comStatus ? asynError : asynSuccess;
|
||||
}
|
||||
|
||||
/** Code for iocsh registration */
|
||||
static const iocshArg PhytronCreateControllerArg0 = {"Port name", iocshArgString};
|
||||
static const iocshArg PhytronCreateControllerArg1 = {"Phytron port name", iocshArgString};
|
||||
static const iocshArg PhytronCreateControllerArg2 = {"Phytron Selector", iocshArgString};
|
||||
static const iocshArg PhytronCreateControllerArg3 = {"EncoderX", iocshArgInt};
|
||||
static const iocshArg PhytronCreateControllerArg4 = {"EncoderY", iocshArgInt};
|
||||
static const iocshArg PhytronCreateControllerArg2 = {"EnoderX", iocshArgInt};
|
||||
static const iocshArg PhytronCreateControllerArg3 = {"EnoderY", iocshArgInt};
|
||||
static const iocshArg * const PhytronCreateControllerArgs[] = {&PhytronCreateControllerArg0,
|
||||
&PhytronCreateControllerArg1,
|
||||
&PhytronCreateControllerArg2,
|
||||
&PhytronCreateControllerArg3,
|
||||
&PhytronCreateControllerArg4};
|
||||
static const iocshFuncDef PhytronCreateControllerDef = {"PhytronCreateController", 5, PhytronCreateControllerArgs};
|
||||
&PhytronCreateControllerArg3};
|
||||
static const iocshFuncDef PhytronCreateControllerDef = {"PhytronCreateController", 4, PhytronCreateControllerArgs};
|
||||
static void PhytronCreateContollerCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
PhytronCreateController(args[0].sval, args[1].sval, args[2].sval, args[3].ival,args[4].ival);
|
||||
PhytronCreateController(args[0].sval, args[1].sval, args[2].ival,args[3].ival);
|
||||
}
|
||||
|
||||
static const iocshArg PhytronDoseCreateControllerArg0 = {"Port name", iocshArgString};
|
||||
static const iocshArg PhytronDoseCreateControllerArg1 = {"Phytron port name", iocshArgString};
|
||||
static const iocshArg PhytronDoseCreateControllerArg2 = {"Phytron Selector", iocshArgString};
|
||||
static const iocshArg PhytronDoseCreateControllerArg3 = {"EncoderX", iocshArgInt};
|
||||
static const iocshArg PhytronDoseCreateControllerArg4 = {"EncoderY", iocshArgInt};
|
||||
static const iocshArg * const PhytronDoseCreateControllerArgs[] = {&PhytronDoseCreateControllerArg0,
|
||||
&PhytronDoseCreateControllerArg1,
|
||||
&PhytronDoseCreateControllerArg2,
|
||||
&PhytronDoseCreateControllerArg3,
|
||||
&PhytronDoseCreateControllerArg4};
|
||||
static const iocshFuncDef PhytronDoseCreateControllerDef = {"PhytronDoseCreateController", 5, PhytronDoseCreateControllerArgs};
|
||||
static void PhytronDoseCreateContollerCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
PhytronDoseCreateController(args[0].sval, args[1].sval, args[2].sval, args[3].ival,args[4].ival);
|
||||
}
|
||||
|
||||
/* PhytronConfigureBrake */
|
||||
static const iocshArg phytronBrakeArg0 = {"Controller port name", iocshArgString};
|
||||
static const iocshArg phytronBrakeArg1 = {"Axis number", iocshArgInt};
|
||||
static const iocshArg phytronBrakeArg2 = {"Brake IO number", iocshArgInt};
|
||||
static const iocshArg * const phytronBrakeArgs[] = {&phytronBrakeArg0,
|
||||
&phytronBrakeArg1,
|
||||
&phytronBrakeArg2};
|
||||
static const iocshFuncDef phytronBrakeDef = {"PhytronConfigureBrake", 3, phytronBrakeArgs};
|
||||
|
||||
static void phytronBrakeCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
PhytronConfBrake(args[0].sval, args[1].ival, args[2].ival);
|
||||
}
|
||||
|
||||
|
||||
static void PhytronRegister(void)
|
||||
{
|
||||
iocshRegister(&PhytronCreateControllerDef, PhytronCreateContollerCallFunc);
|
||||
iocshRegister(&PhytronDoseCreateControllerDef, PhytronDoseCreateContollerCallFunc);
|
||||
iocshRegister(&phytronBrakeDef, phytronBrakeCallFunc);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
@ -5,28 +5,14 @@ USAGE... Motor driver support for the Phytron MCC-2 motor controller.
|
||||
Mark Koennecke
|
||||
September 2016
|
||||
|
||||
|
||||
Updated to go through SINQAxis for -MsgTxt support
|
||||
Added a selector to support multiple phytrons on a connection
|
||||
|
||||
Mark Koennecke, January 2019
|
||||
|
||||
Added PhytronDoseAxis. The speed of this axis is controlled by the
|
||||
neutron dose rate fed in as analog signal
|
||||
|
||||
Mark Koennecke, April 2023
|
||||
*/
|
||||
|
||||
#include "SINQController.h"
|
||||
#include "SINQAxis.h"
|
||||
#include "asynMotorController.h"
|
||||
#include "asynMotorAxis.h"
|
||||
|
||||
#define COMLEN 80
|
||||
|
||||
|
||||
class PhytronController;
|
||||
class PhytronDoseController;
|
||||
|
||||
class PhytronAxis : public SINQAxis
|
||||
class PhytronAxis : public asynMotorAxis
|
||||
{
|
||||
public:
|
||||
/* These are the methods we override from the base class */
|
||||
@ -39,71 +25,32 @@ public:
|
||||
asynStatus poll(bool *moving);
|
||||
asynStatus setPosition(double position);
|
||||
asynStatus setClosedLoop(bool closedLoop);
|
||||
int setBrake(int brakeIO);
|
||||
|
||||
protected:
|
||||
private:
|
||||
char phytronChar;
|
||||
PhytronController *pC_; /**< Pointer to the asynMotorController to which this axis belongs.
|
||||
* Abbreviated because it is used very frequently */
|
||||
double position;
|
||||
int homing;
|
||||
int homing_direction; /*1 forward, 0 backwards */
|
||||
time_t next_poll;
|
||||
int encoder;
|
||||
int haveBrake;
|
||||
int brakeIO;
|
||||
|
||||
friend class PhytronController;
|
||||
};
|
||||
|
||||
class PhytronDoseAxis : public PhytronAxis
|
||||
{
|
||||
// A special version of PhytronAxis where the speed is controlled by the neutron flux.
|
||||
class PhytronController : public asynMotorController {
|
||||
public:
|
||||
PhytronDoseAxis(class PhytronController *pC, int axis, int enc);
|
||||
asynStatus move(double position, int relative, double min_velocity, double max_velocity, double acceleration);
|
||||
|
||||
friend class PhytronDoseController;
|
||||
|
||||
protected:
|
||||
char doseChar;
|
||||
PhytronDoseController *pC_;
|
||||
};
|
||||
|
||||
|
||||
class PhytronController : public SINQController {
|
||||
public:
|
||||
PhytronController(const char *portName, const char *PhytronPortName, const char *selector,
|
||||
int encX, int encY);
|
||||
PhytronController(const char *portName, const char *PhytronPortName, int encX, int encY);
|
||||
|
||||
void report(FILE *fp, int level);
|
||||
PhytronAxis* getAxis(asynUser *pasynUser);
|
||||
PhytronAxis* getAxis(int axisNo);
|
||||
|
||||
friend class PhytronAxis;
|
||||
|
||||
protected:
|
||||
private:
|
||||
asynUser *pasynUserController_;
|
||||
|
||||
asynStatus transactController(int axisNo, char command[COMLEN], char reply[COMLEN]);
|
||||
asynStatus transactController(char command[COMLEN], char reply[COMLEN]);
|
||||
|
||||
const char *selector;
|
||||
|
||||
};
|
||||
|
||||
class PhytronDoseController : public PhytronController {
|
||||
public:
|
||||
PhytronDoseController(const char *portName, const char *PhytronPortName, const char *selector,
|
||||
int encX, int encY);
|
||||
|
||||
PhytronDoseAxis* getAxis(asynUser *pasynUser);
|
||||
PhytronDoseAxis* getAxis(int axisNo);
|
||||
|
||||
friend class PhytronDoseAxis;
|
||||
|
||||
protected:
|
||||
asynUser *pasynUserController_;
|
||||
const char *selector;
|
||||
|
||||
};
|
||||
|
||||
|
@ -12,7 +12,6 @@ SINQAxis::SINQAxis(class SINQController *pC, int axis)
|
||||
: asynMotorAxis((asynMotorController *)pC, axis),
|
||||
pC_(pC)
|
||||
{
|
||||
updateMsgTxtFromDriver("");
|
||||
}
|
||||
|
||||
|
||||
@ -23,7 +22,6 @@ void SINQAxis::updateMsgTxtFromDriver(const char *value)
|
||||
setStringParam(pC_->motorMessageText_,value);
|
||||
} else {
|
||||
pC_->setIntegerParam(axisNo_,pC_->motorMessageIsFromDriver_, 0);
|
||||
setStringParam(pC_->motorMessageText_,"");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,19 +5,13 @@
|
||||
Code lifted from Torsten Boegershausen ESS code.
|
||||
|
||||
Mark Koennecke, March 2017
|
||||
|
||||
Added code to manage an interMessageSleep
|
||||
|
||||
Mark Koennecke, February 2024
|
||||
*/
|
||||
|
||||
#include "SINQController.h"
|
||||
#include "asynMotorController.h"
|
||||
#include "epicsExport.h"
|
||||
#include "iocsh.h"
|
||||
|
||||
SINQController::SINQController(const char *portName, const char *SINQPortName, int numAxes, const int& extraParams)
|
||||
: asynMotorController(portName, numAxes+1, NUM_MOTOR_DRIVER_PARAMS+extraParams,
|
||||
SINQController::SINQController(const char *portName, const char *SINQPortName, int numAxes)
|
||||
: asynMotorController(portName, numAxes+1, NUM_MOTOR_DRIVER_PARAMS+2,
|
||||
0, // No additional interfaces beyond those in base class
|
||||
0, // No additional callback interfaces beyond those in base class
|
||||
ASYN_CANBLOCK | ASYN_MULTIDEVICE,
|
||||
@ -26,53 +20,6 @@ SINQController::SINQController(const char *portName, const char *SINQPortName, i
|
||||
{
|
||||
createParam(motorMessageIsFromDriverString, asynParamInt32, &motorMessageIsFromDriver_);
|
||||
createParam(motorMessageTextString, asynParamOctet, &motorMessageText_);
|
||||
|
||||
interMessageSleep=20;
|
||||
}
|
||||
|
||||
/** Set the interMessageSleep at runtime */
|
||||
asynStatus SINQController::setInterMessageSleep(int messageSleep)
|
||||
{
|
||||
lock();
|
||||
interMessageSleep = messageSleep;
|
||||
unlock();
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
asynStatus setInterMessageSleep(const char *portName, int messageSleep)
|
||||
{
|
||||
SINQController *pC;
|
||||
static const char *functionName = "setIntermessageSleep";
|
||||
|
||||
pC = (SINQController*) findAsynPortDriver(portName);
|
||||
if (!pC) {
|
||||
printf("%s:%s: Error port %s not found\n", "SINQController", functionName, portName);
|
||||
return asynError;
|
||||
}
|
||||
|
||||
return pC->setInterMessageSleep(messageSleep);
|
||||
}
|
||||
|
||||
|
||||
/* setInterMessageSleep */
|
||||
static const iocshArg setInterMessageSleepArg0 = {"Controller port name", iocshArgString};
|
||||
static const iocshArg setInterMessageSleepArg1 = {"inter message sleep time", iocshArgInt};
|
||||
static const iocshArg * const setInterMessageSleepArgs[] = {&setInterMessageSleepArg0,
|
||||
&setInterMessageSleepArg1};
|
||||
static const iocshFuncDef setInterMessageSleepDef = {"setInterMessageSleep", 2, setInterMessageSleepArgs};
|
||||
|
||||
static void setInterMessageSleepCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
setInterMessageSleep(args[0].sval, args[1].ival);
|
||||
}
|
||||
|
||||
static void SINQControllerRegister(void)
|
||||
{
|
||||
iocshRegister(&setInterMessageSleepDef, setInterMessageSleepCallFunc);
|
||||
}
|
||||
epicsExportRegistrar(SINQControllerRegister);
|
||||
|
||||
} // extern C
|
||||
|
||||
|
@ -17,16 +17,12 @@
|
||||
class epicsShareClass SINQController : public asynMotorController
|
||||
{
|
||||
public:
|
||||
SINQController(const char *portName, const char *SINQPortName, int numAxes, const int& extraParams=2);
|
||||
asynStatus setInterMessageSleep(int messageSleep);
|
||||
|
||||
SINQController(const char *portName, const char *SINQPortName, int numAxes);
|
||||
|
||||
friend class SINQAxis;
|
||||
protected:
|
||||
int motorMessageIsFromDriver_;
|
||||
int motorMessageText_;
|
||||
|
||||
int interMessageSleep; // minimum time between message to the controller in microseconds
|
||||
// for slowing down communication to weak controllers.....
|
||||
};
|
||||
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
||||
*
|
||||
* Mark Koennecke, February 2013
|
||||
*
|
||||
* Enhanced by adding an addtional external pause and status flag in the database and code in here
|
||||
* Enhanced by adding an addtional external pause and status flag in the databse and code in here
|
||||
* to handle this. Moreover an external MsgTxt field in the DB can be filled with an error message.
|
||||
*
|
||||
* Mark Koennecke, July 2017
|
||||
@ -40,8 +40,6 @@
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <asynOctetSyncIO.h>
|
||||
#include <epicsEvent.h>
|
||||
#include <epicsThread.h>
|
||||
@ -114,13 +112,13 @@ typedef struct {
|
||||
unsigned int dbInit;
|
||||
}EL737priv;
|
||||
|
||||
static void dummyAsynCallback([[maybe_unused]] asynUser *pasynUser)
|
||||
static void dummyAsynCallback(asynUser *pasynUser)
|
||||
{
|
||||
}
|
||||
|
||||
static void connectSlaveRecords(EL737priv *priv)
|
||||
{
|
||||
char slaveName[PVNAME_SZ + 18], errName[256];
|
||||
char slaveName[PVNAME_SZ], errName[256];
|
||||
long status;
|
||||
|
||||
priv->dbInit = 1;
|
||||
@ -165,10 +163,10 @@ static void connectSlaveRecords(EL737priv *priv)
|
||||
errlogPrintf("dbNameToAddr failed for %s with %s\n", slaveName, errName);
|
||||
priv->dbInit = 0;
|
||||
} else {
|
||||
errlogPrintf("dbNameToAddr succeded for %s, record access %s\n",slaveName, priv->threshCounter.precord->name);
|
||||
errlogPrintf("dbNameToAddr succeded for %s, record access %s\n",slaveName, priv->status.precord->name);
|
||||
}
|
||||
|
||||
snprintf(slaveName, sizeof(slaveName), "%s:Threshold", priv->psr->name);
|
||||
snprintf(slaveName,sizeof(slaveName),"%s:Threshold", priv->psr->name);
|
||||
errlogPrintf("Name of thresholdCounter variable: %s\n", slaveName);
|
||||
status = dbNameToAddr(slaveName,&priv->threshold);
|
||||
if(status!= 0){
|
||||
@ -176,9 +174,9 @@ static void connectSlaveRecords(EL737priv *priv)
|
||||
errlogPrintf("dbNameToAddr failed for %s with %s\n", slaveName, errName);
|
||||
priv->dbInit = 0;
|
||||
} else {
|
||||
errlogPrintf("dbNameToAddr succeded for %s, record access %s\n",slaveName, priv->threshold.precord->name);
|
||||
errlogPrintf("dbNameToAddr succeded for %s, record access %s\n",slaveName, priv->status.precord->name);
|
||||
}
|
||||
priv->thresholdValue = -999;
|
||||
|
||||
}
|
||||
|
||||
static long el737_init_record(scalerRecord *psr, CALLBACK *pcallback)
|
||||
@ -224,18 +222,17 @@ static long el737_init_record(scalerRecord *psr, CALLBACK *pcallback)
|
||||
psr->pact = 1;
|
||||
return 0;
|
||||
}
|
||||
pasynManager->autoConnect(dummyUser, 1);
|
||||
status = pasynOctetSyncIO->connect(port, 0, &priv->asynContext, NULL);
|
||||
if (status) {
|
||||
asynPrint(dummyUser, ASYN_TRACE_ERROR,
|
||||
"%s: cannot connect to EL737 controller\n",
|
||||
"%s: cannot connect to EL734 controller\n",
|
||||
"el737_init_scaler");
|
||||
psr->pact = 1;
|
||||
return 0;
|
||||
}
|
||||
pasynOctetSyncIO->setOutputEos(priv->asynContext,"\r",strlen("\r"));
|
||||
pasynOctetSyncIO->setInputEos(priv->asynContext,"\r",strlen("\r"));
|
||||
priv->asynContext->timeout = 2.0;
|
||||
priv->asynContext->timeout = 1.0;
|
||||
strcpy(command,"RMT 1");
|
||||
pasynOctetSyncIO->writeRead(priv->asynContext, command, strlen(command),
|
||||
reply,sizeof(reply), 1.,&out,&in,&reason);
|
||||
@ -290,7 +287,7 @@ static long el737_write_preset(scalerRecord *psr, int signal, unsigned long val)
|
||||
{
|
||||
EL737priv *priv;
|
||||
|
||||
// errlogPrintf("EL737: Setting preset %d to %ld\n", signal, val);
|
||||
//errlogPrintf("Setting preset %d to %ld\n", signal, val);
|
||||
|
||||
priv = (EL737priv *)psr->dpvt;
|
||||
if(signal >= 0 && signal < 13){
|
||||
@ -299,7 +296,7 @@ static long el737_write_preset(scalerRecord *psr, int signal, unsigned long val)
|
||||
if(signal == THRESHVAL){
|
||||
priv->sendThreshold = 1;
|
||||
epicsEventSignal(priv->wakeUp);
|
||||
// errlogPrintf("EL737: Setting threshold \n");
|
||||
//errlogPrintf("Setting threshold \n");
|
||||
|
||||
}
|
||||
return 0;
|
||||
@ -312,7 +309,7 @@ static long el737_arm(scalerRecord *psr, int val)
|
||||
priv = (EL737priv *)psr->dpvt;
|
||||
priv->countCommand = val;
|
||||
|
||||
// errlogPrintf("EL737: Sending arm %d \n", val);
|
||||
//errlogPrintf("Sending arm %d \n", val);
|
||||
|
||||
epicsEventSignal(priv->wakeUp);
|
||||
|
||||
@ -324,7 +321,7 @@ static long el737_done(scalerRecord *psr)
|
||||
EL737priv *priv;
|
||||
priv = (EL737priv *)psr->dpvt;
|
||||
|
||||
// errlogPrintf("EL737: Calling done with %d\n", psr->cnt);
|
||||
// errlogPrintf("Calling done with %d\n", psr->cnt);
|
||||
if(priv->counting && psr->cnt == 0){
|
||||
priv->countCommand = 0;
|
||||
epicsEventSignal(priv->wakeUp);
|
||||
@ -346,9 +343,7 @@ static asynStatus el737_transactCommand(EL737priv *priv,char command[COMLEN],cha
|
||||
|
||||
pasynOctetSyncIO->flush(priv->asynContext);
|
||||
|
||||
// errlogPrintf("EL737: sending command %s\n", command);
|
||||
|
||||
strcpy(message,"");
|
||||
strcpy(message,"OK");
|
||||
status = pasynOctetSyncIO->writeRead(priv->asynContext, command, strlen(command),
|
||||
reply,COMLEN, 1.,&out,&in,&reason);
|
||||
if(status == asynSuccess){
|
||||
@ -389,13 +384,7 @@ static asynStatus el737_transactCommand(EL737priv *priv,char command[COMLEN],cha
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(errno == EAGAIN){
|
||||
errlogPrintf("Lost response to %s with EAGAIN\n", command);
|
||||
} else {
|
||||
snprintf(message,sizeof(message), "Lost communication with errno %d", errno);
|
||||
/* force a reconnect */
|
||||
pasynOctetSyncIO->disconnect(priv->asynContext);
|
||||
}
|
||||
strncpy(message,"Lost communication",sizeof(message));
|
||||
}
|
||||
if(priv->dbInit){
|
||||
dbStatus = dbPutField(&priv->msgTxt, DBR_STRING,message, 1);
|
||||
@ -410,7 +399,7 @@ static asynStatus el737_transactCommand(EL737priv *priv,char command[COMLEN],cha
|
||||
static asynStatus sendStop(EL737priv *priv)
|
||||
{
|
||||
char command[COMLEN], reply[COMLEN];
|
||||
// errlogPrintf("EL737: Sending stop\n");
|
||||
//errlogPrintf("Sending stop\n");
|
||||
strcpy(command,"S");
|
||||
return el737_transactCommand(priv,command,reply);
|
||||
}
|
||||
@ -419,14 +408,13 @@ static void runEvents(EL737priv *priv)
|
||||
{
|
||||
char command[COMLEN], reply[COMLEN], errName[256];
|
||||
int status;
|
||||
long dbStatus, nElements = 1, options = 0, threshCounter;
|
||||
long unsigned int myThreshold;
|
||||
long dbStatus, myThreshold, nElements = 1, options = 0, threshCounter;
|
||||
|
||||
/*
|
||||
This is the better way to set the threshold rather then the old way below which uses
|
||||
presets for that function. This one uses separate fields.
|
||||
*/
|
||||
if(priv->dbInit == 1 && priv->sendThreshold) {
|
||||
if(priv->dbInit == 1) {
|
||||
dbStatus = dbGetField(&priv->threshold,DBR_LONG,&myThreshold,&options, &nElements,NULL);
|
||||
if(dbStatus != 0){
|
||||
errSymLookup(dbStatus,errName,sizeof(errName));
|
||||
@ -437,16 +425,13 @@ static void runEvents(EL737priv *priv)
|
||||
we have to set the threshold
|
||||
*/
|
||||
dbStatus = dbGetField(&priv->threshCounter,DBR_LONG,&threshCounter, &options, &nElements,NULL);
|
||||
if(dbStatus != 0) {
|
||||
if(dbStatus != 0){
|
||||
errSymLookup(dbStatus,errName,sizeof(errName));
|
||||
errlogPrintf("Reading thresholdCounter failed with %s\n", errName);
|
||||
} else {
|
||||
if(threshCounter == 0){
|
||||
threshCounter = 1;
|
||||
}
|
||||
sprintf(command,"DL %d %d", (int)threshCounter,
|
||||
(int)myThreshold);
|
||||
// errlogPrintf("Sending threshold command %s\n", command);
|
||||
//errlogPrintf("Sending threshold command %s\n", command);
|
||||
status = el737_transactCommand(priv,command,reply);
|
||||
sprintf(command,"DR %d", (int)threshCounter);
|
||||
status = el737_transactCommand(priv, command,reply);
|
||||
@ -457,36 +442,35 @@ static void runEvents(EL737priv *priv)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(priv->sendThreshold == 1) {
|
||||
// fallback when we do not have the DB fields or threshCounter is invalid
|
||||
if(priv->presets[THRESHMON] > 0) {
|
||||
sprintf(command,"DL %d %d", (int)priv->presets[THRESHMON],
|
||||
(int)priv->presets[THRESHVAL]);
|
||||
// errlogPrintf("Sending threshold from presets, command %s\n", command);
|
||||
status = el737_transactCommand(priv,command,reply);
|
||||
sprintf(command,"DR %d", (int)priv->presets[THRESHMON]);
|
||||
status = el737_transactCommand(priv, command,reply);
|
||||
if(status == asynSuccess) {
|
||||
priv->sendThreshold = 0;
|
||||
}
|
||||
if(priv->sendThreshold == 1){
|
||||
sprintf(command,"DL %d %d", (int)priv->presets[THRESHMON],
|
||||
(int)priv->presets[THRESHVAL]);
|
||||
//errlogPrintf("Sending threshold command %s\n", command);
|
||||
status = el737_transactCommand(priv,command,reply);
|
||||
sprintf(command,"DR %d", (int)priv->presets[THRESHMON]);
|
||||
status = el737_transactCommand(priv, command,reply);
|
||||
if(status == asynSuccess){
|
||||
priv->sendThreshold = 0;
|
||||
}
|
||||
}
|
||||
|
||||
errlogPrintf("EL737: Doing a count command: %d\n", priv->countCommand);
|
||||
//errlogPrintf("Doing a count command: %d\n", priv->countCommand);
|
||||
if(priv->countCommand == 1){
|
||||
if(priv->presets[MODE] > 0) {
|
||||
/* preset monitor */
|
||||
sprintf(command,"MP %d", (int)priv->presets[MONITOR]);
|
||||
// errlogPrintf("EL737: Starting preset monitor\n");
|
||||
//errlogPrintf("Starting preset monitor\n");
|
||||
} else {
|
||||
/* preset time */
|
||||
sprintf(command,"TP %f", priv->presets[TIMER]/1000.);
|
||||
// errlogPrintf("EL737: Starting preset timer\n");
|
||||
//errlogPrintf("Starting preset timer\n");
|
||||
}
|
||||
status = el737_transactCommand(priv,command,reply);
|
||||
priv->counting = 1;
|
||||
if(status == asynSuccess){
|
||||
priv->counting = 1;
|
||||
}
|
||||
} else {
|
||||
if(priv->counting) {
|
||||
/* Stop */
|
||||
@ -498,8 +482,8 @@ static void runEvents(EL737priv *priv)
|
||||
|
||||
|
||||
if(status != asynSuccess){
|
||||
errlogPrintf("devScalerEL737::el737Thread communication problem %s\n, errno =%d",
|
||||
priv->asynContext->errorMessage, errno);
|
||||
errlogPrintf("devScalerEL737::el737Thread communication problem %s\n",
|
||||
priv->asynContext->errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@ -513,12 +497,8 @@ static void updateValues(EL737priv *priv)
|
||||
strcpy(command,"RA");
|
||||
status = el737_transactCommand(priv,command,reply);
|
||||
if(status != asynSuccess){
|
||||
if(errno == EAGAIN){
|
||||
errlogPrintf("devScalerEL737::el737Thread lost response to %s with EAGAIN\n", command);
|
||||
} else {
|
||||
errlogPrintf("devScalerEL737::el737Thread communication problem %s, errno = %d\n",
|
||||
priv->asynContext->errorMessage, errno);
|
||||
}
|
||||
errlogPrintf("devScalerEL737::el737Thread communication problem %s\n",
|
||||
priv->asynContext->errorMessage);
|
||||
return;
|
||||
}
|
||||
status = sscanf(reply, "%f %ld %ld %ld %ld %ld %ld %ld %ld",
|
||||
@ -556,11 +536,12 @@ static void el737Thread(void *param)
|
||||
int rs, ctStatus;
|
||||
long dbStatus, options, nElements = 1, pauseFlag = 0;
|
||||
|
||||
// errlogPrintf("EL737: Within EL737 thread \n");
|
||||
//errlogPrintf("Within EL737 thread \n");
|
||||
|
||||
while(1){
|
||||
evStatus = epicsEventWaitWithTimeout(priv->wakeUp,timeout);
|
||||
// errlogPrintf("EL737 thread woke up with %d\n", evStatus);
|
||||
//errlogPrintf("EL737 thread woke up with %d\n", evStatus);
|
||||
|
||||
|
||||
if(evStatus == epicsEventWaitOK) {
|
||||
/*
|
||||
@ -568,8 +549,7 @@ static void el737Thread(void *param)
|
||||
*/
|
||||
runEvents(priv);
|
||||
if(priv->counting == 1){
|
||||
timeout = .2;
|
||||
usleep(500);
|
||||
timeout = .1;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
@ -588,7 +568,7 @@ static void el737Thread(void *param)
|
||||
if(status != asynSuccess){
|
||||
errlogPrintf("devScalerEL737::el737Thread communication problem %s\n",
|
||||
priv->asynContext->errorMessage);
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
sscanf(reply,"%d",&rs);
|
||||
//errlogPrintf("RS = %d\n", rs);
|
||||
@ -637,7 +617,7 @@ static void el737Thread(void *param)
|
||||
if(status != asynSuccess){
|
||||
errlogPrintf("devScalerEL737::el737Thread communication problem %s\n",
|
||||
priv->asynContext->errorMessage);
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
} else if(pauseFlag == 0 && ctStatus == 3){
|
||||
strcpy(command,"CO");
|
||||
@ -645,7 +625,7 @@ static void el737Thread(void *param)
|
||||
if(status != asynSuccess){
|
||||
errlogPrintf("devScalerEL737::el737Thread communication problem %s\n",
|
||||
priv->asynContext->errorMessage);
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -7,28 +7,21 @@
|
||||
* Matthew Pearson
|
||||
* 23 May 2012
|
||||
*
|
||||
* Modified to use the MsgTxt field for SINQ
|
||||
*
|
||||
* Mark Koennecke, January 2019
|
||||
*
|
||||
* EXtended with special motor axis for the Selene
|
||||
* guide, Mark Koennecke, February 2020
|
||||
********************************************/
|
||||
|
||||
#ifndef pmacAxis_H
|
||||
#define pmacAxis_H
|
||||
|
||||
#include "SINQController.h"
|
||||
#include "SINQAxis.h"
|
||||
#include "asynMotorController.h"
|
||||
#include "asynMotorAxis.h"
|
||||
|
||||
class pmacController;
|
||||
class SeleneController;
|
||||
|
||||
class pmacAxis : public SINQAxis
|
||||
class pmacAxis : public asynMotorAxis
|
||||
{
|
||||
public:
|
||||
/* These are the methods we override from the base class */
|
||||
pmacAxis(pmacController *pController, int axisNo, bool enable=true);
|
||||
pmacAxis(pmacController *pController, int axisNo);
|
||||
virtual ~pmacAxis();
|
||||
asynStatus move(double position, int relative, double min_velocity, double max_velocity, double acceleration);
|
||||
asynStatus moveVelocity(double min_velocity, double max_velocity, double acceleration);
|
||||
@ -36,9 +29,8 @@ class pmacAxis : public SINQAxis
|
||||
asynStatus stop(double acceleration);
|
||||
asynStatus poll(bool *moving);
|
||||
asynStatus setPosition(double position);
|
||||
asynStatus enable(int on);
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
pmacController *pC_;
|
||||
|
||||
asynStatus getAxisStatus(bool *moving);
|
||||
@ -61,149 +53,9 @@ protected:
|
||||
time_t status6Time;
|
||||
int starting;
|
||||
int homing;
|
||||
double statusPos;
|
||||
|
||||
time_t next_poll;
|
||||
|
||||
bool autoEnable;
|
||||
|
||||
friend class pmacController;
|
||||
friend class pmacV3Controller;
|
||||
};
|
||||
/*--------------------------------------------------------------------------------------------*/
|
||||
class SeleneAxis : public pmacAxis
|
||||
{
|
||||
public:
|
||||
SeleneAxis(SeleneController *pController, int axisNo, double limitTarget);
|
||||
asynStatus move(double position, int relative, double min_velocity, double max_velocity, double acceleration);
|
||||
asynStatus setPosition(double position);
|
||||
asynStatus home(double min_velocity, double max_velocity, double acceleration, int forwards);
|
||||
|
||||
protected:
|
||||
friend class SeleneController;
|
||||
friend class pmacController;
|
||||
|
||||
private:
|
||||
double limitTarget;
|
||||
asynStatus getSeleneAxisInitialStatus(void);
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
Yet another special set of motors for the Selene Guide at AMOR. Each segment can be lifted or tilted. This is
|
||||
two motors. One acts as a slave and only writes a new target, the other also sets a new target and sends the
|
||||
actual movement command. Both motors are coordianted in the motor controller in order to avoid tension on
|
||||
the guide elements. This gaves rise to the function code LIFTSLAVE and LIFTMASTER.
|
||||
|
||||
In another mode the whole guide can be lifted or tilted. Then motor 1 and 6 get new values and one of them
|
||||
sends the drive command. This causes all 6 motors to drive synchronously to their new targets. This is
|
||||
implemented through the LIFTSEGMENT function code.
|
||||
|
||||
Mark Koennecke, February 2020
|
||||
|
||||
The axis should not be enabled automatically
|
||||
|
||||
Michele Brambilla, February 2020
|
||||
|
||||
*/
|
||||
class LiftAxis : public pmacAxis
|
||||
{
|
||||
public:
|
||||
LiftAxis(pmacController *pController, int axisNo) : pmacAxis((pmacController *)pController,axisNo) {};
|
||||
asynStatus move(double position, int relative, double min_velocity, double max_velocity, double acceleration);
|
||||
asynStatus poll(bool *moving);
|
||||
asynStatus stop(double acceleration);
|
||||
private:
|
||||
int waitStart;
|
||||
};
|
||||
|
||||
/********************************************
|
||||
* Protocol version 3 requires just some minor change
|
||||
*
|
||||
* Michele Brambilla, February 2022
|
||||
********************************************/
|
||||
|
||||
class pmacV3Axis : public pmacAxis {
|
||||
public:
|
||||
|
||||
pmacV3Axis(pmacController *pController, int axisNo);
|
||||
|
||||
asynStatus move(double position, int relative, double min_velocity,
|
||||
double max_velocity, double acceleration);
|
||||
asynStatus poll(bool *moving);
|
||||
protected:
|
||||
int IsEnable;
|
||||
double Speed;
|
||||
|
||||
asynStatus getAxisStatus(bool *moving);
|
||||
|
||||
friend class pmacController;
|
||||
friend class pmacV3Controller;
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------------------------*/
|
||||
class pmacHRPTAxis : public pmacV3Axis
|
||||
{
|
||||
public:
|
||||
pmacHRPTAxis(pmacController *pController, int axisNo) : pmacV3Axis(pController,axisNo) {};
|
||||
/**
|
||||
* Override getAxisStatus in order to read the special parameter indicating a
|
||||
* slit blade crash at HRPT
|
||||
*/
|
||||
asynStatus getAxisStatus(bool *moving);
|
||||
|
||||
protected:
|
||||
friend class pmacController;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Special motors for the AMOR detector movement. The whole
|
||||
* command set is different but on a pmac controller. This implements
|
||||
* a coordinated movement of cox, coz and ftz in order not to break
|
||||
* the flight tube which may have been mounted. This is mapped to three
|
||||
* motors selected via the function code: com, the detector omega, coz,
|
||||
* the detector z offset and park, for parking the flightpath.
|
||||
*/
|
||||
|
||||
#define ADCOM 1
|
||||
#define ADCOZ 2
|
||||
#define ADPARK 3
|
||||
|
||||
class AmorDetectorAxis: public pmacAxis {
|
||||
public:
|
||||
AmorDetectorAxis(pmacController *pController, int axisNo, int function);
|
||||
|
||||
asynStatus move(double position, int relative, double min_velocity,
|
||||
double max_velocity, double acceleration);
|
||||
asynStatus poll(bool *moving);
|
||||
asynStatus moveVelocity(double min_velocity, double max_velocity, double acceleration);
|
||||
asynStatus home(double min_velocity, double max_velocity, double acceleration, int forwards);
|
||||
asynStatus stop(double acceleration);
|
||||
asynStatus setPosition(double position);
|
||||
|
||||
protected:
|
||||
int _function;
|
||||
int det_starting;
|
||||
time_t det_startTime;
|
||||
};
|
||||
|
||||
/*----------------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
class GirderAxis: public pmacV3Axis {
|
||||
public:
|
||||
GirderAxis(pmacController *pController, int axisNo);
|
||||
asynStatus move(double position, int relative, double min_velocity, double max_velocity, double acceleration);
|
||||
asynStatus stop(double acceleration);
|
||||
asynStatus poll(bool *moving);
|
||||
|
||||
protected:
|
||||
int IsEnable;
|
||||
|
||||
friend class pmacController;
|
||||
friend class pmacV3Controller;
|
||||
};
|
||||
|
||||
#endif /* pmacAxis_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -7,27 +7,23 @@
|
||||
* Matthew Pearson
|
||||
* 23 May 2012
|
||||
*
|
||||
*
|
||||
* Modified to use the MsgTxt field for SINQ
|
||||
*
|
||||
* Mark Koennecke, January 2019
|
||||
********************************************/
|
||||
|
||||
#ifndef pmacController_H
|
||||
#define pmacController_H
|
||||
|
||||
#include "SINQController.h"
|
||||
#include "asynMotorController.h"
|
||||
#include "asynMotorAxis.h"
|
||||
#include "pmacAxis.h"
|
||||
|
||||
#define PMAC_C_GlobalStatusString "PMAC_C_GLOBALSTATUS"
|
||||
#define PMAC_C_CommsErrorString "PMAC_C_COMMSERROR"
|
||||
|
||||
class pmacController : public SINQController {
|
||||
class pmacController : public asynMotorController {
|
||||
|
||||
public:
|
||||
pmacController(const char *portName, const char *lowLevelPortName, int lowLevelPortAddress, int numAxes, double movingPollPeriod,
|
||||
double idlePollPeriod, const int& extraParams=2);
|
||||
pmacController(const char *portName, const char *lowLevelPortName, int lowLevelPortAddress, int numAxes, double movingPollPeriod,
|
||||
double idlePollPeriod);
|
||||
|
||||
virtual ~pmacController();
|
||||
|
||||
@ -41,6 +37,7 @@ class pmacController : public SINQController {
|
||||
pmacAxis* getAxis(int axisNo);
|
||||
asynStatus poll();
|
||||
|
||||
|
||||
protected:
|
||||
pmacAxis **pAxes_; /**< Array of pointers to axis objects */
|
||||
|
||||
@ -48,13 +45,13 @@ class pmacController : public SINQController {
|
||||
int PMAC_C_GlobalStatus_;
|
||||
int PMAC_C_CommsError_;
|
||||
#define LAST_PMAC_PARAM PMAC_C_CommsError__
|
||||
void debugFlow(const char *message);
|
||||
asynStatus lowLevelWriteRead(int axisNo, const char *command, char *response);
|
||||
|
||||
private:
|
||||
asynUser* lowLevelPortUser_;
|
||||
epicsUInt32 debugFlag_;
|
||||
asynStatus lowLevelWriteRead(const char *command, char *response);
|
||||
int lowLevelPortConnect(const char *port, int addr, asynUser **ppasynUser, char *inputEos, char *outputEos);
|
||||
void debugFlow(const char *message);
|
||||
|
||||
//static class data members
|
||||
|
||||
@ -135,64 +132,9 @@ class pmacController : public SINQController {
|
||||
static const epicsUInt32 PMAX_AXIS_GENERAL_PROB2;
|
||||
|
||||
friend class pmacAxis;
|
||||
friend class pmacHRPTAxis;
|
||||
friend class SeleneAxis;
|
||||
friend class LiftAxis;
|
||||
friend class pmacV3Axis;
|
||||
friend class GirderAxis;
|
||||
friend class AmorDetectorAxis;
|
||||
|
||||
};
|
||||
|
||||
#define NUM_PMAC_PARAMS (&LAST_PMAC_PARAM - &FIRST_PMAC_PARAM + 1)
|
||||
|
||||
#define MotorSetPositionString "SET_MOTOR_POSITION"
|
||||
|
||||
class SeleneController : public pmacController {
|
||||
public:
|
||||
SeleneController(const char *portName, const char *lowLevelPortName, int lowLevelPortAddress,
|
||||
int numAxes, double movingPollPeriod, double idlePollPeriod);
|
||||
|
||||
~SeleneController(void) { }
|
||||
|
||||
// overloaded because we have a different command to set the limits
|
||||
asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value);
|
||||
|
||||
friend class SeleneAxis;
|
||||
friend class pmacAxis;
|
||||
|
||||
protected:
|
||||
int setMotorPosition_;
|
||||
|
||||
};
|
||||
|
||||
#define EnableAxisString "ENABLE_AXIS"
|
||||
#define AxisEnabledString "AXIS_ENABLED"
|
||||
#define ReReadEncoderPositionString "REREAD_ENCODER_POSITION"
|
||||
#define ReReadEncoderPositionString_RBV "REREAD_ENCODER_POSITION_RBV"
|
||||
|
||||
class pmacV3Controller : public pmacController {
|
||||
public:
|
||||
pmacV3Controller(const char *portName, const char *lowLevelPortName,
|
||||
int lowLevelPortAddress, int numAxes, double movingPollPeriod,
|
||||
double idlePollPeriod, const int &extraParams = 4);
|
||||
|
||||
// overloaded because we want to enable/disable the motor
|
||||
asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
|
||||
|
||||
// overloaded because we want to read the axis state
|
||||
asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value);
|
||||
|
||||
friend class pmacV3Axis;
|
||||
friend class pmacAxis;
|
||||
friend class GirderAxis;
|
||||
|
||||
protected:
|
||||
pmacV3Axis **pAxes_; /**< Array of pointers to axis objects */
|
||||
|
||||
int enableAxis_;
|
||||
int axisEnabled_;
|
||||
int rereadEncoderPosition_;
|
||||
int rereadEncoderPositionRBV_;
|
||||
};
|
||||
|
||||
#endif /* pmacController_H */
|
||||
|
@ -1,96 +0,0 @@
|
||||
#include "pollerRegister.h"
|
||||
|
||||
#include <vector>
|
||||
#include <cstdio>
|
||||
|
||||
#include "libComAPI.h"
|
||||
#include "initHooks.h"
|
||||
|
||||
static std::vector<std::function<void()>> registeredFunctions;
|
||||
|
||||
static void startPollingHook(initHookState state) {
|
||||
switch (state) {
|
||||
case initHookAtIocBuild:
|
||||
printf("\n\n\ninitHookAtIocBuild\n\n\n");
|
||||
break;
|
||||
|
||||
case initHookAtBeginning:
|
||||
printf("\n\n\ninitHookAtBeginning\n\n\n");
|
||||
break;
|
||||
|
||||
case initHookAfterCallbackInit:
|
||||
printf("\n\n\ninitHookAfterCallbackInit\n\n\n");
|
||||
break;
|
||||
|
||||
case initHookAfterCaLinkInit:
|
||||
printf("\n\n\ninitHookAfterCaLinkInit\n\n\n");
|
||||
break;
|
||||
|
||||
case initHookAfterInitDrvSup:
|
||||
printf("\n\n\ninitHookAfterInitDrvSup\n\n\n");
|
||||
break;
|
||||
|
||||
case initHookAfterInitRecSup:
|
||||
printf("\n\n\ninitHookAfterInitRecSup\n\n\n");
|
||||
break;
|
||||
|
||||
case initHookAfterInitDevSup:
|
||||
printf("\n\n\ninitHookAfterInitDevSup\n\n\n");
|
||||
break;
|
||||
|
||||
case initHookAfterInitDatabase:
|
||||
printf("\n\n\ninitHookAfterInitDatabase\n\n\n");
|
||||
break;
|
||||
|
||||
case initHookAfterFinishDevSup:
|
||||
printf("\n\n\ninitHookAfterFinishDevSup\n\n\n");
|
||||
break;
|
||||
|
||||
case initHookAfterScanInit:
|
||||
printf("\n\n\ninitHookAfterScanInit\n\n\n");
|
||||
break;
|
||||
|
||||
case initHookAfterInitialProcess:
|
||||
printf("\n\n\ninitHookAfterInitialProcess\n\n\n");
|
||||
break;
|
||||
|
||||
case initHookAfterCaServerInit:
|
||||
printf("\n\n\ninitHookAfterCaServerInit\n\n\n");
|
||||
break;
|
||||
|
||||
case initHookAfterIocBuilt:
|
||||
printf("\n\n\ninitHookAfterIocBuilt\n\n\n");
|
||||
break;
|
||||
|
||||
case initHookAtIocRun:
|
||||
printf("\n\n\ninitHookAtIocRun\n\n\n");
|
||||
break;
|
||||
|
||||
case initHookAfterDatabaseRunning:
|
||||
printf("\n\n\ninitHookAfterDatabaseRunning\n\n\n");
|
||||
break;
|
||||
|
||||
case initHookAtEnd:
|
||||
printf("\n\n\ninitHookAtEnd\n\n\n");
|
||||
break;
|
||||
|
||||
case initHookAfterCaServerRunning:
|
||||
printf("\n\n\ninitHookAfterCaServerRunning\n\n\n");
|
||||
break;
|
||||
|
||||
case initHookAfterIocRunning:
|
||||
printf("\n\n\ninitHookAfterIocRunning\n\n\n");
|
||||
for(auto&& fn : registeredFunctions)
|
||||
fn();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int myHookStatus = initHookRegister(startPollingHook);
|
||||
|
||||
void registerFunction(std::function<void()> func) {
|
||||
registeredFunctions.push_back(func);
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
#ifndef POLLERREGISTER
|
||||
#define POLLERREGISTER
|
||||
|
||||
#include <functional>
|
||||
|
||||
void registerFunction(std::function<void()> func);
|
||||
|
||||
#endif
|
@ -2,25 +2,21 @@
|
||||
# SINQ specific DB definitions
|
||||
#---------------------------------------------
|
||||
registrar(EL734Register)
|
||||
registrar(PhytronRegister)
|
||||
registrar(EuroMoveRegister)
|
||||
registrar(NanotecRegister)
|
||||
registrar(pmacControllerRegister)
|
||||
registrar(pmacAsynIPPortRegister)
|
||||
registrar(MasterMACSRegister)
|
||||
registrar(SINQControllerRegister)
|
||||
|
||||
#--------------------------------------------------------
|
||||
# With the PSI module build system, including these items actually
|
||||
# hurts. It causes missing symbols when loading the shared lib.
|
||||
#------------------------------------------------------------------
|
||||
#include "/ioc/modules/asyn/427.0.1/R3.14.12/dbd/asyn.dbd"
|
||||
#include "/ioc/modules/motorBase/6.9.12/R3.14.12/dbd/motorBase.dbd"
|
||||
#include "/ioc/modules/SynApps/1.13.0/R3.14.12/dbd/SynApps.dbd"
|
||||
#include "/ioc/modules/scaler/koennecke/R3.14.12/dbd/scaler.dbd"
|
||||
addpath "/opt/epics/modules/asyn/4.27.0/3.14.12.5/dbd"
|
||||
addpath "/opt/epics/bases/base-3.14.12.5/dbd"
|
||||
addpath "/opt/epics/modules/motor/6.10.0/3.14.12.5/dbd"
|
||||
#addpath "/usr/local/epics/support/std-3-1/dbd"
|
||||
addpath "/opt/epics/modules/synAppsStd/3.4.1/3.14.12.5/dbd"
|
||||
include "asyn.dbd"
|
||||
include "motor.dbd"
|
||||
#include "motorSupport.dbd"
|
||||
|
||||
include "synAppsStd.dbd"
|
||||
device(scaler,INST_IO,devScalerEL737,"asynScalerEL737")
|
||||
|
||||
#--------- For lakeshore and magnets
|
||||
#include "/ioc/modules/stream/2.7.9/R3.14.12/dbd/stream.dbd"
|
||||
#include "busy.dbd"
|
||||
#--------- For lakeshore
|
||||
addpath "/opt/epics/modules/streamdevice/2.6.0/3.14.12.5/dbd"
|
||||
include "streamdevice.dbd"
|
||||
addpath "/opt/epics/modules/busy/1.6.0/3.14.12.5/dbd"
|
||||
include "busy.dbd"
|
||||
|
@ -1,88 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: iso-8859-1 -*-
|
||||
"""
|
||||
Created on Thur Feb 06 10:22:42 2020
|
||||
|
||||
@author: gaston emmanuel exil
|
||||
"""
|
||||
|
||||
#pip install pyusb
|
||||
#sudo cp 10-llbDevices.rules /etc/udev/rules.d/
|
||||
#sudo udevadm control --reload-rules && udevadm trigger
|
||||
#reboot
|
||||
|
||||
import sys
|
||||
import usb.core
|
||||
import usb.util
|
||||
from time import sleep
|
||||
|
||||
# 1. Device
|
||||
llbVendorID=0x04B4
|
||||
llbProductID=0x1002
|
||||
|
||||
# 2. Configuration
|
||||
CONFIGURATION_EV3 = 1 # 1-based
|
||||
# 3. Interface
|
||||
INTERFACE_EV3 = 0 # 0-based
|
||||
# 4. Alternate setting
|
||||
SETTING_EV3 = 0 # 0-based
|
||||
# 5. Endpoint
|
||||
ENDPOINT_EV3 = 1 # 0-based
|
||||
|
||||
# find our device
|
||||
device = usb.core.find(idVendor=llbVendorID, idProduct=llbProductID)
|
||||
|
||||
# was it found?
|
||||
if device is None:
|
||||
raise ValueError('Device not found')
|
||||
sys.exit(1)
|
||||
else:
|
||||
if device._manufacturer is None:
|
||||
device._manufacturer = usb.util.get_string(device, device.iManufacturer)
|
||||
print("manufacturer: ", str(device._manufacturer))
|
||||
if device._product is None:
|
||||
device._product = usb.util.get_string(device, device.iProduct)
|
||||
print("product: ", str(device._product))
|
||||
|
||||
|
||||
# By default, the kernel will claim the device and make it available via
|
||||
# /dev/usb/hiddevN and /dev/hidrawN which also prevents us
|
||||
# from communicating otherwise. This removes these kernel devices.
|
||||
# Yes, it is weird to specify an interface before we get to a configuration.
|
||||
|
||||
if device.is_kernel_driver_active(INTERFACE_EV3):
|
||||
print("Detaching kernel driver")
|
||||
device.detach_kernel_driver(INTERFACE_EV3)
|
||||
|
||||
# claim the device
|
||||
usb.util.claim_interface(device, INTERFACE_EV3)
|
||||
|
||||
# write endpoint
|
||||
endpoint_BulkOut = device[0][(0,0)][0]
|
||||
# Read endpoint
|
||||
endpoint_BulkIn = device[0][(0,0)][2]
|
||||
try:
|
||||
command = "L"+chr(13)
|
||||
assert device.write(endpoint_BulkOut, command.encode('utf-8'), 100) == len(command)
|
||||
ret = device.read(endpoint_BulkIn, endpoint_BulkIn.wMaxPacketSize, timeout=30000)
|
||||
print(ret)
|
||||
#byte_str = "".join(chr(n) for n in ret)
|
||||
print(ret.tostring())
|
||||
|
||||
|
||||
|
||||
command = "A1,4"+chr(13)
|
||||
assert device.write(endpoint_BulkOut, command.encode('utf-8'), 100) == len(command)
|
||||
ret = device.read(endpoint_BulkIn, endpoint_BulkIn.wMaxPacketSize, timeout=30000)
|
||||
print(ret)
|
||||
byte_str = "".join(chr(n) for n in ret)
|
||||
print(ret.tostring())
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
|
||||
# release the device
|
||||
usb.util.release_interface(device, INTERFACE_EV3)
|
||||
# reattach the device to the OS kernel
|
||||
#device.attach_kernel_driver(INTERFACE_EV3)
|
@ -1,23 +0,0 @@
|
||||
record(motor,"$(P)$(M)")
|
||||
{
|
||||
field(DESC,"$(DESC)")
|
||||
field(DTYP,"$(DTYP)")
|
||||
field(DIR,"$(DIR)")
|
||||
field(VELO,"$(VELO)")
|
||||
field(VBAS,"$(VBAS)")
|
||||
field(ACCL,"$(ACCL)")
|
||||
field(BDST,"$(BDST)")
|
||||
field(BVEL,"$(BVEL)")
|
||||
field(BACC,"$(BACC)")
|
||||
field(OUT,"@asyn($(PORT),$(ADDR))")
|
||||
field(MRES,"$(MRES)")
|
||||
field(PREC,"$(PREC)")
|
||||
field(EGU,"$(EGU)")
|
||||
field(DHLM,"$(DHLM)")
|
||||
field(DLLM,"$(DLLM)")
|
||||
field(INIT,"$(INIT)")
|
||||
field(TWV,"1")
|
||||
field(RDBD,"$(RDBD)")
|
||||
field(RTRY,"0")
|
||||
}
|
||||
|
@ -1,21 +0,0 @@
|
||||
grecord(motor,"$(P)$(M)")
|
||||
{
|
||||
field(DESC,"$(DESC)")
|
||||
field(DTYP,"$(DTYP)")
|
||||
field(DIR,"$(DIR)")
|
||||
field(VELO,"$(VELO)")
|
||||
field(VBAS,"$(VBAS)")
|
||||
field(ACCL,"$(ACCL)")
|
||||
field(BDST,"$(BDST)")
|
||||
field(BVEL,"$(BVEL)")
|
||||
field(BACC,"$(BACC)")
|
||||
field(OUT,"#C$(C) S$(S) @")
|
||||
field(MRES,"$(MRES)")
|
||||
field(PREC,"$(PREC)")
|
||||
field(EGU,"$(EGU)")
|
||||
field(DHLM,"$(DHLM)")
|
||||
field(DLLM,"$(DLLM)")
|
||||
field(INIT,"$(INIT)")
|
||||
field(TWV,"1")
|
||||
}
|
||||
|
@ -1,18 +0,0 @@
|
||||
|
||||
# The message text
|
||||
record(waveform, "$(P)$(M)-MsgTxt") {
|
||||
field(DTYP, "asynOctetRead")
|
||||
field(INP, "@asyn($(PORT),$(N),1) MOTOR_MESSAGE_TEXT")
|
||||
field(FTVL, "CHAR")
|
||||
field(NELM, "80")
|
||||
field(SCAN, "I/O Intr")
|
||||
}
|
||||
|
||||
record(ao,"$(P)m$(N)-Resolution"){
|
||||
field(DESC,"m$(N) Resolution")
|
||||
field(DOL,"$(P)m$(N).MRES CP MS")
|
||||
field(OMSL,"closed_loop")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(OUT,"@asyn($(PORT),$(N))MOTOR_RESOLUTION")
|
||||
field(PREC,"3")
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
record(motor,"$(P)$(M)")
|
||||
{
|
||||
field(DESC,"$(DESC)")
|
||||
field(DTYP,"$(DTYP)")
|
||||
field(DIR,"$(DIR)")
|
||||
field(VELO,"$(VELO)")
|
||||
field(VMAX,"$(VMAX=$(VELO))")
|
||||
field(VBAS,"$(VBAS)")
|
||||
field(ACCL,"$(ACCL)")
|
||||
field(BDST,"$(BDST)")
|
||||
field(BVEL,"$(BVEL)")
|
||||
field(BACC,"$(BACC)")
|
||||
field(OUT,"@asyn($(PORT),$(ADDR))")
|
||||
field(MRES,"$(MRES)")
|
||||
field(PREC,"$(PREC)")
|
||||
field(EGU,"$(EGU)")
|
||||
field(DHLM,"$(DHLM)")
|
||||
field(DLLM,"$(DLLM)")
|
||||
field(INIT,"$(INIT)")
|
||||
field(TWV,"1")
|
||||
field(RDBD,"$(RDBD)")
|
||||
}
|
||||
|
||||
|
||||
# The message text
|
||||
record(waveform, "$(P)$(M)-MsgTxt") {
|
||||
field(DTYP, "asynOctetRead")
|
||||
field(INP, "@asyn($(PORT),$(N),1) MOTOR_MESSAGE_TEXT")
|
||||
field(FTVL, "CHAR")
|
||||
field(NELM, "80")
|
||||
field(SCAN, "I/O Intr")
|
||||
}
|
||||
|
||||
# enable axis
|
||||
record(longout, "$(P)$(M):Enable") {
|
||||
field(DTYP, "asynInt32")
|
||||
field(OUT, "@asyn($(PORT),$(N),1) ENABLE_AXIS")
|
||||
field(PINI, "YES")
|
||||
}
|
||||
|
||||
# enable axis
|
||||
record(longin, "$(P)$(M):Enable_RBV") {
|
||||
field(DTYP, "asynInt32")
|
||||
field(INP, "@asyn($(PORT),$(N),1) AXIS_ENABLED")
|
||||
field(PINI, "YES")
|
||||
field(SCAN, "1 second")
|
||||
}
|
||||
|
@ -1,13 +0,0 @@
|
||||
file "$(TOP)/db/basic_asyn_motor.db"
|
||||
{
|
||||
pattern
|
||||
{P, N, M, DTYP, PORT, ADDR, DESC, EGU, DIR, VELO, VBAS, ACCL, BDST, BVEL, BACC, MRES, PREC, DLLM, DHLM, INIT}
|
||||
{KM36:mota:, 2, "m$(N)", "asynMotor", mota, 2, "sgl", degree, Pos, 2.0, 0.1, .2, 0, 1, .2, 1., 3, -20.0, 20.0, ""}
|
||||
}
|
||||
|
||||
file "$(TOP)/db/motorMessage.db"
|
||||
{
|
||||
pattern
|
||||
{P,N, M,PORT}
|
||||
{KM36:mota:, 2, "m$(N)",mota}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
file "$(TOP)/db/sinq_asyn_motor.db"
|
||||
{
|
||||
pattern
|
||||
{P, N, M, DTYP, PORT, ADDR, DESC, EGU, DIR, VELO, VBAS, ACCL, BDST, BVEL, BACC, MRES, PREC, DLLM, DHLM, INIT, RDBD}
|
||||
{KM36:mota:,2,"m$(N)","asynMotor", mota, 2, "sgl", degree, Pos, 100, 0.1, .2, 0, 1, .2, 1., 3,-180.0,360.0,"", 0.2}}
|
||||
|
||||
file "$(TOP)/db/motorMessage.db"
|
||||
{
|
||||
pattern
|
||||
{P,N, M,PORT}
|
||||
{KM36:mota:, 2, "m$(N)",mota}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
#!/usr/local/bin/iocsh
|
||||
|
||||
require sinq,koennecke
|
||||
|
||||
epicsEnvSet("TOP","/afs/psi.ch/project/sinqdev/sinqepicsapp/testel734")
|
||||
|
||||
drvAsynIPPortConfigure("serial1", "localhost:61000",0,0,0)
|
||||
EL734CreateController("mota","serial1",3)
|
||||
|
||||
#dbLoadTemplate "mota.sub"
|
||||
dbLoadTemplate "motaspeed.sub"
|
||||
|
@ -1,11 +0,0 @@
|
||||
#!/usr/local/bin/iocsh
|
||||
|
||||
require sinq,koennecke
|
||||
|
||||
epicsEnvSet("TOP","/afs/psi.ch/project/sinqdev/sinqepicsapp")
|
||||
|
||||
#--------- load EL737 counter box
|
||||
drvAsynIPPortConfigure("cter1","localhost:62000",0,0,0)
|
||||
dbLoadRecords("$(TOP)/db/asynRecord.db","P=KM36:,R=cter1,PORT=cter1,ADDR=0,OMAX=80,IMAX=80")
|
||||
dbLoadRecords("${TOP}/db/el737Record.db","P=KM36:counter,PORT=cter1,DESC=SANSCounter")
|
||||
|
@ -1,9 +0,0 @@
|
||||
record(asyn,"$(P)$(R)")
|
||||
{
|
||||
field(DTYP,"asynRecordDevice")
|
||||
field(PORT,"$(PORT)")
|
||||
field(ADDR,"$(ADDR)")
|
||||
field(OMAX,"$(OMAX)")
|
||||
field(IMAX,"$(IMAX)")
|
||||
}
|
||||
|
@ -1,23 +0,0 @@
|
||||
record(motor,"$(P)$(M)")
|
||||
{
|
||||
field(DESC,"$(DESC)")
|
||||
field(DTYP,"$(DTYP)")
|
||||
field(DIR,"$(DIR)")
|
||||
field(VELO,"$(VELO)")
|
||||
field(VBAS,"$(VBAS)")
|
||||
field(ACCL,"$(ACCL)")
|
||||
field(BDST,"$(BDST)")
|
||||
field(BVEL,"$(BVEL)")
|
||||
field(BACC,"$(BACC)")
|
||||
field(OUT,"@asyn($(PORT),$(ADDR))")
|
||||
field(MRES,"$(MRES)")
|
||||
field(PREC,"$(PREC)")
|
||||
field(EGU,"$(EGU)")
|
||||
field(DHLM,"$(DHLM)")
|
||||
field(DLLM,"$(DLLM)")
|
||||
field(INIT,"$(INIT)")
|
||||
field(TWV,"1")
|
||||
field(RDBD,"$(RDBD)")
|
||||
field(RTRY,"0")
|
||||
}
|
||||
|
@ -1,21 +0,0 @@
|
||||
grecord(motor,"$(P)$(M)")
|
||||
{
|
||||
field(DESC,"$(DESC)")
|
||||
field(DTYP,"$(DTYP)")
|
||||
field(DIR,"$(DIR)")
|
||||
field(VELO,"$(VELO)")
|
||||
field(VBAS,"$(VBAS)")
|
||||
field(ACCL,"$(ACCL)")
|
||||
field(BDST,"$(BDST)")
|
||||
field(BVEL,"$(BVEL)")
|
||||
field(BACC,"$(BACC)")
|
||||
field(OUT,"#C$(C) S$(S) @")
|
||||
field(MRES,"$(MRES)")
|
||||
field(PREC,"$(PREC)")
|
||||
field(EGU,"$(EGU)")
|
||||
field(DHLM,"$(DHLM)")
|
||||
field(DLLM,"$(DLLM)")
|
||||
field(INIT,"$(INIT)")
|
||||
field(TWV,"1")
|
||||
}
|
||||
|
@ -1,18 +0,0 @@
|
||||
|
||||
# The message text
|
||||
record(waveform, "$(P)$(M)-MsgTxt") {
|
||||
field(DTYP, "asynOctetRead")
|
||||
field(INP, "@asyn($(PORT),$(N),1) MOTOR_MESSAGE_TEXT")
|
||||
field(FTVL, "CHAR")
|
||||
field(NELM, "80")
|
||||
field(SCAN, "I/O Intr")
|
||||
}
|
||||
|
||||
record(ao,"$(P)m$(N)-Resolution"){
|
||||
field(DESC,"m$(N) Resolution")
|
||||
field(DOL,"$(P)m$(N).MRES CP MS")
|
||||
field(OMSL,"closed_loop")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(OUT,"@asyn($(PORT),$(N))MOTOR_RESOLUTION")
|
||||
field(PREC,"3")
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
# enable axis
|
||||
record(longout, "$(P)$(M):Enable") {
|
||||
field(DTYP, "asynInt32")
|
||||
field(OUT, "@asyn($(PORT),$(N),1) ENABLE_AXIS")
|
||||
field(PINI, "YES")
|
||||
}
|
||||
|
||||
# enable axis
|
||||
record(longin, "$(P)$(M):Enable_RBV") {
|
||||
field(DTYP, "asynInt32")
|
||||
field(INP, "@asyn($(PORT),$(N),1) AXIS_ENABLED")
|
||||
field(PINI, "YES")
|
||||
field(SCAN, "1 second")
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
record(motor,"$(P)$(M)")
|
||||
{
|
||||
field(DESC,"$(DESC)")
|
||||
field(DTYP,"$(DTYP)")
|
||||
field(DIR,"$(DIR)")
|
||||
field(VELO,"$(VELO)")
|
||||
field(VBAS,"$(VBAS)")
|
||||
field(ACCL,"$(ACCL)")
|
||||
field(BDST,"$(BDST)")
|
||||
field(BVEL,"$(BVEL)")
|
||||
field(BACC,"$(BACC)")
|
||||
field(OUT,"@asyn($(PORT),$(ADDR))")
|
||||
field(MRES,"$(MRES)")
|
||||
field(PREC,"$(PREC)")
|
||||
field(EGU,"$(EGU)")
|
||||
field(DHLM,"$(DHLM)")
|
||||
field(DLLM,"$(DLLM)")
|
||||
field(INIT,"$(INIT)")
|
||||
field(TWV,"1")
|
||||
field(RDBD,"$(RDBD)")
|
||||
}
|
||||
|
||||
|
||||
# The message text
|
||||
record(waveform, "$(P)$(M)-MsgTxt") {
|
||||
field(DTYP, "asynOctetRead")
|
||||
field(INP, "@asyn($(PORT),$(N),1) MOTOR_MESSAGE_TEXT")
|
||||
field(FTVL, "CHAR")
|
||||
field(NELM, "80")
|
||||
field(SCAN, "I/O Intr")
|
||||
}
|
||||
|
||||
# enable axis
|
||||
record(longout, "$(P)$(M):Enable") {
|
||||
field(DTYP, "asynInt32")
|
||||
field(OUT, "@asyn($(PORT),$(N),1) ENABLE_AXIS")
|
||||
field(PINI, "YES")
|
||||
}
|
||||
|
||||
# enable axis
|
||||
record(longin, "$(P)$(M):Enable_RBV") {
|
||||
field(DTYP, "asynInt32")
|
||||
field(INP, "@asyn($(PORT),$(N),1) AXIS_ENABLED")
|
||||
field(PINI, "YES")
|
||||
field(SCAN, "5 second")
|
||||
}
|
||||
|
@ -1,33 +0,0 @@
|
||||
#!/ioc/tools/iocsh
|
||||
|
||||
require motorHuber,brambilla_m
|
||||
|
||||
# epicsEnvSet("TOP","/ioc/sinq-ioc/boa-ioc")
|
||||
|
||||
epicsEnvSet("TOP","/afs/psi.ch/project/sinqdev/sinqepicsapp/testhuber")
|
||||
|
||||
epicsEnvSet("STREAM_PROTOCOL_PATH","./db")
|
||||
epicsEnvSet("MOTOR",".")
|
||||
|
||||
# require autosave, koennecke
|
||||
|
||||
# Configure IP Port
|
||||
drvAsynIPPortConfigure("Huber1", "129.129.195.128:1234",0,0,0)
|
||||
|
||||
# Configure Controller
|
||||
asynOctetSetInputEos( "Huber1", -1, "\r")
|
||||
asynOctetSetOutputEos("Huber1", -1, "\r")
|
||||
|
||||
SMC9300CreateController("SMC1", "Huber1", 5, 50, 2000)
|
||||
|
||||
dbLoadTemplate "motor.substitutions.smc9300"
|
||||
|
||||
dbLoadRecords("$(TOP)/db/asynRecord.db","P=SQ:BOA:optics:,R=mcu,PORT=Huber1,ADDR=0,OMAX=80,IMAX=80")
|
||||
|
||||
|
||||
#--------------------------------- restore autosave
|
||||
#set_requestfile_path("$(TOP)", "")
|
||||
#set_savefile_path("$(TOP)/autosave")
|
||||
#save_restoreSet_Debug(0)
|
||||
#set_pass0_restoreFile("$(TOP)/autosave/huber.sav","")
|
||||
#set_pass1_restoreFile("$(TOP)/autosave/huber.sav","")
|
@ -1,19 +0,0 @@
|
||||
file "$(MOTOR)/db/basic_asyn_motor.db"
|
||||
{
|
||||
pattern
|
||||
{P, N, M, DTYP, PORT, ADDR,DESC, EGU, DIR, VELO, VBAS, ACCL, BDST, BVEL, BACC, MRES, PREC, DHLM, DLLM, RDBD, INIT}
|
||||
{SQ:BOA:optics:, 1, "trans1","asynMotor", SMC1, 1, "translation 1",mm, Pos, 200, 10, 20, 0, 1, .2, 0.0001, 4, 150, -150, 0.1, ""}
|
||||
{SQ:BOA:optics:, 2, "lift1", "asynMotor", SMC1, 2, "lift 1", mm, Pos, 200, 10, 80, 0, 1, .2, 0.0001, 4, 100, 0, 0.1, ""}
|
||||
{SQ:BOA:optics:, 3, "trans2","asynMotor", SMC1, 3, "translation 2",mm, Pos, 200, 10, 80, 0, 1, .2, 0.0001, 4, 150, -150, 0.1, ""}
|
||||
{SQ:BOA:optics:, 4, "lift2", "asynMotor", SMC1, 4, "lift 2" ,mm, Pos, 200, 10, 80, 0, 1, .2, 0.0001, 4, 100, 0, 0.1, ""}
|
||||
}
|
||||
|
||||
file "$(TOP)/db/motorMessage.db"
|
||||
{
|
||||
pattern
|
||||
{P,N, M,PORT}
|
||||
{SQ:BOA:optics:, 1, "trans1", SMC1}
|
||||
{SQ:BOA:optics:, 2, "lift1", SMC1}
|
||||
{SQ:BOA:optics:, 3, "trans2", SMC1}
|
||||
{SQ:BOA:optics:, 4, "lift2", SMC1}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
record(asyn,"$(P)$(R)")
|
||||
{
|
||||
field(DTYP,"asynRecordDevice")
|
||||
field(PORT,"$(PORT)")
|
||||
field(ADDR,"$(ADDR)")
|
||||
field(OMAX,"$(OMAX)")
|
||||
field(IMAX,"$(IMAX)")
|
||||
}
|
||||
|
@ -1,23 +0,0 @@
|
||||
record(motor,"$(P)$(M)")
|
||||
{
|
||||
field(DESC,"$(DESC)")
|
||||
field(DTYP,"$(DTYP)")
|
||||
field(DIR,"$(DIR)")
|
||||
field(VELO,"$(VELO)")
|
||||
field(VBAS,"$(VBAS)")
|
||||
field(ACCL,"$(ACCL)")
|
||||
field(BDST,"$(BDST)")
|
||||
field(BVEL,"$(BVEL)")
|
||||
field(BACC,"$(BACC)")
|
||||
field(OUT,"@asyn($(PORT),$(ADDR))")
|
||||
field(MRES,"$(MRES)")
|
||||
field(PREC,"$(PREC)")
|
||||
field(EGU,"$(EGU)")
|
||||
field(DHLM,"$(DHLM)")
|
||||
field(DLLM,"$(DLLM)")
|
||||
field(INIT,"$(INIT)")
|
||||
field(TWV,"1")
|
||||
field(RDBD,"$(RDBD)")
|
||||
field(RTRY,"0")
|
||||
}
|
||||
|
@ -1,21 +0,0 @@
|
||||
grecord(motor,"$(P)$(M)")
|
||||
{
|
||||
field(DESC,"$(DESC)")
|
||||
field(DTYP,"$(DTYP)")
|
||||
field(DIR,"$(DIR)")
|
||||
field(VELO,"$(VELO)")
|
||||
field(VBAS,"$(VBAS)")
|
||||
field(ACCL,"$(ACCL)")
|
||||
field(BDST,"$(BDST)")
|
||||
field(BVEL,"$(BVEL)")
|
||||
field(BACC,"$(BACC)")
|
||||
field(OUT,"#C$(C) S$(S) @")
|
||||
field(MRES,"$(MRES)")
|
||||
field(PREC,"$(PREC)")
|
||||
field(EGU,"$(EGU)")
|
||||
field(DHLM,"$(DHLM)")
|
||||
field(DLLM,"$(DLLM)")
|
||||
field(INIT,"$(INIT)")
|
||||
field(TWV,"1")
|
||||
}
|
||||
|
@ -1,18 +0,0 @@
|
||||
|
||||
# The message text
|
||||
record(waveform, "$(P)$(M)-MsgTxt") {
|
||||
field(DTYP, "asynOctetRead")
|
||||
field(INP, "@asyn($(PORT),$(N),1) MOTOR_MESSAGE_TEXT")
|
||||
field(FTVL, "CHAR")
|
||||
field(NELM, "80")
|
||||
field(SCAN, "I/O Intr")
|
||||
}
|
||||
|
||||
record(ao,"$(P)m$(N)-Resolution"){
|
||||
field(DESC,"m$(N) Resolution")
|
||||
field(DOL,"$(P)m$(N).MRES CP MS")
|
||||
field(OMSL,"closed_loop")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(OUT,"@asyn($(PORT),$(N))MOTOR_RESOLUTION")
|
||||
field(PREC,"3")
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
# enable axis
|
||||
record(longout, "$(P)$(M):Enable") {
|
||||
field(DTYP, "asynInt32")
|
||||
field(OUT, "@asyn($(PORT),$(N),1) ENABLE_AXIS")
|
||||
field(PINI, "YES")
|
||||
}
|
||||
|
||||
# enable axis
|
||||
record(longin, "$(P)$(M):Enable_RBV") {
|
||||
field(DTYP, "asynInt32")
|
||||
field(INP, "@asyn($(PORT),$(N),1) AXIS_ENABLED")
|
||||
field(PINI, "YES")
|
||||
field(SCAN, "1 second")
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
record(motor,"$(P)$(M)")
|
||||
{
|
||||
field(DESC,"$(DESC)")
|
||||
field(DTYP,"$(DTYP)")
|
||||
field(DIR,"$(DIR)")
|
||||
field(VELO,"$(VELO)")
|
||||
field(VBAS,"$(VBAS)")
|
||||
field(ACCL,"$(ACCL)")
|
||||
field(BDST,"$(BDST)")
|
||||
field(BVEL,"$(BVEL)")
|
||||
field(BACC,"$(BACC)")
|
||||
field(OUT,"@asyn($(PORT),$(ADDR))")
|
||||
field(MRES,"$(MRES)")
|
||||
field(PREC,"$(PREC)")
|
||||
field(EGU,"$(EGU)")
|
||||
field(DHLM,"$(DHLM)")
|
||||
field(DLLM,"$(DLLM)")
|
||||
field(INIT,"$(INIT)")
|
||||
field(TWV,"1")
|
||||
field(RDBD,"$(RDBD)")
|
||||
}
|
||||
|
||||
|
||||
# The message text
|
||||
record(waveform, "$(P)$(M)-MsgTxt") {
|
||||
field(DTYP, "asynOctetRead")
|
||||
field(INP, "@asyn($(PORT),$(N),1) MOTOR_MESSAGE_TEXT")
|
||||
field(FTVL, "CHAR")
|
||||
field(NELM, "80")
|
||||
field(SCAN, "I/O Intr")
|
||||
}
|
||||
|
||||
# enable axis
|
||||
record(longout, "$(P)$(M):Enable") {
|
||||
field(DTYP, "asynInt32")
|
||||
field(OUT, "@asyn($(PORT),$(N),1) ENABLE_AXIS")
|
||||
field(PINI, "YES")
|
||||
}
|
||||
|
||||
# enable axis
|
||||
record(longin, "$(P)$(M):Enable_RBV") {
|
||||
field(DTYP, "asynInt32")
|
||||
field(INP, "@asyn($(PORT),$(N),1) AXIS_ENABLED")
|
||||
field(PINI, "YES")
|
||||
field(SCAN, "5 second")
|
||||
}
|
||||
|
@ -1,15 +0,0 @@
|
||||
file "$(TOP)/db/basic_asyn_motor.db"
|
||||
{
|
||||
pattern
|
||||
{P, N, M, DTYP, PORT, ADDR, DESC, EGU, DIR, VELO, VBAS, ACCL, BDST, BVEL, BACC, MRES, PREC, DLLM, DHLM, INIT}
|
||||
{KM36:mota:, 5, "m$(N)", "asynMotor", mota, 5, "m5", degree, Pos, 2.0, 0.1, .2, 0, 1, .2, 1., 3, -20.0, 20.0, ""}
|
||||
{KM36:mota:, 6, "m$(N)", "asynMotor", mota, 6, "m6", degree, Pos, 2.0, 0.1, .2, 0, 1, .2, 1., 3, -20.0, 20.0, ""}
|
||||
}
|
||||
|
||||
file "$(TOP)/db/motorMessage.db"
|
||||
{
|
||||
pattern
|
||||
{P,N, M,PORT}
|
||||
{KM36:mota:, 5, "m$(N)",mota}
|
||||
{KM36:mota:, 6, "m$(N)",mota}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
file "$(TOP)/db/sinq_asyn_motor.db"
|
||||
{
|
||||
pattern
|
||||
{P, N, M, DTYP, PORT, ADDR, DESC, EGU, DIR, VELO, VBAS, ACCL, BDST, BVEL, BACC, MRES, PREC, DLLM, DHLM, RDBD, INIT}
|
||||
{KM36:mota:,5,"m$(N)","asynMotor", mota, 5, "m5", degree, Pos, 2.0, 0.1, .2, 0, 1, .2, .001, 3,-400000.000,400000.000,.01, ""}
|
||||
{KM36:mota:,6,"m$(N)","asynMotor", mota, 6, "m6", degree, Pos, 2.0, 0.1, .2, 0, 1, .2, .001, 3,-200000.000,200000.000,.01, ""}
|
||||
}
|
||||
|
@ -1,13 +0,0 @@
|
||||
file "$(TOP)/db/basic_asyn_motor.db"
|
||||
{
|
||||
pattern
|
||||
{P, N, M, DTYP, PORT, ADDR, DESC, EGU, DIR, VELO, VBAS, ACCL, BDST, BVEL, BACC, MRES, PREC, DLLM, DHLM, INIT}
|
||||
{KM36:mota:, 2, "m$(N)", "asynMotor", mota, 2, "sgl", degree, Pos, 2.0, 0.1, .2, 0, 1, .2, 1., 3, -20.0, 20.0, ""}
|
||||
}
|
||||
|
||||
file "$(TOP)/db/motorMessage.db"
|
||||
{
|
||||
pattern
|
||||
{P,N, M,PORT}
|
||||
{KM36:mota:, 2, "m$(N)",mota}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
file "$(TOP)/db/sinq_asyn_motor.db"
|
||||
{
|
||||
pattern
|
||||
{P, N, M, DTYP, PORT, ADDR, DESC, EGU, DIR, VELO, VBAS, ACCL, BDST, BVEL, BACC, MRES, PREC, DLLM, DHLM, INIT, RDBD}
|
||||
{KM36:mota:,2,"m$(N)","asynMotor", mota, 2, "sgl", degree, Pos, 100, 0.1, .2, 0, 1, .2, 1., 3,-180.0,360.0,"", 0.2}}
|
||||
|
||||
file "$(TOP)/db/motorMessage.db"
|
||||
{
|
||||
pattern
|
||||
{P,N, M,PORT}
|
||||
{KM36:mota:, 2, "m$(N)",mota}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
#!/usr/local/bin/iocsh
|
||||
|
||||
require sinq,koennecke
|
||||
require autosave,koennecke
|
||||
|
||||
epicsEnvSet("TOP","/afs/psi.ch/project/sinqdev/sinqepicsapp/testmmac")
|
||||
|
||||
set_requestfile_path("$(TOP)", "")
|
||||
set_savefile_path("$(TOP)/autosave")
|
||||
save_restoreSet_Debug(0)
|
||||
#--------------------------------- restore autosave
|
||||
set_pass0_restoreFile("$(TOP)/autosave/test.sav","")
|
||||
set_pass1_restoreFile("$(TOP)/autosave/test.sav","")
|
||||
|
||||
|
||||
#drvAsynMMACSPortConfigure("macs1", "localhost:8080",0,0,0)
|
||||
#asynInterposeEosConfig("macs1", 0, 0, 0)
|
||||
#dbLoadRecords("$(TOP)/db/asynRecord.db","P=KM36:,R=macs1,PORT=macs1,ADDR=0,OMAX=80,IMAX=80")
|
||||
#asynSetTraceMask("macs1", 0, 255)
|
||||
|
||||
#asynSetTraceMask("macs1", 0, 255)
|
||||
#drvAsynIPPortConfigure("macs1", "localhost:8080",0,0,0)
|
||||
drvAsynIPPortConfigure("macs1", "Marcel1--MACS:1917")
|
||||
MasterMACSCreateController("mota","macs1",7, 500, 10000)
|
||||
MasterMACSCreateAxis("mota",5)
|
||||
MasterMACSCreateAxis("mota",6)
|
||||
|
||||
dbLoadTemplate "mmacs2.sub"
|
||||
|
||||
iocInit()
|
||||
setMovingPollPeriod("mota", .5)
|
||||
setIdlePollPeriod("mota", 10. )
|
||||
|
||||
create_monitor_set("test.req", 10, "")
|
||||
|
@ -1,9 +0,0 @@
|
||||
record(asyn,"$(P)$(R)")
|
||||
{
|
||||
field(DTYP,"asynRecordDevice")
|
||||
field(PORT,"$(PORT)")
|
||||
field(ADDR,"$(ADDR)")
|
||||
field(OMAX,"$(OMAX)")
|
||||
field(IMAX,"$(IMAX)")
|
||||
}
|
||||
|
@ -1,22 +0,0 @@
|
||||
record(motor,"$(P)$(M)")
|
||||
{
|
||||
field(DESC,"$(DESC)")
|
||||
field(DTYP,"$(DTYP)")
|
||||
field(DIR,"$(DIR)")
|
||||
field(VELO,"$(VELO)")
|
||||
field(VBAS,"$(VBAS)")
|
||||
field(ACCL,"$(ACCL)")
|
||||
field(BDST,"$(BDST)")
|
||||
field(BVEL,"$(BVEL)")
|
||||
field(BACC,"$(BACC)")
|
||||
field(OUT,"@asyn($(PORT),$(ADDR))")
|
||||
field(MRES,"$(MRES)")
|
||||
field(PREC,"$(PREC)")
|
||||
field(EGU,"$(EGU)")
|
||||
field(DHLM,"$(DHLM)")
|
||||
field(DLLM,"$(DLLM)")
|
||||
field(INIT,"$(INIT)")
|
||||
field(TWV,"1")
|
||||
field(RTRY,"0")
|
||||
}
|
||||
|
19544
testpmacV3/db/huber.dbd
19544
testpmacV3/db/huber.dbd
File diff suppressed because it is too large
Load Diff
@ -1,9 +0,0 @@
|
||||
|
||||
# The message text
|
||||
record(waveform, "$(P)$(M)-MsgTxt") {
|
||||
field(DTYP, "asynOctetRead")
|
||||
field(INP, "@asyn($(PORT),$(N),1) MOTOR_MESSAGE_TEXT")
|
||||
field(FTVL, "CHAR")
|
||||
field(NELM, "80")
|
||||
field(SCAN, "I/O Intr")
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
# enable axis
|
||||
record(longout, "$(P)$(M):Enable") {
|
||||
field(DTYP, "asynInt32")
|
||||
field(OUT, "@asyn($(PORT),$(N),1) ENABLE_AXIS")
|
||||
field(PINI, "YES")
|
||||
}
|
||||
|
||||
# enable axis
|
||||
record(longin, "$(P)$(M):Enable_RBV") {
|
||||
field(DTYP, "asynInt32")
|
||||
field(INP, "@asyn($(PORT),$(N),1) AXIS_ENABLED")
|
||||
field(PINI, "YES")
|
||||
field(SCAN, "1 second")
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
file "$(TOP)/db/basic_asyn_motor.db"
|
||||
{
|
||||
pattern
|
||||
{P, N, M, DTYP, PORT, ADDR, DESC, EGU, DIR, VELO, VBAS, ACCL, BDST, BVEL, BACC, MRES, PREC, DHLM, DLLM, INIT}
|
||||
{SQ:TEST:mcu:, 2, "m$(N)", "asynMotor", mcu, 2, "m$(N)", degrees, Pos, 2.0, 0.1, .2, 0, 1, .2, .001, 3, 358., 2., ""}
|
||||
{SQ:TEST:mcu:, 6, "m$(N)", "asynMotor", mcu, 6, "m$(N)", degrees, Pos, 2.0, 0.1, .2, 0, 1, .2, .001, 3, 358., 2., ""}
|
||||
{SQ:TEST:mcu:,10, "m$(N)", "asynMotor", mcu,10, "m$(N)", degrees, Pos, 2.0, 0.1, .2, 0, 1, .2, .001, 3, 358., 2., ""}
|
||||
}
|
||||
|
||||
file "$(TOP)/db/motorMessage.db"
|
||||
{
|
||||
pattern
|
||||
{P,N, M,PORT}
|
||||
{SQ:TEST:mcu:, 2, "m$(N)", mcu}
|
||||
{SQ:TEST:mcu:, 6, "m$(N)", mcu}
|
||||
{SQ:TEST:mcu:,10, "m$(N)", mcu}
|
||||
}
|
||||
|
||||
file "$(TOP)/db/pmacV3.db"
|
||||
{
|
||||
pattern
|
||||
{P,N, M,PORT}
|
||||
{SQ:TEST:mcu:, 2, "m$(N)", mcu}
|
||||
{SQ:TEST:mcu:, 6, "m$(N)", mcu}
|
||||
{SQ:TEST:mcu:,10, "m$(N)", mcu}
|
||||
}
|
||||
|
@ -1,25 +0,0 @@
|
||||
#!/ioc/tools/iocsh
|
||||
|
||||
require sinq,brambilla_m
|
||||
#require sinq,koennecke
|
||||
|
||||
epicsEnvSet("TOP","/afs/psi.ch/project/sinqdev/sinqepicsapp/testpmacV3")
|
||||
|
||||
epicsEnvSet("EPICS_CA_ADDR_LIST","127.0.0.1")
|
||||
|
||||
epicsEnvSet("STREAM_PROTOCOL_PATH","$(TOP)/db")
|
||||
|
||||
|
||||
var streamDebug 3
|
||||
|
||||
# motors
|
||||
|
||||
pmacAsynIPConfigure("pmacV3", "129.129.138.234:1025")
|
||||
pmacV3CreateController("mcu","pmacV3",0,16,50,1000);
|
||||
pmacV3CreateAxis("mcu",2,0);
|
||||
pmacV3CreateAxis("mcu",6,0);
|
||||
pmacV3CreateAxis("mcu",10,0);
|
||||
dbLoadTemplate "$(TOP)/mcu.substitutions"
|
||||
dbLoadRecords("$(TOP)/db/asynRecord.db","P=SQ:TEST:,R=mcu,PORT=pmacV3,ADDR=0,OMAX=80,IMAX=80")
|
||||
|
||||
iocInit
|
@ -1,56 +0,0 @@
|
||||
#!/usr/bin/python
|
||||
"""
|
||||
This is a little program which generates soft motor initialisation lines and iocsh morsels
|
||||
from a motor substitutions file.
|
||||
|
||||
Mark Koennecke, December 2019
|
||||
"""
|
||||
import sys
|
||||
import pdb
|
||||
import os
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print('Usage:\n\tconvertsub XXXX.substitutions')
|
||||
sys.exit(1)
|
||||
|
||||
subLen = 0
|
||||
motors = []
|
||||
port = None
|
||||
|
||||
with open(sys.argv[1],'r') as fin:
|
||||
line = fin.readline()
|
||||
while line:
|
||||
line = line.replace(' ','')
|
||||
line = line.strip('{}')
|
||||
l = line.split(',')
|
||||
if line.find('DHLM') > 0: # that is the index discovery line
|
||||
lowlimidx = l.index('DLLM')
|
||||
highlimidx = l.index('DHLM')
|
||||
mresidx = l.index('MRES')
|
||||
addridx = l.index('ADDR')
|
||||
prefix = l[0]
|
||||
subLen = len(l)
|
||||
portIdx = l.index('PORT')
|
||||
elif subLen > 0:
|
||||
l = line.split(',')
|
||||
if subLen == len(l):
|
||||
motors.append((l[addridx],l[mresidx],l[lowlimidx],l[highlimidx]))
|
||||
port = l[portIdx]
|
||||
else:
|
||||
pass
|
||||
line = fin.readline()
|
||||
|
||||
print('%d motors found' % len(motors))
|
||||
|
||||
fname = os.path.splitext(sys.argv[1])[0] + '.cmd'
|
||||
|
||||
out = open(fname,'w')
|
||||
out.write('motorSimCreateController(\"%s\",%d)\n' % (port, len(motors)+2))
|
||||
for mot in motors:
|
||||
mres = float(mot[1])
|
||||
highlim = int(float(mot[3])/mres)
|
||||
lowlim = int(float(mot[2])/mres)
|
||||
out.write('motorSimConfigAxis(\"%s\",%s,%d,%d,0,0)\n' %(port,mot[0],highlim,lowlim))
|
||||
out.write('dbLoadTemplate(\"$(TOP)/%s\")\n' % (sys.argv[1]))
|
||||
out.close()
|
||||
print(fname + ' written')
|
@ -1,177 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
This is some code for communicating with a Delta-Tau PMAC motor
|
||||
controller as used at SINQ from python. Python 3 is assumed and
|
||||
tested. We use the ethernet protocol of the Pmac. This code benefits
|
||||
from the SICS driver for Pmac which in turn benefits from the driver
|
||||
written by Pete Leicester at Diamond.
|
||||
|
||||
|
||||
Usage: python36 deltatau.py pmachost:port command
|
||||
Then returns the response for command.
|
||||
|
||||
Mark Koennecke, October 2019
|
||||
"""
|
||||
|
||||
import struct
|
||||
import socket
|
||||
import curses
|
||||
|
||||
def packPmacCommand(command):
|
||||
# 0x40 = VR_DOWNLOAD
|
||||
# 0xBF = VR_PMAC_GETRESPONSE
|
||||
buf = struct.pack('BBHHH',0x40,0xBF,0,0,socket.htons(len(command)))
|
||||
buf = buf + bytes(command,'utf-8')
|
||||
return buf
|
||||
|
||||
def readPmacReply(input):
|
||||
msg = bytearray()
|
||||
expectAck = True
|
||||
while True:
|
||||
b = input.recv(1)
|
||||
bint = int.from_bytes(b,byteorder='little')
|
||||
if bint == 2 or bint == 7: #STX or BELL
|
||||
expectAck = False
|
||||
continue
|
||||
if expectAck and bint == 6: # ACK
|
||||
return bytes(msg)
|
||||
else:
|
||||
if bint == 13 and not expectAck: # CR
|
||||
return bytes(msg)
|
||||
else:
|
||||
msg.append(bint)
|
||||
|
||||
if __name__ == "__main__":
|
||||
from sys import argv
|
||||
|
||||
try:
|
||||
|
||||
addr = argv[1].split(':')
|
||||
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
|
||||
s.connect((addr[0],int(addr[1])))
|
||||
|
||||
if len(argv) == 3:
|
||||
buf = packPmacCommand(argv[2])
|
||||
s.send(buf)
|
||||
reply = readPmacReply(s)
|
||||
print(reply.decode('utf-8') + '\n')
|
||||
|
||||
else:
|
||||
|
||||
try:
|
||||
|
||||
stdscr = curses.initscr()
|
||||
curses.noecho()
|
||||
curses.cbreak()
|
||||
stdscr.keypad(True)
|
||||
|
||||
stdscr.addstr(">> ")
|
||||
stdscr.refresh()
|
||||
|
||||
history = [""]
|
||||
ptr = len(history) - 1
|
||||
|
||||
while True:
|
||||
c = stdscr.getch()
|
||||
if c == curses.KEY_RIGHT:
|
||||
(y, x) = stdscr.getyx()
|
||||
if x < len(history[ptr]) + 3:
|
||||
stdscr.move(y, x+1)
|
||||
stdscr.refresh()
|
||||
elif c == curses.KEY_LEFT:
|
||||
(y, x) = stdscr.getyx()
|
||||
if x > 3:
|
||||
stdscr.move(y, x-1)
|
||||
stdscr.refresh()
|
||||
elif c == curses.KEY_UP:
|
||||
if ptr > 0:
|
||||
ptr -= 1
|
||||
stdscr.addch("\r")
|
||||
stdscr.clrtoeol()
|
||||
stdscr.addstr(">> " + history[ptr])
|
||||
elif c == curses.KEY_DOWN:
|
||||
if ptr < len(history) - 1:
|
||||
ptr += 1
|
||||
stdscr.addch("\r")
|
||||
stdscr.clrtoeol()
|
||||
stdscr.addstr(">> " + history[ptr])
|
||||
elif c == curses.KEY_ENTER or c == ord('\n') or c == ord('\r'):
|
||||
if history[ptr] == 'quit':
|
||||
break
|
||||
|
||||
# because of arrow keys move back to the end of the line
|
||||
(y, x) = stdscr.getyx()
|
||||
stdscr.move(y, 3+len(history[ptr]))
|
||||
|
||||
if history[ptr]:
|
||||
buf = packPmacCommand(history[ptr])
|
||||
s.send(buf)
|
||||
reply = readPmacReply(s)
|
||||
stdscr.addstr("\n" + reply.decode('utf-8')[0:-1])
|
||||
|
||||
if ptr == len(history) - 1 and history[ptr] != "":
|
||||
history += [""]
|
||||
else:
|
||||
history[-1] = ""
|
||||
ptr = len(history) - 1
|
||||
|
||||
stdscr.addstr("\n>> ")
|
||||
stdscr.refresh()
|
||||
|
||||
else:
|
||||
if ptr < len(history) - 1: # Modifying previous input
|
||||
if len(history[-1]) == 0:
|
||||
history[-1] = history[ptr]
|
||||
ptr = len(history) - 1
|
||||
|
||||
else:
|
||||
history += [history[ptr]]
|
||||
ptr = len(history) - 1
|
||||
|
||||
if c == curses.KEY_BACKSPACE:
|
||||
if len(history[ptr]) == 0:
|
||||
continue
|
||||
(y, x) = stdscr.getyx()
|
||||
history[ptr] = history[ptr][0:x-4] + history[ptr][x-3:]
|
||||
stdscr.addch("\r")
|
||||
stdscr.clrtoeol()
|
||||
stdscr.addstr(">> " + history[ptr])
|
||||
stdscr.move(y, x-1)
|
||||
stdscr.refresh()
|
||||
|
||||
else:
|
||||
(y, x) = stdscr.getyx()
|
||||
history[ptr] = history[ptr][0:x-3] + chr(c) + history[ptr][x-3:]
|
||||
stdscr.addch("\r")
|
||||
stdscr.clrtoeol()
|
||||
stdscr.addstr(">> " + history[ptr])
|
||||
stdscr.move(y, x+1)
|
||||
stdscr.refresh()
|
||||
|
||||
finally:
|
||||
|
||||
# to quit
|
||||
curses.nocbreak()
|
||||
stdscr.keypad(False)
|
||||
curses.echo()
|
||||
curses.endwin()
|
||||
|
||||
except:
|
||||
print("""
|
||||
Invalid Arguments
|
||||
|
||||
Option 1: Single Command
|
||||
------------------------
|
||||
|
||||
Usage: deltatau.py pmachost:port command
|
||||
This then returns the response for command.
|
||||
|
||||
Option 2: CLI Mode
|
||||
------------------
|
||||
|
||||
Usage: deltatau.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.
|
||||
""")
|
@ -1,54 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Usage: macmaster.py macmasterhost port
|
||||
Listen for commands to send and returns reponse
|
||||
until exit has been typed
|
||||
|
||||
Mark Koennecke, March 2023
|
||||
"""
|
||||
|
||||
import socket
|
||||
import struct
|
||||
|
||||
|
||||
class MasterMACS():
|
||||
def __init__(self, host, port):
|
||||
self._socke = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self._socke.connect((host, int(port)))
|
||||
|
||||
def send(self, command):
|
||||
buf = struct.pack('BBBB', 0x05, len(command) + 4, 0, 0x19)
|
||||
buf += bytes(command, 'utf-8')
|
||||
buf += struct.pack('BB', 0x0D, 0x03)
|
||||
self._socke.send(buf)
|
||||
|
||||
def receive(self):
|
||||
buf = self._socke.recv(35, socket.MSG_WAITALL)
|
||||
if len(buf) < 35:
|
||||
raise EOFException('Master MACS returned only %d bytes, 35 expected' % len(buf))
|
||||
idx = buf.find(0x0D)
|
||||
ackbyte = buf[idx-1]
|
||||
if ackbyte == 0x06:
|
||||
ack = 'ACK'
|
||||
elif ackbyte == 0x15:
|
||||
ack = 'NAK',
|
||||
else:
|
||||
ack = 'NO'
|
||||
reply = buf[4:idx-1].decode('utf-8')
|
||||
return ack, reply
|
||||
|
||||
if __name__ == "__main__":
|
||||
from sys import argv, exit, stdin
|
||||
if len(argv) < 3:
|
||||
print('Usage:\n\tmacmaster.py machost macport')
|
||||
exit(1)
|
||||
mac = MasterMACS(argv[1], argv[2])
|
||||
while(True):
|
||||
# import pdb; pdb.set_trace()
|
||||
line = stdin.readline()
|
||||
if line.find('exit') >= 0:
|
||||
exit(0)
|
||||
mac.send(line.strip())
|
||||
ack, reply = mac.receive()
|
||||
print('%s, %s' %(ack, reply))
|
||||
|
@ -1,58 +0,0 @@
|
||||
#!/usr/bin/tclsh
|
||||
# This is a little program which acts as a shell to the phytron.
|
||||
# It connects to another program which is supposed to talk to the phytron controller
|
||||
# It reads from stdin, packages the message into the phytron format and sends it to
|
||||
# the phytron communication program. Then it reads from the phytron communication program
|
||||
# and unpacks the reply.
|
||||
#
|
||||
# This is also a nice exampe for dealing with binary in Tcl
|
||||
# Making the binary character only worked with %c
|
||||
# The only way to do the comparison is with the string comare
|
||||
#
|
||||
# Mark Könnecke, September 2016
|
||||
|
||||
|
||||
if {[llength $argv] < 1} {
|
||||
puts stdout "Usage:\n\t physhell.tcl phytronprogram"
|
||||
exit
|
||||
}
|
||||
|
||||
set phprogram [lindex $argv 0]
|
||||
|
||||
set phyio [open "| $phprogram" "w+b"]
|
||||
fconfigure $phyio -buffering none
|
||||
fconfigure $phyio -translation {binary binary}
|
||||
set etx [format "%c" 0x03]
|
||||
set stx [format "%c" 0x02]
|
||||
set ack [format "%c" 0x06]
|
||||
set nack [format "%c" 0x05]
|
||||
|
||||
|
||||
while {1} {
|
||||
set inp [gets stdin]
|
||||
puts -nonewline $phyio [format "%c%s%c" 0x02 $inp 0x03]
|
||||
set mode start
|
||||
set reply ""
|
||||
while {[string compare $mode done] != 0 } {
|
||||
set c [read $phyio 1]
|
||||
switch $mode {
|
||||
start {
|
||||
if {[string compare $c $stx] == 0} {
|
||||
set mode data
|
||||
}
|
||||
}
|
||||
data {
|
||||
if {[string compare $c $etx] == 0} {
|
||||
puts stdout $reply
|
||||
set mode done
|
||||
} elseif {[string compare $c $nack] == 0} {
|
||||
append reply NACK
|
||||
} elseif {[string compare $c $ack] == 0} {
|
||||
append reply ACK
|
||||
} else {
|
||||
append reply $c
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,114 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
This little program synchronizes an EPICS substitutions file with values read
|
||||
from the EL734 motor controller. Some research showed that the EPICS motorRecord
|
||||
seems to have no means of reading configuration data like limits or speeds or such
|
||||
from the device support. Than it is the easiest to read the data with this small
|
||||
program and update the substitutions file with it.
|
||||
|
||||
Mark Koennecke, January 2023
|
||||
"""
|
||||
|
||||
import socket
|
||||
import sys
|
||||
import time
|
||||
|
||||
socke = None
|
||||
sockfd = None
|
||||
|
||||
# --------------- communication section
|
||||
def connect(host, port):
|
||||
global socke, sockfd
|
||||
socke = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
# socke.connect(('localhost', 5050))
|
||||
socke.connect((host, port))
|
||||
socke.settimeout(2.)
|
||||
sockfd = socke.makefile(mode='rw', newline='\r')
|
||||
sockfd.write('RMT 1\r')
|
||||
sockfd.flush()
|
||||
sockfd.write('ECHO 0\r')
|
||||
sockfd.flush()
|
||||
sockfd.readline()
|
||||
|
||||
def transact(command):
|
||||
global socke, sockfd
|
||||
sockfd.write(command + '\r')
|
||||
sockfd.flush()
|
||||
time.sleep(.1)
|
||||
return sockfd.readline()
|
||||
|
||||
def find_commas(rawline):
|
||||
comma_list = []
|
||||
for i in range(len(rawline)):
|
||||
if rawline[i] == ',':
|
||||
comma_list.append(i)
|
||||
return comma_list
|
||||
|
||||
def pretty_line(newlist, comma_list):
|
||||
"""
|
||||
adds spaces to match the tabbing of the pattern line
|
||||
"""
|
||||
newline = ''
|
||||
for item, idx in zip(newlist, comma_list):
|
||||
length = len(newline) + 1 + len(item)
|
||||
if length < idx:
|
||||
newline += ' ' * (idx - length)
|
||||
newline += item
|
||||
newline += ','
|
||||
newline += newlist[-1]
|
||||
return newline[0:-1]
|
||||
|
||||
def fix_line(par_list, index_list):
|
||||
# import pdb; pdb.set_trace()
|
||||
addridx = index_list.index('ADDR')
|
||||
motNo = par_list[addridx]
|
||||
limits = transact('H ' + motNo)
|
||||
time.sleep(.1)
|
||||
l = limits.split()
|
||||
lowidx = index_list.index('DLLM')
|
||||
# import pdb; pdb.set_trace()
|
||||
par_list[lowidx] = l[0]
|
||||
highidx = index_list.index('DHLM')
|
||||
par_list[highidx] = l[1]
|
||||
speed = transact('J ' + motNo)
|
||||
vidx = index_list.index('VELO')
|
||||
par_list[vidx] = speed.strip()
|
||||
# vidx = index_list.index('VMAX')
|
||||
# par_list[vidx] = speed.strip()
|
||||
return par_list
|
||||
|
||||
def scan_substitution_file(filename):
|
||||
index_list = None
|
||||
# import pdb; pdb.set_trace()
|
||||
with open(filename, 'r') as fin:
|
||||
rawline = fin.readline()
|
||||
while rawline:
|
||||
line = rawline.replace(' ','')
|
||||
line = line.strip('{}')
|
||||
l = line.split(',')
|
||||
if line.find('DHLM') > 0:
|
||||
index_list = l
|
||||
comma_list = find_commas(rawline)
|
||||
sys.stdout.write(rawline)
|
||||
elif not index_list:
|
||||
sys.stdout.write(rawline)
|
||||
else:
|
||||
if len(l) == len(index_list):
|
||||
newlist = fix_line(l, index_list)
|
||||
# newline = ','.join(newlist)
|
||||
newline = pretty_line(newlist, comma_list)
|
||||
sys.stdout.write('{' + newline + '\n')
|
||||
else:
|
||||
sys.stdout.write(rawline)
|
||||
rawline = fin.readline()
|
||||
|
||||
#------------------ main
|
||||
if len(sys.argv) < 4:
|
||||
print('Usage:\n\tsyncEL734sub.py <host> <port> <substitutions-file>\n')
|
||||
sys.exit(1)
|
||||
|
||||
connect(sys.argv[1], int(sys.argv[2]))
|
||||
scan_substitution_file(sys.argv[3])
|
||||
socke.close()
|
||||
|
||||
|
@ -1,98 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
This little program synchronizes an EPICS substitutions file with values read
|
||||
from a MasterMAC motor controller.
|
||||
|
||||
Mark Koennecke, February 2023
|
||||
"""
|
||||
import sys
|
||||
import time
|
||||
|
||||
from macmaster import MasterMACS
|
||||
|
||||
def find_commas(rawline):
|
||||
comma_list = []
|
||||
for i in range(len(rawline)):
|
||||
if rawline[i] == ',':
|
||||
comma_list.append(i)
|
||||
return comma_list
|
||||
|
||||
def pretty_line(newlist, comma_list):
|
||||
"""
|
||||
adds spaces to match the tabbing of the patter line
|
||||
"""
|
||||
newline = ''
|
||||
for item, idx in zip(newlist, comma_list):
|
||||
length = len(newline) + 1 + len(item)
|
||||
if length < idx:
|
||||
newline += ' ' * (idx - length)
|
||||
newline += item
|
||||
newline += ','
|
||||
newline += newlist[-1]
|
||||
return newline[0:-1]
|
||||
|
||||
def transact(command):
|
||||
global mac
|
||||
mac.send(command)
|
||||
time.sleep(.1)
|
||||
return mac.receive()
|
||||
|
||||
def fix_line(par_list, index_list):
|
||||
# import pdb; pdb.set_trace()
|
||||
addridx = index_list.index('ADDR')
|
||||
motNo = int(par_list[addridx])
|
||||
ack, reply = transact('%dR24' % motNo)
|
||||
if ack == 'NO':
|
||||
idx = reply.find('=')
|
||||
lowlim = reply[idx+1:]
|
||||
lowidx = index_list.index('DLLM')
|
||||
par_list[lowidx] = lowlim.strip()
|
||||
ack, reply = transact('%dR23' % motNo)
|
||||
if ack == 'NO':
|
||||
idx = reply.find('=')
|
||||
highlim = reply[idx+1:]
|
||||
highidx = index_list.index('DHLM')
|
||||
par_list[highidx] = highlim.strip()
|
||||
ack, reply = transact('%dR05' % motNo)
|
||||
if ack == 'NO':
|
||||
idx = reply.find('=')
|
||||
speed = reply[idx+1:]
|
||||
speedidx = index_list.index('VELO')
|
||||
par_list[speedidx] = speed.strip()
|
||||
return par_list
|
||||
|
||||
def scan_substitution_file(filename):
|
||||
index_list = None
|
||||
# import pdb; pdb.set_trace()
|
||||
with open(filename, 'r') as fin:
|
||||
rawline = fin.readline()
|
||||
# import pdb; pdb.set_trace()
|
||||
while rawline:
|
||||
line = rawline.replace(' ','')
|
||||
line = line.strip('{}')
|
||||
l = line.split(',')
|
||||
if line.find('DHLM') > 0:
|
||||
index_list = l
|
||||
comma_list = find_commas(rawline)
|
||||
sys.stdout.write(rawline)
|
||||
elif not index_list:
|
||||
sys.stdout.write(rawline)
|
||||
else:
|
||||
if len(l) == len(index_list):
|
||||
newlist = fix_line(l, index_list)
|
||||
# newline = ','.join(newlist)
|
||||
newline = pretty_line(newlist, comma_list)
|
||||
sys.stdout.write('{' + newline + '\n')
|
||||
else:
|
||||
sys.stdout.write(rawline)
|
||||
rawline = fin.readline()
|
||||
|
||||
#------------------ main
|
||||
if len(sys.argv) < 4:
|
||||
print('Usage:\n\tsyncMMACSub.py <host> <port> <substitutions-file>\n')
|
||||
sys.exit(1)
|
||||
|
||||
mac = MasterMACS(sys.argv[1], sys.argv[2])
|
||||
scan_substitution_file(sys.argv[3])
|
||||
|
||||
|
@ -1,104 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
This little program synchronizes an EPICS substitutions file with values read
|
||||
from the delta tau motor controller. Some research showed that the EPICS motorRecord
|
||||
seems to have no means of reading configuration data like limits or speeds or such
|
||||
from the device support. Than it is the easiest to read the data with this small
|
||||
program and update the substitutions file with it.
|
||||
|
||||
Mark Koennecke, January 2023
|
||||
"""
|
||||
|
||||
import socket
|
||||
import sys
|
||||
from deltatau import packPmacCommand, readPmacReply
|
||||
|
||||
|
||||
socke = None
|
||||
|
||||
# --------------- communication section
|
||||
def connect(host, port):
|
||||
global socke, sockfd
|
||||
socke = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
# socke.connect(('localhost', 5050))
|
||||
socke.connect((host, port))
|
||||
socke.settimeout(1.)
|
||||
|
||||
def transact(command):
|
||||
global socke
|
||||
data = packPmacCommand(command)
|
||||
socke.send(data)
|
||||
reply = readPmacReply(socke)
|
||||
return reply.decode('utf-8')
|
||||
|
||||
def find_commas(rawline):
|
||||
comma_list = []
|
||||
for i in range(len(rawline)):
|
||||
if rawline[i] == ',':
|
||||
comma_list.append(i)
|
||||
return comma_list
|
||||
|
||||
def pretty_line(newlist, comma_list):
|
||||
"""
|
||||
adds spaces to match the tabbing of the patter line
|
||||
"""
|
||||
newline = ''
|
||||
for item, idx in zip(newlist, comma_list):
|
||||
length = len(newline) + 1 + len(item)
|
||||
if length < idx:
|
||||
newline += ' ' * (idx - length)
|
||||
newline += item
|
||||
newline += ','
|
||||
newline += newlist[-1]
|
||||
return newline[0:-1]
|
||||
|
||||
def fix_line(par_list, index_list):
|
||||
# import pdb; pdb.set_trace()
|
||||
addridx = index_list.index('ADDR')
|
||||
motNo = int(par_list[addridx])
|
||||
lowlim = transact('Q%d14' % motNo)
|
||||
lowidx = index_list.index('DLLM')
|
||||
par_list[lowidx] = lowlim.strip()
|
||||
highlim = transact('Q%d13' % motNo)
|
||||
highidx = index_list.index('DHLM')
|
||||
par_list[highidx] = highlim.strip()
|
||||
speed = transact('Q%d03' % motNo)
|
||||
speedidx = index_list.index('VELO')
|
||||
par_list[speedidx] = speed.strip()
|
||||
return par_list
|
||||
|
||||
def scan_substitution_file(filename):
|
||||
index_list = None
|
||||
# import pdb; pdb.set_trace()
|
||||
with open(filename, 'r') as fin:
|
||||
rawline = fin.readline()
|
||||
while rawline:
|
||||
line = rawline.replace(' ','')
|
||||
line = line.strip('{}')
|
||||
l = line.split(',')
|
||||
if line.find('DHLM') > 0:
|
||||
index_list = l
|
||||
comma_list = find_commas(rawline)
|
||||
sys.stdout.write(rawline)
|
||||
elif not index_list:
|
||||
sys.stdout.write(rawline)
|
||||
else:
|
||||
if len(l) == len(index_list):
|
||||
newlist = fix_line(l, index_list)
|
||||
# newline = ','.join(newlist)
|
||||
newline = pretty_line(newlist, comma_list)
|
||||
sys.stdout.write('{' + newline + '\n')
|
||||
else:
|
||||
sys.stdout.write(rawline)
|
||||
rawline = fin.readline()
|
||||
|
||||
#------------------ main
|
||||
if len(sys.argv) < 4:
|
||||
print('Usage:\n\tsyncPmacSub.py <host> <port> <substitutions-file>\n')
|
||||
sys.exit(1)
|
||||
|
||||
connect(sys.argv[1], int(sys.argv[2]))
|
||||
scan_substitution_file(sys.argv[3])
|
||||
socke.close()
|
||||
|
||||
|
Reference in New Issue
Block a user