Compare commits
67 Commits
Author | SHA1 | Date | |
---|---|---|---|
0cbfe45893 | |||
bb1c10c7cd | |||
339da2e9ff | |||
80877aa6ab | |||
afc92bde3f | |||
8e2c1af10e | |||
f5da0d54bd | |||
ad05433602 | |||
92364a1de8 | |||
403eecafae | |||
fbf2331a05 | |||
14bbda3364 | |||
c7fea08718 | |||
edc71af235 | |||
c805385ad1 | |||
929f9f600d | |||
8c3e68394f | |||
646607e476 | |||
68a265b199 | |||
542abcbaad | |||
efbd0e19cf | |||
6de4a878ef | |||
d86da602d2 | |||
c9e7830274 | |||
d1d74f4db3 | |||
d1beb9b0d8 | |||
3ae13875cf | |||
f56ef2c74c | |||
a25f8cabb9 | |||
c4fe45c0cb | |||
3b7133ecfe | |||
e9a615d0fa | |||
12249d5471 | |||
6d823e2265 | |||
75de7a3a4c | |||
5aefbd4684 | |||
3133d933fa | |||
bf2ff63a4b | |||
b4b093efdf | |||
f424477a6a | |||
3bea34700e | |||
02ab5ff9b8 | |||
972131d86a | |||
f909c41a2b | |||
460030e410 | |||
2a964503a4 | |||
1687ebf4c7 | |||
7023f52336 | |||
83a995a16d | |||
124aa97cd6 | |||
bd3b808312 | |||
9a3b0f7666 | |||
0eed0c9357 | |||
7263a0772f | |||
9c507a05ba | |||
dc966bc976 | |||
edd3005f85 | |||
af4d16d25f | |||
6ea6fdcb85 | |||
389e7f9157 | |||
8858761e74 | |||
2950f21353 | |||
28999f2212 | |||
7c1693e606 | |||
c75957f284 | |||
8f0c240e76 | |||
5dff3bc23b |
121
.gitignore
vendored
Normal file
121
.gitignore
vendored
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
# 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
|
||||||
|
*~
|
||||||
|
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
#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
10-llbDevices.rules
Normal file
1
10-llbDevices.rules
Normal file
@ -0,0 +1 @@
|
|||||||
|
SUBSYSTEM=="usb", ATTR{idVendor}=="04b4", ATTR{idProduct}=="1002", MODE="0666" GROUP="plugdev", TAG+="uaccess"
|
22
MakeAutoSave.RHEL7
Normal file
22
MakeAutoSave.RHEL7
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# 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
|
17
MakeScaler.RHEL7
Normal file
17
MakeScaler.RHEL7
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
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
|
1
Makefile
1
Makefile
@ -1,3 +1,4 @@
|
|||||||
|
# This is for building the IOC application against the EEE-setup
|
||||||
#Makefile at top of application tree
|
#Makefile at top of application tree
|
||||||
TOP = .
|
TOP = .
|
||||||
include $(TOP)/configure/CONFIG
|
include $(TOP)/configure/CONFIG
|
||||||
|
33
Makefile.EEE
Normal file
33
Makefile.EEE
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# This build the SINQ stuff as an EEE module. Which we cannot use yet because of the political problem
|
||||||
|
# of integrating this module into the EEE distribution
|
||||||
|
include ${EPICS_ENV_PATH}/module.Makefile
|
||||||
|
|
||||||
|
PROJECT=sinq
|
||||||
|
|
||||||
|
USR_DEPENDENCIES = asyn,4.27.0
|
||||||
|
USR_DEPENDENCIES += motor,6.10.0
|
||||||
|
USR_DEPENDENCIES += synAppsStd,3.4.1
|
||||||
|
USR_DEPENDENCIES += streamdevice,2.6.0
|
||||||
|
USR_DEPENDENCIES += busy,1.6.0
|
||||||
|
USR_DEPENDENCIES += pcre,8.36.0
|
||||||
|
|
||||||
|
|
||||||
|
TEMPLATES += sinqEPICSApp/Db/dimetix.db
|
||||||
|
TEMPLATES += sinqEPICSApp/Db/slsvme.db
|
||||||
|
TEMPLATES += sinqEPICSApp/Db/spsamor.db
|
||||||
|
TEMPLATES += sinqEPICSApp/Db/el737Record.db
|
||||||
|
|
||||||
|
|
||||||
|
DBDS += sinqEPICSApp/src/sinq.dbd
|
||||||
|
|
||||||
|
SUBSTITUTIONS=-none-
|
||||||
|
|
||||||
|
OPIS=-none-
|
||||||
|
|
||||||
|
# What we need at SINQ
|
||||||
|
SOURCES += sinqEPICSApp/src/devScalerEL737.c
|
||||||
|
SOURCES += sinqEPICSApp/src/EL734Driver.cpp
|
||||||
|
SOURCES += sinqEPICSApp/src/NanotecDriver.cpp
|
||||||
|
SOURCES += sinqEPICSApp/src/stptok.cpp
|
||||||
|
|
||||||
|
# MISCS would be the place to keep the stream device template files
|
36
Makefile.RHEL7
Normal file
36
Makefile.RHEL7
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
# This build the sinq extensions for the PSI EPICS setup
|
||||||
|
include /ioc/tools/driver.makefile
|
||||||
|
|
||||||
|
MODULE=sinq
|
||||||
|
LIBVERSION=koennecke
|
||||||
|
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
|
||||||
|
|
||||||
|
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
|
37
Makefile.RHEL7.michele
Normal file
37
Makefile.RHEL7.michele
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# This build the sinq extensions for the PSI EPICS setup
|
||||||
|
include /ioc/tools/driver.makefile
|
||||||
|
|
||||||
|
MODULE=sinq
|
||||||
|
LIBVERSION=brambilla_m
|
||||||
|
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
|
40
README.md
Normal file
40
README.md
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
# 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.
|
||||||
|
|
@ -32,3 +32,5 @@ INSTALL_LOCATION=/afs/psi.ch/project/sinqdev/sinqepicsapp
|
|||||||
# You must rebuild in the iocBoot directory for this to
|
# You must rebuild in the iocBoot directory for this to
|
||||||
# take effect.
|
# take effect.
|
||||||
#IOCS_APPL_TOP = </IOC/path/to/application/top>
|
#IOCS_APPL_TOP = </IOC/path/to/application/top>
|
||||||
|
STATIC_BUILD=NO
|
||||||
|
SHARED_LIBRARIES=YES
|
||||||
|
@ -25,16 +25,20 @@ TEMPLATE_TOP=$(EPICS_BASE)/templates/makeBaseApp/top
|
|||||||
#SNCSEQ=$(EPICS_BASE)/../modules/soft/seq
|
#SNCSEQ=$(EPICS_BASE)/../modules/soft/seq
|
||||||
|
|
||||||
# EPICS_BASE usually appears last so other apps can override stuff:
|
# EPICS_BASE usually appears last so other apps can override stuff:
|
||||||
EPICS_BASE=/usr/local/epics
|
|
||||||
|
#EPICS_BASE=
|
||||||
|
#MODULES=/home/epics/modules
|
||||||
|
|
||||||
# Set RULES here if you want to take build rules from somewhere
|
# Set RULES here if you want to take build rules from somewhere
|
||||||
# other than EPICS_BASE:
|
# other than EPICS_BASE:
|
||||||
#RULES=/path/to/epics/support/module/rules/x-y
|
##RULES=/path/to/epics/support/module/rules/x-y
|
||||||
MOTOR=/usr/local/epics/support/motor-6-7
|
#MOTOR=/opt/epics/modules/motor/6.10.0/3.14.12.5
|
||||||
ASYN=/usr/local/epics/support/asyn-4-18
|
#ASYN=/opt/epics/modules/asyn/4.27.0/3.14.12.5
|
||||||
STD=/usr/local/epics/support/std-3-1
|
#SYNAPPSSTD=/opt/epics/modules/synAppsStd/3.4.1/3.14.12.5/
|
||||||
ANC=/usr/local/epics/anc350v17
|
##ANC=/usr/local/epics/anc350v17
|
||||||
STREAMS=/usr/local/epics/support/StreamDevice-2-6
|
#STREAMS=/opt/epics/modules/streamdevice/2.6.0/3.14.12.5
|
||||||
LAKESHORE336=/usr/local/epics/support/lakeshore336
|
##LAKESHORE336=/usr/local/epics/support/lakeshore336
|
||||||
BUSY=/usr/local/epics/support/busy-1-4
|
#BUSY=/opt/epics/modules/busy/1.6.0/3.14.12.5
|
||||||
OXINSTCRYOJET=/usr/local/epics/support/OxInstCryojet-2-18-3
|
##OXINSTCRYOJET=/usr/local/epics/support/OxInstCryojet-2-18-3
|
||||||
|
#PCRE=/opt/epics/modules/pcre/8.36.0/3.14.12.5
|
||||||
|
|
||||||
|
61
essst.cmd
Executable file
61
essst.cmd
Executable file
@ -0,0 +1,61 @@
|
|||||||
|
###!/opt/epics/modules/environment/1.8.0/3.14.12.5/bin/centos7-x86_64/iocsh
|
||||||
|
|
||||||
|
var requireDebug 2
|
||||||
|
|
||||||
|
require sinq, local
|
||||||
|
|
||||||
|
|
||||||
|
#---------- connect to controllers
|
||||||
|
drvAsynIPPortConfigure("serial1", "localhost:60001",0,0,0)
|
||||||
|
drvAsynIPPortConfigure("serial2", "localhost:60002",0,0,0)
|
||||||
|
drvAsynIPPortConfigure("serial3", "localhost:60003",0,0,0)
|
||||||
|
EL734CreateController("mota","serial1",12);
|
||||||
|
EL734CreateController("motb","serial2",12);
|
||||||
|
EL734CreateController("motc","serial3",12);
|
||||||
|
|
||||||
|
### Motors
|
||||||
|
|
||||||
|
dbLoadRecords("asynRecord.db","P=SQ:AMOR:,R=serial1,PORT=serial1,ADDR=0,OMAX=80,IMAX=80")
|
||||||
|
dbLoadRecords("asynRecord.db","P=SQ:AMOR:,R=serial2,PORT=serial1,ADDR=0,OMAX=80,IMAX=80")
|
||||||
|
dbLoadRecords("asynRecord.db","P=SQ:AMOR:,R=serial3,PORT=serial1,ADDR=0,OMAX=80,IMAX=80")
|
||||||
|
|
||||||
|
dbLoadTemplate "mota.substitutions"
|
||||||
|
dbLoadTemplate "motb.substitutions"
|
||||||
|
dbLoadTemplate "motc.substitutions"
|
||||||
|
|
||||||
|
|
||||||
|
#--------- load EL737 counter box
|
||||||
|
drvAsynIPPortConfigure("cter1","localhost:62000",0,0,0)
|
||||||
|
dbLoadRecords("asynRecord.db","P=SQ:AMOR:,R=cter1,PORT=cter1,ADDR=0,OMAX=80,IMAX=80")
|
||||||
|
dbLoadRecords("el737Record.db")
|
||||||
|
|
||||||
|
#asynSetTraceIOMask("cter1",0,2)
|
||||||
|
|
||||||
|
#----------- load Magnets
|
||||||
|
drvAsynIPPortConfigure("slsvme", "localhost:60066",0,0,0)
|
||||||
|
#drvAsynIPPortConfigure("slsvme", "localhost:8080",0,0,0)
|
||||||
|
|
||||||
|
dbLoadRecords("asynRecord.db","P=SQ:AMOR:,R=slsvme,PORT=slsvme,ADDR=0,OMAX=80,IMAX=80")
|
||||||
|
|
||||||
|
epicsEnvSet ("STREAM_PROTOCOL_PATH", "$(TOP)/db:.")
|
||||||
|
|
||||||
|
dbLoadRecords("slsvme.db","PREFIX=SQ:AMOR:PBY:,NO=1")
|
||||||
|
dbLoadRecords("slsvme.db","PREFIX=SQ:AMOR:FMA:,NO=2")
|
||||||
|
dbLoadRecords("slsvme.db","PREFIX=SQ:AMOR:ABY:,NO=3")
|
||||||
|
|
||||||
|
#-------------- load SPS
|
||||||
|
drvAsynIPPortConfigure("sps1", "localhost:60077",0,0,0)
|
||||||
|
dbLoadRecords("asynRecord.db","P=SQ:AMOR:,R=spsdirect,PORT=sps1,ADDR=0,OMAX=80,IMAX=80")
|
||||||
|
dbLoadRecords("spsamor.db","PREFIX=SQ:AMOR:SPS1:")
|
||||||
|
|
||||||
|
#------------- Load dimetix distance measurement device
|
||||||
|
drvAsynIPPortConfigure("dimetix", "localhost:60088",0,0,0)
|
||||||
|
dbLoadRecords("asynRecord.db","P=SQ:AMOR:,R=dimetixdirect,PORT=dimetix,ADDR=0,OMAX=80,IMAX=80")
|
||||||
|
dbLoadRecords("dimetix.db","PREFIX=SQ:AMOR:DIMETIX:")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
iocInit
|
||||||
|
|
||||||
|
## Start any sequence programs
|
||||||
|
#seq sncxxx,"user=koenneckeHost"
|
@ -1,8 +0,0 @@
|
|||||||
epicsEnvSet("ARCH","linux-x86-debug")
|
|
||||||
epicsEnvSet("IOC","iocsinqEPICS")
|
|
||||||
epicsEnvSet("TOP","/afs/psi.ch/project/sinqdev/sinqepicsapp")
|
|
||||||
epicsEnvSet("EPICS_BASE","/usr/local/epics")
|
|
||||||
epicsEnvSet("ASYN","/usr/local/epics/support/asyn-4-18")
|
|
||||||
epicsEnvSet("MOTOR","/usr/local/epics/support/motor-6-7")
|
|
||||||
epicsEnvSet("LAKESHORE336","/usr/local/epics/support/lakeshore336")
|
|
||||||
epicsEnvSet("OXINSTCRYOJET","/usr/local/epics/support/OxInstCryojet-2-18-3")
|
|
23
iocBoot/iocsinqEPICS/euromovetest.cmd
Executable file
23
iocBoot/iocsinqEPICS/euromovetest.cmd
Executable file
@ -0,0 +1,23 @@
|
|||||||
|
#!/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,10 +1,21 @@
|
|||||||
file "$(MOTOR)/db/basic_asyn_motor.db"
|
qfile "$(MOTOR)/db/basic_asyn_motor.db"
|
||||||
{
|
{
|
||||||
pattern
|
pattern
|
||||||
{P, N, M, DTYP, PORT, ADDR, DESC, EGU, DIR, VELO, VBAS, ACCL, BDST, BVEL, BACC, MRES, PREC, DHLM, DLLM, INIT}
|
{P, N, M, DTYP, PORT, ADDR, DESC, EGU, DIR, VELO, VBAS, ACCL, BDST, BVEL, BACC, MRES, PREC, DHLM, DLLM, INIT}
|
||||||
{NZ:mota:, 1, "m$(N)", "asynMotor", mota, 1, "sgu", degree, Pos, 2.0, 0.1, .2, 0, 1, .2, 1., 3, 20, -20, ""}
|
{NZ:mota:, 1, "m$(N)", "asynMotor", mota, 1, "sgu", degree, Pos, 2.0, 0.1, .2, 0, 1, .2, 1., 3, 20, -20, ""}
|
||||||
{NZ:mota:, 2, "m$(N)", "asynMotor", mota, 2, "sgl", degree, Pos, 2.0, 0.1, .2, 0, 1, .2, 1., 3, 20, -20, ""}
|
{NZ:mota:, 2, "m$(N)", "asynMotor", mota, 2, "sgl", degree, Pos, 2.0, 0.1, .2, 0, 1, .2, 1., 3, 20, -20, ""}
|
||||||
{NZ:mota:, 3, "m$(N)", "asynMotor", mota, 3, "sgd", degree, Pos, 2.0, 0.1, .2, 0, 1, .2, 1., 3, 20, -20, ""}
|
{NZ:mota:, 3, "m$(N)", "asynMotor", mota, 3, "sgd", degree, Pos, 2.0, 0.1, .2, 0, 1, .2, 1., 3, 20, -20, ""}
|
||||||
{NZ:mota:, 4, "m$(N)", "asynMotor", mota, 4, "som", degree, Pos, 2.0, 0.1, .2, 0, 1, .2, 0.001, 3, 37, -37, ""}
|
{NZ:mota:, 4, "m$(N)", "asynMotor", mota, 4, "som", degree, Pos, 2.0, 0.1, .2, 0, 1, .2, 0.001, 3, 37, -37, ""}
|
||||||
{NZ:mota:, 5, "m$(N)", "asynMotor", mota, 5, "sty", degree, Pos, 2.0, 0.1, .2, 0, 1, .2, 0.001, 3, 150, -149, ""}
|
{NZ:mota:, 5, "m$(N)", "asynMotor", mota, 5, "sty", degree, Pos, 2.0, 0.1, .2, 0, 1, .2, 0.001, 3, 150, -149, ""}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
file "$(SINQ)/Db/motorMessage.db"
|
||||||
|
{
|
||||||
|
pattern
|
||||||
|
{P,N, M,PORT}
|
||||||
|
{NZ:mota:, 1, "m$(N)",mota}
|
||||||
|
{NZ:mota:, 2, "m$(N)",mota}
|
||||||
|
{NZ:mota:, 3, "m$(N)",mota}
|
||||||
|
{NZ:mota:, 4, "m$(N)",mota}
|
||||||
|
{NZ:mota:, 5, "m$(N)",mota}
|
||||||
|
}
|
13
iocBoot/iocsinqEPICS/motor.substitutions.eurollb
Normal file
13
iocBoot/iocsinqEPICS/motor.substitutions.eurollb
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
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,7 +1,15 @@
|
|||||||
file "$(MOTOR)/db/basic_asyn_motor.db"
|
file "$(BASE)/sinqEPICSApp/Db/basic_asyn_motor.db"
|
||||||
{
|
{
|
||||||
pattern
|
pattern
|
||||||
{P, N, M, DTYP, PORT, ADDR, DESC, EGU, DIR, VELO, VBAS, ACCL, BDST, BVEL, BACC, MRES, PREC, DHLM, DLLM, INIT}
|
{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, 100, -100, "1"}
|
{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, 100, -100, "10"}
|
{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"}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
file "$(BASE)/sinqEPICSApp/Db/motorMessage.db"
|
||||||
|
{
|
||||||
|
pattern
|
||||||
|
{P,N, M,PORT}
|
||||||
|
{KM36:phytron:, 1, "m$(N)",phy}
|
||||||
|
{KM36:phytron:, 2, "m$(N)",phy}
|
||||||
|
}
|
25
iocBoot/iocsinqEPICS/phytest.cmd
Executable file
25
iocBoot/iocsinqEPICS/phytest.cmd
Executable file
@ -0,0 +1,25 @@
|
|||||||
|
#!/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,19 +18,16 @@ epicsEnvSet("dbPATH","${EPICS_BASE}/dbd::${ASYN}/dbd:${MOTOR}/dbd:${ANC}/dbd")
|
|||||||
cd ${TOP}
|
cd ${TOP}
|
||||||
|
|
||||||
## Register all support components
|
## Register all support components
|
||||||
dbLoadDatabase "../../dbd/sinqEPICS.dbd"
|
dbLoadDatabase "../../sinqEPICSApp/src/sinq.dbd"
|
||||||
#dbLoadDatabase "dbd/sinq.dbd"
|
|
||||||
sinqEPICS_registerRecordDeviceDriver pdbbase
|
sinqEPICS_registerRecordDeviceDriver pdbbase
|
||||||
|
|
||||||
## Load record instances
|
|
||||||
#dbLoadRecords("db/xxx.db","user=koenneckeHost")
|
|
||||||
|
|
||||||
|
|
||||||
#---------- load Nanotec motor controller
|
#---------- load Nanotec motor controller
|
||||||
#drvAsynIPPortConfigure("serial1", "narziss-ts:3002",0,0,0)
|
#drvAsynIPPortConfigure("serial1", "narziss-ts:3002",0,0,0)
|
||||||
#drvAsynIPPortConfigure("serial1", "localhost:5050",0,0,0)
|
#drvAsynIPPortConfigure("serial1", "localhost:5050",0,0,0)
|
||||||
drvAsynIPPortConfigure("serial1", "localhost:8080",0,0,0)
|
drvAsynIPPortConfigure("serial1", "localhost:8080",0,0,0)
|
||||||
PhytronCreateController("phy","serial1",1,1);
|
PhytronCreateController("phy","serial1","0",1,1);
|
||||||
|
|
||||||
### Motors
|
### Motors
|
||||||
|
|
||||||
|
94
iocBoot/iocsinqEPICS/slsvme.db
Normal file
94
iocBoot/iocsinqEPICS/slsvme.db
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
# 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")
|
||||||
|
}
|
@ -1,41 +1,42 @@
|
|||||||
#!../../bin/linux-x86/sinqEPICS
|
#!../../bin/linux-x86-debug/sinqEPICS
|
||||||
|
|
||||||
## You may have to change sinqEPICS to something else
|
|
||||||
## everywhere it appears in this file
|
cd /opt/amor/epics
|
||||||
|
|
||||||
< envPaths
|
< envPaths
|
||||||
|
|
||||||
cd ${TOP}
|
|
||||||
|
|
||||||
## Register all support components
|
## Register all support components
|
||||||
dbLoadDatabase "dbd/sinqEPICS.dbd"
|
dbLoadDatabase "dbd/sinqEPICS.dbd"
|
||||||
dbLoadDatabase "dbd/sinq.dbd"
|
dbLoadDatabase "dbd/sinq.dbd"
|
||||||
sinqEPICS_registerRecordDeviceDriver pdbbase
|
sinqEPICS_registerRecordDeviceDriver pdbbase
|
||||||
|
|
||||||
## Load record instances
|
|
||||||
#dbLoadRecords("db/xxx.db","user=koenneckeHost")
|
|
||||||
|
|
||||||
|
#---------- connect to controllers
|
||||||
#---------- load EL734 motor controller
|
drvAsynIPPortConfigure("serial1", "localhost:60001",0,0,0)
|
||||||
drvAsynIPPortConfigure("serial1", "narziss-ts:3002",0,0,0)
|
drvAsynIPPortConfigure("serial2", "localhost:60002",0,0,0)
|
||||||
#drvAsynIPPortConfigure("serial1", "localhost:8080",0,0,0)
|
drvAsynIPPortConfigure("serial3", "localhost:60003",0,0,0)
|
||||||
EL734CreateController("mota","serial1",6);
|
EL734CreateController("mota","serial1",12);
|
||||||
|
EL734CreateController("motb","serial2",12);
|
||||||
|
EL734CreateController("motc","serial3",12);
|
||||||
|
|
||||||
### Motors
|
### Motors
|
||||||
|
|
||||||
dbLoadRecords("$(ASYN)/db/asynRecord.db","P=NZ:,R=serial1,PORT=serial1,ADDR=0,OMAX=80,IMAX=80")
|
dbLoadRecords("$(ASYN)/db/asynRecord.db","P=SQ:AMOR:,R=serial1,PORT=serial1,ADDR=0,OMAX=80,IMAX=80")
|
||||||
|
dbLoadRecords("$(ASYN)/db/asynRecord.db","P=SQ:AMOR:,R=serial2,PORT=serial1,ADDR=0,OMAX=80,IMAX=80")
|
||||||
|
dbLoadRecords("$(ASYN)/db/asynRecord.db","P=SQ:AMOR:,R=serial3,PORT=serial1,ADDR=0,OMAX=80,IMAX=80")
|
||||||
|
|
||||||
|
dbLoadTemplate "mota.substitutions"
|
||||||
cd ${TOP}/iocBoot/${IOC}
|
dbLoadTemplate "motb.substitutions"
|
||||||
dbLoadTemplate "motor.substitutions.el734"
|
dbLoadTemplate "motc.substitutions"
|
||||||
|
|
||||||
|
|
||||||
#--------- load EL737 counter box
|
#--------- load EL737 counter box
|
||||||
drvAsynIPPortConfigure("cter1","narziss-ts:3003",0,0,0)
|
drvAsynIPPortConfigure("cter1","localhost:62000",0,0,0)
|
||||||
dbLoadRecords("$(ASYN)/db/asynRecord.db","P=NZ:,R=cter1,PORT=cter1,ADDR=0,OMAX=80,IMAX=80")
|
dbLoadRecords("$(ASYN)/db/asynRecord.db","P=SQ:AMOR:,R=cter1,PORT=cter1,ADDR=0,OMAX=80,IMAX=80")
|
||||||
dbLoadRecords("${TOP}/db/el737Record.db")
|
dbLoadRecords("${TOP}/db/el737Record.db")
|
||||||
|
|
||||||
asynSetTraceIOMask("cter1",0,2)
|
#asynSetTraceIOMask("cter1",0,2)
|
||||||
|
|
||||||
iocInit
|
iocInit
|
||||||
|
|
||||||
|
34
iocBoot/iocsinqEPICS/stdimetix.cmd
Executable file
34
iocBoot/iocsinqEPICS/stdimetix.cmd
Executable file
@ -0,0 +1,34 @@
|
|||||||
|
#!../../bin/centos7-x86_64/sinqEPICS
|
||||||
|
# for debugging..................
|
||||||
|
## You may have to change sinqEPICS to something else
|
||||||
|
## everywhere it appears in this file
|
||||||
|
|
||||||
|
< envPaths
|
||||||
|
|
||||||
|
cd ${TOP}
|
||||||
|
|
||||||
|
## Register all support components
|
||||||
|
dbLoadDatabase "dbd/sinqEPICS.dbd"
|
||||||
|
dbLoadDatabase "dbd/sinq.dbd"
|
||||||
|
sinqEPICS_registerRecordDeviceDriver pdbbase
|
||||||
|
|
||||||
|
## Load record instances
|
||||||
|
#dbLoadRecords("db/xxx.db","user=koenneckeHost")
|
||||||
|
|
||||||
|
|
||||||
|
#---------- Install SPS
|
||||||
|
drvAsynIPPortConfigure("dimetix", "localhost:64000",0,0,0)
|
||||||
|
#drvAsynIPPortConfigure("slsvme", "localhost:8080",0,0,0)
|
||||||
|
|
||||||
|
dbLoadRecords("$(ASYN)/db/asynRecord.db","P=SQ:AMOR:,R=dimetix,PORT=dimetix,ADDR=0,OMAX=80,IMAX=80")
|
||||||
|
|
||||||
|
epicsEnvSet ("STREAM_PROTOCOL_PATH", "$(TOP)/sinqEPICSApp/Db:.")
|
||||||
|
|
||||||
|
cd ${TOP}/iocBoot/iocsinqEPICS
|
||||||
|
dbLoadRecords("$(TOP)/sinqEPICSApp/Db/dimetix.db","PREFIX=SQ:AMOR:DIMETIX:")
|
||||||
|
|
||||||
|
|
||||||
|
iocInit
|
||||||
|
|
||||||
|
## Start any sequence programs
|
||||||
|
#seq sncxxx,"user=koenneckeHost"
|
34
iocBoot/iocsinqEPICS/stel755.cmd
Executable file
34
iocBoot/iocsinqEPICS/stel755.cmd
Executable file
@ -0,0 +1,34 @@
|
|||||||
|
#!../../bin/linux-x86-debug/sinqEPICS
|
||||||
|
# for debugging..................
|
||||||
|
## You may have to change sinqEPICS to something else
|
||||||
|
## everywhere it appears in this file
|
||||||
|
|
||||||
|
< envPaths
|
||||||
|
|
||||||
|
cd ${TOP}
|
||||||
|
|
||||||
|
## Register all support components
|
||||||
|
dbLoadDatabase "$(TOP)/dbd/sinqEPICS.dbd"
|
||||||
|
dbLoadDatabase "$(TOP)/sinqEPICSApp/src/sinq.dbd"
|
||||||
|
sinqEPICS_registerRecordDeviceDriver pdbbase
|
||||||
|
|
||||||
|
## Load record instances
|
||||||
|
#dbLoadRecords("db/xxx.db","user=koenneckeHost")
|
||||||
|
|
||||||
|
|
||||||
|
#---------- Install SLSVME
|
||||||
|
drvAsynIPPortConfigure("el755", "narziss-ts:3004",0,0,0)
|
||||||
|
#drvAsynIPPortConfigure("slsvme", "localhost:8080",0,0,0)
|
||||||
|
|
||||||
|
dbLoadRecords("$(ASYN)/db/asynRecord.db","P=SQ:NZ:,R=el755,PORT=el755,ADDR=0,OMAX=80,IMAX=80")
|
||||||
|
|
||||||
|
epicsEnvSet ("STREAM_PROTOCOL_PATH", "$(TOP)/sinqEPICSApp/Db:.")
|
||||||
|
|
||||||
|
cd ${TOP}/iocBoot/iocsinqEPICS
|
||||||
|
dbLoadRecords("$(TOP)/sinqEPICSApp/Db/el755.db","PREFIX=SQ:NZ:AMAG:,NO=2")
|
||||||
|
|
||||||
|
|
||||||
|
iocInit
|
||||||
|
|
||||||
|
## Start any sequence programs
|
||||||
|
#seq sncxxx,"user=koenneckeHost"
|
34
iocBoot/iocsinqEPICS/stslsvme.cmd
Executable file
34
iocBoot/iocsinqEPICS/stslsvme.cmd
Executable file
@ -0,0 +1,34 @@
|
|||||||
|
#!../../bin/centos7-x86_64/sinqEPICS
|
||||||
|
# for debugging..................
|
||||||
|
## You may have to change sinqEPICS to something else
|
||||||
|
## everywhere it appears in this file
|
||||||
|
|
||||||
|
< envPaths
|
||||||
|
|
||||||
|
cd ${TOP}
|
||||||
|
|
||||||
|
## Register all support components
|
||||||
|
dbLoadDatabase "dbd/sinqEPICS.dbd"
|
||||||
|
dbLoadDatabase "dbd/sinq.dbd"
|
||||||
|
sinqEPICS_registerRecordDeviceDriver pdbbase
|
||||||
|
|
||||||
|
## Load record instances
|
||||||
|
#dbLoadRecords("db/xxx.db","user=koenneckeHost")
|
||||||
|
|
||||||
|
|
||||||
|
#---------- Install SLSVME
|
||||||
|
drvAsynIPPortConfigure("slsvme", "mpc2084:60066",0,0,0)
|
||||||
|
#drvAsynIPPortConfigure("slsvme", "localhost:8080",0,0,0)
|
||||||
|
|
||||||
|
dbLoadRecords("$(ASYN)/db/asynRecord.db","P=SQ:AMOR:,R=slsvme,PORT=slsvme,ADDR=0,OMAX=80,IMAX=80")
|
||||||
|
|
||||||
|
epicsEnvSet ("STREAM_PROTOCOL_PATH", "$(TOP)/sinqEPICSApp/Db:.")
|
||||||
|
|
||||||
|
cd ${TOP}/iocBoot/iocsinqEPICS
|
||||||
|
dbLoadRecords("slsvme.db","PREFIX=SQ:AMOR:PBY:,NO=1")
|
||||||
|
|
||||||
|
|
||||||
|
iocInit
|
||||||
|
|
||||||
|
## Start any sequence programs
|
||||||
|
#seq sncxxx,"user=koenneckeHost"
|
34
iocBoot/iocsinqEPICS/stsps.cmd
Executable file
34
iocBoot/iocsinqEPICS/stsps.cmd
Executable file
@ -0,0 +1,34 @@
|
|||||||
|
#!../../bin/centos7-x86_64/sinqEPICS
|
||||||
|
# for debugging..................
|
||||||
|
## You may have to change sinqEPICS to something else
|
||||||
|
## everywhere it appears in this file
|
||||||
|
|
||||||
|
< envPaths
|
||||||
|
|
||||||
|
cd ${TOP}
|
||||||
|
|
||||||
|
## Register all support components
|
||||||
|
dbLoadDatabase "dbd/sinqEPICS.dbd"
|
||||||
|
dbLoadDatabase "dbd/sinq.dbd"
|
||||||
|
sinqEPICS_registerRecordDeviceDriver pdbbase
|
||||||
|
|
||||||
|
## Load record instances
|
||||||
|
#dbLoadRecords("db/xxx.db","user=koenneckeHost")
|
||||||
|
|
||||||
|
|
||||||
|
#---------- Install SPS
|
||||||
|
drvAsynIPPortConfigure("spss5", "localhost:63000",0,0,0)
|
||||||
|
#drvAsynIPPortConfigure("slsvme", "localhost:8080",0,0,0)
|
||||||
|
|
||||||
|
dbLoadRecords("$(ASYN)/db/asynRecord.db","P=SQ:AMOR:,R=spss5,PORT=spss5,ADDR=0,OMAX=80,IMAX=80")
|
||||||
|
|
||||||
|
epicsEnvSet ("STREAM_PROTOCOL_PATH", "$(TOP)/sinqEPICSApp/Db:.")
|
||||||
|
|
||||||
|
cd ${TOP}/iocBoot/iocsinqEPICS
|
||||||
|
dbLoadRecords("$(TOP)/sinqEPICSApp/Db/spsamor.db","PREFIX=SQ:AMOR:SPSS5:")
|
||||||
|
|
||||||
|
|
||||||
|
iocInit
|
||||||
|
|
||||||
|
## Start any sequence programs
|
||||||
|
#seq sncxxx,"user=koenneckeHost"
|
7
makesinqtar
Executable file
7
makesinqtar
Executable file
@ -0,0 +1,7 @@
|
|||||||
|
#!/usr/bin/tclsh
|
||||||
|
|
||||||
|
set dir [pwd]
|
||||||
|
|
||||||
|
cd /usr/local/ioc
|
||||||
|
|
||||||
|
exec /usr/bin/tar czvf $dir/sinqepics.tgz modules/scaler modules/sinq modules/anc350 modules/autosave
|
@ -10,7 +10,7 @@ include $(TOP)/configure/CONFIG
|
|||||||
#----------------------------------------------------
|
#----------------------------------------------------
|
||||||
# Create and install (or just install) into <top>/db
|
# Create and install (or just install) into <top>/db
|
||||||
# databases, templates, substitutions like this
|
# databases, templates, substitutions like this
|
||||||
#DB += xxx.db
|
DB_INSTALL += slsvme.proto
|
||||||
|
|
||||||
#----------------------------------------------------
|
#----------------------------------------------------
|
||||||
# If <anyname>.db template is not named <anyname>*.template add
|
# If <anyname>.db template is not named <anyname>*.template add
|
||||||
|
9
sinqEPICSApp/Db/asynRecord.db
Normal file
9
sinqEPICSApp/Db/asynRecord.db
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
record(asyn,"$(P)$(R)")
|
||||||
|
{
|
||||||
|
field(DTYP,"asynRecordDevice")
|
||||||
|
field(PORT,"$(PORT)")
|
||||||
|
field(ADDR,"$(ADDR)")
|
||||||
|
field(OMAX,"$(OMAX)")
|
||||||
|
field(IMAX,"$(IMAX)")
|
||||||
|
}
|
||||||
|
|
23
sinqEPICSApp/Db/basic_asyn_motor.db
Normal file
23
sinqEPICSApp/Db/basic_asyn_motor.db
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
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")
|
||||||
|
}
|
||||||
|
|
21
sinqEPICSApp/Db/basic_motor.db
Normal file
21
sinqEPICSApp/Db/basic_motor.db
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
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")
|
||||||
|
}
|
||||||
|
|
40
sinqEPICSApp/Db/dimetix.db
Normal file
40
sinqEPICSApp/Db/dimetix.db
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
|
||||||
|
# DB file for dimetix laser distance measurement device
|
||||||
|
|
||||||
|
##
|
||||||
|
## Switch the laser
|
||||||
|
##
|
||||||
|
record(bo, "$(PREFIX)LASER") {
|
||||||
|
field(DESC, "Switch laser on and off")
|
||||||
|
field(DTYP,"stream")
|
||||||
|
field(OUT,"@dimetix.proto setlaser() dimetix 0")
|
||||||
|
field(PINI, "YES")
|
||||||
|
field(VAL, "0")
|
||||||
|
field(ZNAM, "OFF")
|
||||||
|
field(ONAM, "ON")
|
||||||
|
}
|
||||||
|
|
||||||
|
##
|
||||||
|
## Read the distance
|
||||||
|
##
|
||||||
|
record(ai, "$(PREFIX)DIST") {
|
||||||
|
field(DTYP, "stream")
|
||||||
|
field(DESC, "Distance")
|
||||||
|
field(INP, "@dimetix.proto read() dimetix 0")
|
||||||
|
field(SCAN, "1 second")
|
||||||
|
field(PREC, "1")
|
||||||
|
field(EGU, "mm")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
## Set the readback (for simulation purposes only)
|
||||||
|
##
|
||||||
|
record(ao, "$(PREFIX)SimVal") {
|
||||||
|
field(DTYP, "stream")
|
||||||
|
field(DESC, "Set readback for simulation")
|
||||||
|
field(OUT, "@dimetix.proto setreadback() dimetix 0")
|
||||||
|
field(PREC, "1")
|
||||||
|
field(EGU, "mm")
|
||||||
|
}
|
||||||
|
|
23
sinqEPICSApp/Db/dimetix.proto
Normal file
23
sinqEPICSApp/Db/dimetix.proto
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# Streamdevice protocol file for a Dimetix distance measuring device as used at
|
||||||
|
# AMOR
|
||||||
|
|
||||||
|
InTerminator = "\n";
|
||||||
|
OutTerminator = "\r\n";
|
||||||
|
ExtraInput = Ignore;
|
||||||
|
|
||||||
|
setlaser {
|
||||||
|
out "%{s0p|s0o}";
|
||||||
|
in "g0?";
|
||||||
|
}
|
||||||
|
|
||||||
|
setreadback {
|
||||||
|
out "setval %d";
|
||||||
|
in "g0?";
|
||||||
|
}
|
||||||
|
|
||||||
|
read {
|
||||||
|
out "s0g";
|
||||||
|
in "g0g+%d";
|
||||||
|
@mismatch {in "@E213"}
|
||||||
|
}
|
||||||
|
|
27
sinqEPICSApp/Db/el737Record.db
Normal file
27
sinqEPICSApp/Db/el737Record.db
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
|
||||||
|
record(bo,"$(P):Pause")
|
||||||
|
{
|
||||||
|
field(DTYP,"Soft Channel")
|
||||||
|
}
|
||||||
|
record(longin,"$(P):Status")
|
||||||
|
{
|
||||||
|
field(DTYP,"Soft Channel")
|
||||||
|
}
|
||||||
|
record(stringin,"$(P):MsgTxt")
|
||||||
|
{
|
||||||
|
field(DTYP,"Soft Channel")
|
||||||
|
}
|
||||||
|
record(longout,"$(P):ThresholdCounter")
|
||||||
|
{
|
||||||
|
field(DTYP,"Soft Channel")
|
||||||
|
}
|
||||||
|
record(longout,"$(P):Threshold")
|
||||||
|
{
|
||||||
|
field(DTYP,"Soft Channel")
|
||||||
|
}
|
||||||
|
record(scaler,"$(P)")
|
||||||
|
{
|
||||||
|
field(DESC,"$(DESC)")
|
||||||
|
field(DTYP,"asynScalerEL737")
|
||||||
|
field(OUT,"INST_IO @asyn($(PORT),0)")
|
||||||
|
}
|
22
sinqEPICSApp/Db/el755.db
Normal file
22
sinqEPICSApp/Db/el755.db
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
##
|
||||||
|
## Read the Current
|
||||||
|
##
|
||||||
|
record(ai, "$(PREFIX)CurRBV") {
|
||||||
|
field(DTYP, "stream")
|
||||||
|
field(DESC, "Current Readback")
|
||||||
|
field(INP, "@el755.proto read($(NO)) el755 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, "@el755.proto write($(NO)) el755 0")
|
||||||
|
field(PREC, "3")
|
||||||
|
field(EGU, "A")
|
||||||
|
}
|
22
sinqEPICSApp/Db/el755.proto
Normal file
22
sinqEPICSApp/Db/el755.proto
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# Streamdevice protocol file for the PSI EL755 Magnet Controller
|
||||||
|
|
||||||
|
InTerminator = "\r";
|
||||||
|
OutTerminator = "\r";
|
||||||
|
#ExtraInput = Ignore;
|
||||||
|
|
||||||
|
read {
|
||||||
|
out "I \$1";
|
||||||
|
in "%*f %f";
|
||||||
|
@mismatch {out "RMT 1";
|
||||||
|
in "";
|
||||||
|
out "ECHO 0";
|
||||||
|
in "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
write {
|
||||||
|
out "I \$1 %f";
|
||||||
|
in "";
|
||||||
|
}
|
||||||
|
|
18
sinqEPICSApp/Db/motorMessage.db
Normal file
18
sinqEPICSApp/Db/motorMessage.db
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
# 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")
|
||||||
|
}
|
13
sinqEPICSApp/Db/motorSet.db
Normal file
13
sinqEPICSApp/Db/motorSet.db
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# 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")
|
||||||
|
}
|
94
sinqEPICSApp/Db/slsvme.db
Normal file
94
sinqEPICSApp/Db/slsvme.db
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
# 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")
|
||||||
|
}
|
31
sinqEPICSApp/Db/slsvme.proto
Normal file
31
sinqEPICSApp/Db/slsvme.proto
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# Streamdevice protocol file for the PSI SLS VME magnet controller used at AMOR
|
||||||
|
|
||||||
|
InTerminator = "\n";
|
||||||
|
OutTerminator = "\r\n";
|
||||||
|
#ExtraInput = Ignore;
|
||||||
|
|
||||||
|
read {
|
||||||
|
out "r \$1 \$2";
|
||||||
|
in "\$1 \$2 %f";
|
||||||
|
}
|
||||||
|
|
||||||
|
readErrTxt {
|
||||||
|
out "r \$1 errtext";
|
||||||
|
in "\$1 errtext %s";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
write {
|
||||||
|
out "w \$1 \$2 %f";
|
||||||
|
in "OK";
|
||||||
|
}
|
||||||
|
|
||||||
|
readonoff {
|
||||||
|
out "r \$1 onoff";
|
||||||
|
in "\$1 onoff %{off|on}";
|
||||||
|
}
|
||||||
|
|
||||||
|
setpower {
|
||||||
|
out "w \$1 %{on|off}";
|
||||||
|
in "OK";
|
||||||
|
}
|
32
sinqEPICSApp/Db/spsamor.db
Normal file
32
sinqEPICSApp/Db/spsamor.db
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# DB definition for a SPS-S5 with the custom RS232 interface as used at SINQ.
|
||||||
|
|
||||||
|
#The digital inputs. Ignore the first one, which is the response character R
|
||||||
|
|
||||||
|
record(waveform, "$(PREFIX)DigitalInput") {
|
||||||
|
field(DTYP, "stream")
|
||||||
|
field(INP, "@spss5.proto readDigital() spss5 0")
|
||||||
|
field(SCAN, "5 second")
|
||||||
|
field(NELM, "16")
|
||||||
|
field(FTVL, "LONG")
|
||||||
|
field(PREC, "1")
|
||||||
|
}
|
||||||
|
|
||||||
|
# The analog inputs, again ignore the first one as it is the response character A
|
||||||
|
record(waveform, "$(PREFIX)AnalogInput") {
|
||||||
|
field(DTYP, "stream")
|
||||||
|
field(INP, "@spss5.proto readAnalog() spss5 0")
|
||||||
|
field(SCAN, "5 second")
|
||||||
|
field(NELM, "8")
|
||||||
|
field(FTVL, "LONG")
|
||||||
|
field(PREC, "1")
|
||||||
|
}
|
||||||
|
|
||||||
|
# This is forwarding the S0001 style strings to the hardware. This is the easiest solution but requires
|
||||||
|
# Hardware knowledge upstream. Which is required anyway. The syntax is: SBBBI with 3 characters for the byte
|
||||||
|
# to set and one character for the bit in the byte. The Byte must always be filled with 0 to the left.
|
||||||
|
record(stringout, "$(PREFIX)Push") {
|
||||||
|
field(DESC, "String for pushing buttons")
|
||||||
|
field(DTYP, "stream")
|
||||||
|
field(OUT, "@spss5.proto push() spss5 0")
|
||||||
|
}
|
||||||
|
|
25
sinqEPICSApp/Db/spss5.proto
Normal file
25
sinqEPICSApp/Db/spss5.proto
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# Streamdevice protocol file for the Siemens SPS-S5 with the custom RS232 interface as used at
|
||||||
|
# AMOR
|
||||||
|
|
||||||
|
InTerminator = "\n";
|
||||||
|
OutTerminator = "\r\n";
|
||||||
|
ExtraInput = Ignore;
|
||||||
|
|
||||||
|
|
||||||
|
readDigital {
|
||||||
|
out "R";
|
||||||
|
separator="";
|
||||||
|
in "\?%d";
|
||||||
|
}
|
||||||
|
|
||||||
|
readAnalog {
|
||||||
|
out "A";
|
||||||
|
separator="";
|
||||||
|
in "\?%d";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
push {
|
||||||
|
out "%s";
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,10 @@ USAGE... Motor driver support for the PSI EL734 controller.
|
|||||||
Mark Koennecke
|
Mark Koennecke
|
||||||
February 2013
|
February 2013
|
||||||
|
|
||||||
|
Updated to have an MsgTxt field through SINQAxis, error handling
|
||||||
|
|
||||||
|
Mark Koennecke, May, August 2017
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@ -33,18 +37,13 @@ February 2013
|
|||||||
* \param[in] numAxes The number of axes that this controller supports
|
* \param[in] numAxes The number of axes that this controller supports
|
||||||
*/
|
*/
|
||||||
EL734Controller::EL734Controller(const char *portName, const char *EL734PortName, int numAxes)
|
EL734Controller::EL734Controller(const char *portName, const char *EL734PortName, int numAxes)
|
||||||
: asynMotorController(portName, numAxes+1, 0,
|
: SINQController(portName, EL734PortName, numAxes)
|
||||||
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;
|
int axis;
|
||||||
asynStatus status;
|
asynStatus status;
|
||||||
EL734Axis *pAxis;
|
|
||||||
static const char *functionName = "EL734Controller::EL734Controller";
|
static const char *functionName = "EL734Controller::EL734Controller";
|
||||||
|
|
||||||
|
|
||||||
/* Connect to EL734 controller */
|
/* Connect to EL734 controller */
|
||||||
status = pasynOctetSyncIO->connect(EL734PortName, 0, &pasynUserController_, NULL);
|
status = pasynOctetSyncIO->connect(EL734PortName, 0, &pasynUserController_, NULL);
|
||||||
if (status) {
|
if (status) {
|
||||||
@ -58,7 +57,7 @@ EL734Controller::EL734Controller(const char *portName, const char *EL734PortName
|
|||||||
switchRemote();
|
switchRemote();
|
||||||
|
|
||||||
for (axis=0; axis<numAxes; axis++) {
|
for (axis=0; axis<numAxes; axis++) {
|
||||||
pAxis = new EL734Axis(this, axis+1);
|
new EL734Axis(this, axis+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
startPoller(1000./1000., IDLEPOLL, 2);
|
startPoller(1000./1000., IDLEPOLL, 2);
|
||||||
@ -114,21 +113,20 @@ EL734Axis* EL734Controller::getAxis(int axisNo)
|
|||||||
void EL734Controller::switchRemote()
|
void EL734Controller::switchRemote()
|
||||||
{
|
{
|
||||||
char command[COMLEN], reply[COMLEN];
|
char command[COMLEN], reply[COMLEN];
|
||||||
int status;
|
|
||||||
size_t in, out;
|
size_t in, out;
|
||||||
int reason;
|
int reason;
|
||||||
|
|
||||||
strcpy(command,"RMT 1");
|
strcpy(command,"RMT 1");
|
||||||
status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
|
pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
|
||||||
reply,COMLEN, 1.,&out,&in,&reason);
|
reply,COMLEN, 1.,&out,&in,&reason);
|
||||||
strcpy(command,"ECHO 0");
|
strcpy(command,"ECHO 0");
|
||||||
status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
|
pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
|
||||||
reply,COMLEN, 1.,&out,&in,&reason);
|
reply,COMLEN, 1.,&out,&in,&reason);
|
||||||
strcpy(command,"RMT 1");
|
strcpy(command,"RMT 1");
|
||||||
status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
|
pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
|
||||||
reply,COMLEN, 1.,&out,&in,&reason);
|
reply,COMLEN, 1.,&out,&in,&reason);
|
||||||
strcpy(command,"ECHO 0");
|
strcpy(command,"ECHO 0");
|
||||||
status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
|
pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
|
||||||
reply,COMLEN, 1.,&out,&in,&reason);
|
reply,COMLEN, 1.,&out,&in,&reason);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -138,18 +136,22 @@ void EL734Controller::switchRemote()
|
|||||||
* \param[out] reply The controllers reply
|
* \param[out] reply The controllers reply
|
||||||
*/
|
*/
|
||||||
|
|
||||||
asynStatus EL734Controller::transactController(char command[COMLEN], char reply[COMLEN])
|
asynStatus EL734Controller::transactController(int axisNo,char command[COMLEN], char reply[COMLEN])
|
||||||
{
|
{
|
||||||
asynStatus status;
|
asynStatus status;
|
||||||
size_t in, out, i;
|
size_t in, out, i;
|
||||||
int reason;
|
int reason;
|
||||||
char myReply[COMLEN];
|
char myReply[COMLEN], errTxt[256];
|
||||||
|
SINQAxis *axis = getAxis(axisNo);
|
||||||
|
|
||||||
pasynOctetSyncIO->flush(pasynUserController_);
|
pasynOctetSyncIO->flush(pasynUserController_);
|
||||||
|
|
||||||
status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
|
status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
|
||||||
reply,COMLEN, 1.,&out,&in,&reason);
|
reply,COMLEN, 2.,&out,&in,&reason);
|
||||||
if(status != asynSuccess){
|
if(status != asynSuccess){
|
||||||
|
if(axis!= NULL){
|
||||||
|
axis->updateMsgTxtFromDriver("Lost connection to motor controller");
|
||||||
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,13 +180,25 @@ asynStatus EL734Controller::transactController(char command[COMLEN], char reply[
|
|||||||
myReply[i] = (char)tolower((int)reply[i]);
|
myReply[i] = (char)tolower((int)reply[i]);
|
||||||
}
|
}
|
||||||
if(strstr(myReply,"?cmd") != NULL){
|
if(strstr(myReply,"?cmd") != NULL){
|
||||||
errlogSevPrintf(errlogMajor, "Bad command %s", command);
|
snprintf(errTxt,sizeof(errTxt), "Bad command %s at axis %d", command, axisNo);
|
||||||
|
errlogSevPrintf(errlogMajor, errTxt);
|
||||||
|
if(axis!= NULL){
|
||||||
|
axis->updateMsgTxtFromDriver(errTxt);
|
||||||
|
}
|
||||||
return asynError;
|
return asynError;
|
||||||
} else if(strstr(myReply,"?par") != NULL){
|
} else if(strstr(myReply,"?par") != NULL){
|
||||||
errlogSevPrintf(errlogMajor, "Bad parameter in command %s", command);
|
snprintf(errTxt,sizeof(errTxt), "Bad parameter in command %s", command);
|
||||||
|
errlogSevPrintf(errlogMajor, errTxt);
|
||||||
|
if(axis!= NULL){
|
||||||
|
axis->updateMsgTxtFromDriver(errTxt);
|
||||||
|
}
|
||||||
return asynError;
|
return asynError;
|
||||||
} else if(strstr(myReply,"?rng") != NULL){
|
} else if(strstr(myReply,"?rng") != NULL){
|
||||||
errlogSevPrintf(errlogMajor, "Parameter out of range in command %s", command);
|
snprintf(errTxt,sizeof(errTxt), "Parameter out of range in command %s", command);
|
||||||
|
errlogSevPrintf(errlogMajor, errTxt);
|
||||||
|
if(axis!= NULL){
|
||||||
|
axis->updateMsgTxtFromDriver(errTxt);
|
||||||
|
}
|
||||||
return asynError;
|
return asynError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,9 +214,29 @@ asynStatus EL734Controller::transactController(char command[COMLEN], char reply[
|
|||||||
* Initializes register numbers, etc.
|
* Initializes register numbers, etc.
|
||||||
*/
|
*/
|
||||||
EL734Axis::EL734Axis(EL734Controller *pC, int axisNo)
|
EL734Axis::EL734Axis(EL734Controller *pC, int axisNo)
|
||||||
: asynMotorAxis(pC, axisNo),
|
: SINQAxis(pC, axisNo), pC_(pC)
|
||||||
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);
|
||||||
|
} else {
|
||||||
|
errlogPrintf("Bad response - %s - requesting limits at axis %d", reply, axisNo_);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
errlogPrintf("Failed to read limits at axis %d", axisNo_);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -238,8 +272,12 @@ asynStatus EL734Axis::move(double position, int relative, double minVelocity, do
|
|||||||
}
|
}
|
||||||
oredMSR = 0;
|
oredMSR = 0;
|
||||||
homing = 0;
|
homing = 0;
|
||||||
|
errorReported = 0;
|
||||||
|
errlogPrintf("Starting axis %d with destination %f", axisNo_,position/1000);
|
||||||
sprintf(command, "p %d %.3f", axisNo_, position/1000.);
|
sprintf(command, "p %d %.3f", axisNo_, position/1000.);
|
||||||
status = pC_->transactController(command,reply);
|
status = pC_->transactController(axisNo_,command,reply);
|
||||||
|
setIntegerParam(pC_->motorStatusProblem_, false);
|
||||||
|
updateMsgTxtFromDriver("");
|
||||||
next_poll = -1;
|
next_poll = -1;
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -252,10 +290,14 @@ asynStatus EL734Axis::home(double minVelocity, double maxVelocity, double accele
|
|||||||
|
|
||||||
// status = sendAccelAndVelocity(acceleration, maxVelocity);
|
// status = sendAccelAndVelocity(acceleration, maxVelocity);
|
||||||
|
|
||||||
|
setIntegerParam(pC_->motorStatusProblem_, false);
|
||||||
|
updateMsgTxtFromDriver("");
|
||||||
|
errorReported = 0;
|
||||||
|
|
||||||
sprintf(command, "R %d", axisNo_);
|
sprintf(command, "R %d", axisNo_);
|
||||||
homing = 1;
|
homing = 1;
|
||||||
next_poll= -1;
|
next_poll= -1;
|
||||||
status = pC_->transactController(command,reply);
|
status = pC_->transactController(axisNo_,command,reply);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,6 +312,7 @@ asynStatus EL734Axis::moveVelocity(double minVelocity, double maxVelocity, doubl
|
|||||||
// functionName, minVelocity, maxVelocity, acceleration);
|
// functionName, minVelocity, maxVelocity, acceleration);
|
||||||
|
|
||||||
|
|
||||||
|
errorReported = 0;
|
||||||
if (maxVelocity > 0.) {
|
if (maxVelocity > 0.) {
|
||||||
/* This is a positive move */
|
/* This is a positive move */
|
||||||
sprintf(command, "FF %d", axisNo_);
|
sprintf(command, "FF %d", axisNo_);
|
||||||
@ -277,20 +320,25 @@ asynStatus EL734Axis::moveVelocity(double minVelocity, double maxVelocity, doubl
|
|||||||
/* This is a negative move */
|
/* This is a negative move */
|
||||||
sprintf(command, "FB %d", axisNo_);
|
sprintf(command, "FB %d", axisNo_);
|
||||||
}
|
}
|
||||||
status = pC_->transactController(command,reply);
|
status = pC_->transactController(axisNo_,command,reply);
|
||||||
|
setIntegerParam(pC_->motorStatusProblem_, false);
|
||||||
|
updateMsgTxtFromDriver("");
|
||||||
next_poll = -1;
|
next_poll = -1;
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus EL734Axis::stop(double acceleration )
|
asynStatus EL734Axis::stop(double acceleration )
|
||||||
{
|
{
|
||||||
asynStatus status;
|
asynStatus status = asynSuccess;
|
||||||
//static const char *functionName = "EL734Axis::stop";
|
//static const char *functionName = "EL734Axis::stop";
|
||||||
char command[COMLEN], reply[COMLEN];
|
char command[COMLEN], reply[COMLEN];
|
||||||
|
|
||||||
sprintf(command, "S %d", axisNo_);
|
if(errorReported == 0){
|
||||||
status = pC_->transactController(command,reply);
|
sprintf(command, "S %d", axisNo_);
|
||||||
errlogPrintf("Sent STOP on Axis %d\n", axisNo_);
|
status = pC_->transactController(axisNo_,command,reply);
|
||||||
|
errlogPrintf("Sent STOP on Axis %d\n", axisNo_);
|
||||||
|
updateMsgTxtFromDriver("Axis interrupted");
|
||||||
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -301,8 +349,8 @@ asynStatus EL734Axis::setPosition(double position)
|
|||||||
//static const char *functionName = "EL734Axis::setPosition";
|
//static const char *functionName = "EL734Axis::setPosition";
|
||||||
char command[COMLEN], reply[COMLEN];
|
char command[COMLEN], reply[COMLEN];
|
||||||
|
|
||||||
sprintf(command, "P %d %f", axisNo_, position/1000.);
|
sprintf(command, "U %d %f", axisNo_, position/1000.);
|
||||||
status = pC_->transactController(command,reply);
|
status = pC_->transactController(axisNo_,command,reply);
|
||||||
next_poll = -1;
|
next_poll = -1;
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
@ -328,10 +376,9 @@ asynStatus EL734Axis::setClosedLoop(bool closedLoop)
|
|||||||
* \param[out] moving A flag that is set indicating that the axis is moving (true) or done (false). */
|
* \param[out] moving A flag that is set indicating that the axis is moving (true) or done (false). */
|
||||||
asynStatus EL734Axis::poll(bool *moving)
|
asynStatus EL734Axis::poll(bool *moving)
|
||||||
{
|
{
|
||||||
int msr;
|
int msr, count;
|
||||||
asynStatus comStatus;
|
asynStatus comStatus = asynSuccess;
|
||||||
char command[COMLEN], reply[COMLEN];
|
char command[COMLEN], reply[COMLEN], errTxt[256];
|
||||||
|
|
||||||
|
|
||||||
// protect against excessive polling
|
// protect against excessive polling
|
||||||
if(time(NULL) < next_poll){
|
if(time(NULL) < next_poll){
|
||||||
@ -340,71 +387,121 @@ asynStatus EL734Axis::poll(bool *moving)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read the current motor position
|
// Read the current motor position
|
||||||
|
setIntegerParam(pC_->motorStatusProblem_,false);
|
||||||
sprintf(command,"u %d", axisNo_);
|
sprintf(command,"u %d", axisNo_);
|
||||||
comStatus = pC_->transactController(command,reply);
|
comStatus = pC_->transactController(axisNo_,command,reply);
|
||||||
if(comStatus) goto skip;
|
if(comStatus == asynError){
|
||||||
|
setIntegerParam(pC_->motorStatusProblem_,true);
|
||||||
|
goto skip;
|
||||||
|
}
|
||||||
if(strstr(reply,"*ES") != NULL){
|
if(strstr(reply,"*ES") != NULL){
|
||||||
*moving = false;
|
*moving = false;
|
||||||
setIntegerParam(pC_->motorStatusDone_, true);
|
setIntegerParam(pC_->motorStatusDone_, true);
|
||||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||||
|
errorReported = 1;
|
||||||
|
updateMsgTxtFromDriver("Emergency Stop Engaged");
|
||||||
|
comStatus = asynError;
|
||||||
goto skip;
|
goto skip;
|
||||||
} else if(strstr(reply,"?BSY") != NULL){
|
} else if(strstr(reply,"?BSY") != NULL){
|
||||||
*moving = true;
|
*moving = true;
|
||||||
setIntegerParam(pC_->motorStatusDone_, false);
|
setIntegerParam(pC_->motorStatusDone_, false);
|
||||||
goto skip;
|
goto skip;
|
||||||
}
|
}
|
||||||
sscanf(reply,"%lf", &position);
|
count = sscanf(reply,"%lf", &position);
|
||||||
//errlogPrintf("Axis %d, reply %s, position %lf\n", axisNo_, reply, position);
|
if(count != 1) {
|
||||||
setDoubleParam(pC_->motorPosition_, position*1000);
|
if(!homing) {
|
||||||
//setDoubleParam(pC_->motorEncoderPosition_, position);
|
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 {
|
||||||
|
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
|
// Read the moving status of this motor
|
||||||
sprintf(command,"msr %d",axisNo_);
|
sprintf(command,"msr %d",axisNo_);
|
||||||
comStatus = pC_->transactController(command,reply);
|
comStatus = pC_->transactController(axisNo_,command,reply);
|
||||||
if(comStatus) goto skip;
|
if(comStatus == asynError){
|
||||||
|
setIntegerParam(pC_->motorStatusProblem_,true);
|
||||||
|
goto skip;
|
||||||
|
}
|
||||||
sscanf(reply,"%x",&msr);
|
sscanf(reply,"%x",&msr);
|
||||||
// errlogPrintf("Axis %d, reply %s, msr %d, position = %lf\n",
|
|
||||||
// axisNo_, reply, msr, position);
|
//errlogPrintf("Axis %d, reply %s, msr %d, oredmsr = %d, position = %lf\n",
|
||||||
|
// axisNo_, reply, msr, oredMSR, position);
|
||||||
|
|
||||||
oredMSR |= msr;
|
oredMSR |= msr;
|
||||||
if( (msr & 0x1) == 0){
|
if( (msr & 0x1) == 0){
|
||||||
// done: check for trouble
|
// done: check for trouble
|
||||||
//errlogPrintf("Axis %d finished\n", axisNo_);
|
//errlogPrintf("Axis %d finished\n", axisNo_);
|
||||||
|
*moving = false;
|
||||||
|
setIntegerParam(pC_->motorStatusDone_, true);
|
||||||
|
|
||||||
next_poll = time(NULL)+IDLEPOLL;
|
next_poll = time(NULL)+IDLEPOLL;
|
||||||
if(oredMSR & 0x10){
|
if(oredMSR & 0x10){
|
||||||
setIntegerParam(pC_->motorStatusLowLimit_, true);
|
setIntegerParam(pC_->motorStatusLowLimit_, true);
|
||||||
|
updateMsgTxtFromDriver("Lower Limit Hit");
|
||||||
|
errorReported = 1;
|
||||||
|
comStatus = asynError;
|
||||||
|
goto skip;
|
||||||
} else {
|
} else {
|
||||||
setIntegerParam(pC_->motorStatusLowLimit_, false);
|
setIntegerParam(pC_->motorStatusLowLimit_, false);
|
||||||
}
|
}
|
||||||
if(oredMSR & 0x20){
|
if(oredMSR & 0x20){
|
||||||
setIntegerParam(pC_->motorStatusHighLimit_, true);
|
setIntegerParam(pC_->motorStatusHighLimit_, true);
|
||||||
|
updateMsgTxtFromDriver("Upper Limit Hit");
|
||||||
|
errorReported = 1;
|
||||||
|
comStatus = asynError;
|
||||||
|
goto skip;
|
||||||
} else {
|
} else {
|
||||||
setIntegerParam(pC_->motorStatusHighLimit_, false);
|
setIntegerParam(pC_->motorStatusHighLimit_, false);
|
||||||
}
|
}
|
||||||
if(homing){
|
if(homing){
|
||||||
setIntegerParam(pC_->motorStatusAtHome_, true);
|
setIntegerParam(pC_->motorStatusAtHome_, true);
|
||||||
}
|
}
|
||||||
setIntegerParam(pC_->motorStatusProblem_, false);
|
if(oredMSR & 0x1000){
|
||||||
if(oredMSR &0x1000){
|
|
||||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||||
|
// errlogPrintf("Detected air cushion error on %d", axisNo_);
|
||||||
errlogSevPrintf(errlogMajor, "Air cushion problem on %d", axisNo_);
|
errlogSevPrintf(errlogMajor, "Air cushion problem on %d", axisNo_);
|
||||||
|
updateMsgTxtFromDriver("Air cushion error");
|
||||||
|
errorReported = 1;
|
||||||
|
comStatus = asynError;
|
||||||
|
goto skip;
|
||||||
}
|
}
|
||||||
if(oredMSR &0x80){
|
if(oredMSR & 0x100){
|
||||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||||
errlogSevPrintf(errlogMajor, "Positioning fault at %d", axisNo_);
|
errlogSevPrintf(errlogMajor, "Run failure at %d", axisNo_);
|
||||||
|
updateMsgTxtFromDriver("Run failure");
|
||||||
|
comStatus = asynError;
|
||||||
|
errorReported = 1;
|
||||||
|
goto skip;
|
||||||
}
|
}
|
||||||
*moving = false;
|
if(oredMSR & 0x400){
|
||||||
setIntegerParam(pC_->motorStatusDone_, true);
|
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||||
} else {
|
errlogSevPrintf(errlogMajor, "Positioning failure at %d", axisNo_);
|
||||||
|
updateMsgTxtFromDriver("Positioning failure");
|
||||||
|
comStatus = asynError;
|
||||||
|
errorReported = 1;
|
||||||
|
goto skip;
|
||||||
|
}
|
||||||
|
if(oredMSR & 0x200 || oredMSR & 0x80) {
|
||||||
|
errlogSevPrintf(errlogMinor, "Positioning fault at %d", axisNo_);
|
||||||
|
}
|
||||||
|
setIntegerParam(pC_->motorStatusProblem_, false);
|
||||||
|
} else {
|
||||||
*moving = true;
|
*moving = true;
|
||||||
next_poll = -1;
|
next_poll = -1;
|
||||||
setIntegerParam(pC_->motorStatusDone_, false);
|
setIntegerParam(pC_->motorStatusDone_, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
skip:
|
skip:
|
||||||
setIntegerParam(pC_->motorStatusProblem_, comStatus ? 1:0);
|
|
||||||
callParamCallbacks();
|
callParamCallbacks();
|
||||||
return comStatus ? asynError : asynSuccess;
|
return comStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Code for iocsh registration */
|
/** Code for iocsh registration */
|
||||||
|
@ -7,13 +7,13 @@ February 2013
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "asynMotorController.h"
|
#include "SINQController.h"
|
||||||
#include "asynMotorAxis.h"
|
#include "SINQAxis.h"
|
||||||
|
|
||||||
#define MAX_EL734_AXES 12
|
#define MAX_EL734_AXES 12
|
||||||
#define COMLEN 80
|
#define COMLEN 80
|
||||||
|
|
||||||
class EL734Axis : public asynMotorAxis
|
class EL734Axis : public SINQAxis
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/* These are the methods we override from the base class */
|
/* These are the methods we override from the base class */
|
||||||
@ -34,11 +34,12 @@ private:
|
|||||||
double position;
|
double position;
|
||||||
int homing;
|
int homing;
|
||||||
time_t next_poll;
|
time_t next_poll;
|
||||||
|
int errorReported;
|
||||||
|
|
||||||
friend class EL734Controller;
|
friend class EL734Controller;
|
||||||
};
|
};
|
||||||
|
|
||||||
class EL734Controller : public asynMotorController {
|
class EL734Controller : public SINQController {
|
||||||
public:
|
public:
|
||||||
EL734Controller(const char *portName, const char *EL734PortName, int numAxes);
|
EL734Controller(const char *portName, const char *EL734PortName, int numAxes);
|
||||||
|
|
||||||
@ -50,7 +51,7 @@ friend class EL734Axis;
|
|||||||
private:
|
private:
|
||||||
asynUser *pasynUserController_;
|
asynUser *pasynUserController_;
|
||||||
|
|
||||||
asynStatus transactController(char command[COMLEN], char reply[COMLEN]);
|
asynStatus transactController(int axis, char command[COMLEN], char reply[COMLEN]);
|
||||||
|
|
||||||
void switchRemote();
|
void switchRemote();
|
||||||
|
|
||||||
|
678
sinqEPICSApp/src/EuroMoveDriver.cpp
Normal file
678
sinqEPICSApp/src/EuroMoveDriver.cpp
Normal file
@ -0,0 +1,678 @@
|
|||||||
|
/*
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** 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);
|
||||||
|
}
|
72
sinqEPICSApp/src/EuroMoveDriver.h
Normal file
72
sinqEPICSApp/src/EuroMoveDriver.h
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
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]);
|
||||||
|
|
||||||
|
};
|
@ -17,17 +17,18 @@ sinqEPICS_DBD += base.dbd
|
|||||||
|
|
||||||
# Include dbd files from all support applications:
|
# Include dbd files from all support applications:
|
||||||
sinqEPICS_DBD += sinq.dbd
|
sinqEPICS_DBD += sinq.dbd
|
||||||
sinqEPICS_DBD += pmacAsynIPPort.dbd pmacAsynMotorPort.dbd
|
#sinqEPICS_DBD += pmacAsynIPPort.dbd pmacAsynMotorPort.dbd
|
||||||
|
|
||||||
# Add all the support libraries needed by this IOC
|
# Add all the support libraries needed by this IOC
|
||||||
sinqEPICS_LIBS += motor asyn std anc350 anc350AsynMotor stream busy
|
sinqEPICS_LIBS += motor asyn busy synAppsStd streamdevice pcre
|
||||||
|
|
||||||
# sinqEPICS_registerRecordDeviceDriver.cpp derives from sinqEPICS.dbd
|
# sinqEPICS_registerRecordDeviceDriver.cpp derives from sinqEPICS.dbd
|
||||||
sinqEPICS_SRCS += sinqEPICS_registerRecordDeviceDriver.cpp
|
sinqEPICS_SRCS += sinqEPICS_registerRecordDeviceDriver.cpp
|
||||||
sinqEPICS_SRCS += EL734Driver.cpp devScalerEL737.c pmacAsynIPPort.c
|
sinqEPICS_SRCS += EL734Driver.cpp devScalerEL737.c pmacAsynIPPort.c SINQAxis.cpp SINQController.cpp
|
||||||
sinqEPICS_SRCS += pmacController.cpp pmacAxis.cpp
|
sinqEPICS_SRCS += pmacController.cpp pmacAxis.cpp
|
||||||
sinqEPICS_SRCS += NanotecDriver.cpp stptok.cpp
|
sinqEPICS_SRCS += NanotecDriver.cpp stptok.cpp
|
||||||
sinqEPICS_SRCS += PhytronDriver.cpp
|
sinqEPICS_SRCS += PhytronDriver.cpp
|
||||||
|
sinqEPICS_SRCS += EuroMoveDriver.cpp
|
||||||
|
|
||||||
|
|
||||||
# Build the main IOC entry point on workstation OSs.
|
# Build the main IOC entry point on workstation OSs.
|
||||||
|
@ -14,6 +14,9 @@ list to the motor controller constructor.
|
|||||||
Mark Koennecke
|
Mark Koennecke
|
||||||
July 2015
|
July 2015
|
||||||
|
|
||||||
|
Modified to use the MsgTxt field for SINQ
|
||||||
|
|
||||||
|
Mark Koennecke, January 2019
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@ -43,12 +46,7 @@ July 2015
|
|||||||
* \param[in] NanotecPortName The name of the drvAsynSerialPort that was created previously to connect to the Nanotec controller
|
* \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)
|
NanotecController::NanotecController(const char *portName, const char *NanotecPortName, int motCount, const char *bus)
|
||||||
: asynMotorController(portName, motCount+1, 0,
|
: SINQController(portName, NanotecPortName, motCount+1)
|
||||||
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;
|
int axis, busAddress;
|
||||||
asynStatus status;
|
asynStatus status;
|
||||||
@ -136,7 +134,7 @@ NanotecAxis* NanotecController::getAxis(int axisNo)
|
|||||||
* Initializes register numbers, etc.
|
* Initializes register numbers, etc.
|
||||||
*/
|
*/
|
||||||
NanotecAxis::NanotecAxis(NanotecController *pC, int axisNo, int busAddress)
|
NanotecAxis::NanotecAxis(NanotecController *pC, int axisNo, int busAddress)
|
||||||
: asynMotorAxis(pC, axisNo),
|
: SINQAxis(pC, axisNo),
|
||||||
pC_(pC)
|
pC_(pC)
|
||||||
{
|
{
|
||||||
this->busAddress = busAddress;
|
this->busAddress = busAddress;
|
||||||
@ -162,17 +160,21 @@ void NanotecAxis::report(FILE *fp, int level)
|
|||||||
//asynMotorAxis::report(fp, level);
|
//asynMotorAxis::report(fp, level);
|
||||||
}
|
}
|
||||||
|
|
||||||
asynStatus NanotecController::transactController(char command[COMLEN], char reply[COMLEN])
|
asynStatus NanotecController::transactController(int axisNo, char command[COMLEN], char reply[COMLEN])
|
||||||
{
|
{
|
||||||
asynStatus status;
|
asynStatus status;
|
||||||
size_t in, out;
|
size_t in, out;
|
||||||
int reason;
|
int reason;
|
||||||
|
SINQAxis *axis = getAxis(axisNo);
|
||||||
|
|
||||||
pasynOctetSyncIO->flush(pasynUserController_);
|
pasynOctetSyncIO->flush(pasynUserController_);
|
||||||
|
|
||||||
status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
|
status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
|
||||||
reply,COMLEN, 1.,&out,&in,&reason);
|
reply,COMLEN, 1.,&out,&in,&reason);
|
||||||
if(status != asynSuccess){
|
if(status != asynSuccess){
|
||||||
|
if(axis != NULL){
|
||||||
|
axis->updateMsgTxtFromDriver("Lost connection to motor controller");
|
||||||
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,6 +202,8 @@ asynStatus NanotecAxis::move(double position, int relative, double minVelocity,
|
|||||||
size_t in, out;
|
size_t in, out;
|
||||||
int reason;
|
int reason;
|
||||||
|
|
||||||
|
updateMsgTxtFromDriver("");
|
||||||
|
|
||||||
// status = sendAccelAndVelocity(acceleration, maxVelocity);
|
// status = sendAccelAndVelocity(acceleration, maxVelocity);
|
||||||
|
|
||||||
if (relative) {
|
if (relative) {
|
||||||
@ -215,7 +219,7 @@ asynStatus NanotecAxis::move(double position, int relative, double minVelocity,
|
|||||||
set mode
|
set mode
|
||||||
*/
|
*/
|
||||||
snprintf(command,sizeof(command),"#%dp2",busAddress);
|
snprintf(command,sizeof(command),"#%dp2",busAddress);
|
||||||
status = pC_->transactController(command,reply);
|
status = pC_->transactController(axisNo_,command,reply);
|
||||||
if(status != asynSuccess){
|
if(status != asynSuccess){
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -224,7 +228,7 @@ asynStatus NanotecAxis::move(double position, int relative, double minVelocity,
|
|||||||
set target
|
set target
|
||||||
*/
|
*/
|
||||||
snprintf(command,sizeof(command),"#%ds%d",busAddress, (int)position);
|
snprintf(command,sizeof(command),"#%ds%d",busAddress, (int)position);
|
||||||
status = pC_->transactController(command,reply);
|
status = pC_->transactController(axisNo_,command,reply);
|
||||||
if(status != asynSuccess){
|
if(status != asynSuccess){
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -233,7 +237,7 @@ asynStatus NanotecAxis::move(double position, int relative, double minVelocity,
|
|||||||
and start..
|
and start..
|
||||||
*/
|
*/
|
||||||
snprintf(command,sizeof(command),"#%dA",busAddress);
|
snprintf(command,sizeof(command),"#%dA",busAddress);
|
||||||
status = pC_->transactController(command,reply);
|
status = pC_->transactController(axisNo_,command,reply);
|
||||||
if(status != asynSuccess){
|
if(status != asynSuccess){
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -250,11 +254,13 @@ asynStatus NanotecAxis::home(double minVelocity, double maxVelocity, double acce
|
|||||||
|
|
||||||
setIntegerParam(pC_->motorStatusAtHome_, false);
|
setIntegerParam(pC_->motorStatusAtHome_, false);
|
||||||
|
|
||||||
|
updateMsgTxtFromDriver("");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
reset positioning errors
|
reset positioning errors
|
||||||
*/
|
*/
|
||||||
snprintf(command,sizeof(command),"#%dD",busAddress);
|
snprintf(command,sizeof(command),"#%dD",busAddress);
|
||||||
status = pC_->transactController(command,reply);
|
status = pC_->transactController(axisNo_,command,reply);
|
||||||
if(status != asynSuccess){
|
if(status != asynSuccess){
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -263,7 +269,7 @@ asynStatus NanotecAxis::home(double minVelocity, double maxVelocity, double acce
|
|||||||
set mode
|
set mode
|
||||||
*/
|
*/
|
||||||
snprintf(command,sizeof(command),"#%dp4",busAddress);
|
snprintf(command,sizeof(command),"#%dp4",busAddress);
|
||||||
status = pC_->transactController(command,reply);
|
status = pC_->transactController(axisNo_,command,reply);
|
||||||
if(status != asynSuccess){
|
if(status != asynSuccess){
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -273,7 +279,7 @@ asynStatus NanotecAxis::home(double minVelocity, double maxVelocity, double acce
|
|||||||
set direction
|
set direction
|
||||||
*/
|
*/
|
||||||
snprintf(command,sizeof(command),"#%dd0",busAddress);
|
snprintf(command,sizeof(command),"#%dd0",busAddress);
|
||||||
status = pC_->transactController(command,reply);
|
status = pC_->transactController(axisNo_,command,reply);
|
||||||
if(status != asynSuccess){
|
if(status != asynSuccess){
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -283,7 +289,7 @@ asynStatus NanotecAxis::home(double minVelocity, double maxVelocity, double acce
|
|||||||
and start..
|
and start..
|
||||||
*/
|
*/
|
||||||
snprintf(command,sizeof(command),"#%dA",busAddress);
|
snprintf(command,sizeof(command),"#%dA",busAddress);
|
||||||
status = pC_->transactController(command,reply);
|
status = pC_->transactController(axisNo_,command,reply);
|
||||||
if(status != asynSuccess){
|
if(status != asynSuccess){
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -304,6 +310,7 @@ asynStatus NanotecAxis::moveVelocity(double minVelocity, double maxVelocity, dou
|
|||||||
// "%s: minVelocity=%f, maxVelocity=%f, acceleration=%f\n",
|
// "%s: minVelocity=%f, maxVelocity=%f, acceleration=%f\n",
|
||||||
// functionName, minVelocity, maxVelocity, acceleration);
|
// functionName, minVelocity, maxVelocity, acceleration);
|
||||||
|
|
||||||
|
updateMsgTxtFromDriver("");
|
||||||
|
|
||||||
|
|
||||||
if (maxVelocity > 0.) {
|
if (maxVelocity > 0.) {
|
||||||
@ -326,7 +333,7 @@ asynStatus NanotecAxis::stop(double acceleration )
|
|||||||
char command[COMLEN], reply[COMLEN];
|
char command[COMLEN], reply[COMLEN];
|
||||||
|
|
||||||
sprintf(command, "#%dS1", busAddress);
|
sprintf(command, "#%dS1", busAddress);
|
||||||
status = pC_->transactController(command,reply);
|
status = pC_->transactController(axisNo_,command,reply);
|
||||||
errlogPrintf("Sent STOP on Axis %d\n", axisNo_);
|
errlogPrintf("Sent STOP on Axis %d\n", axisNo_);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
@ -338,8 +345,10 @@ asynStatus NanotecAxis::setPosition(double position)
|
|||||||
//static const char *functionName = "NanotecAxis::setPosition";
|
//static const char *functionName = "NanotecAxis::setPosition";
|
||||||
char command[COMLEN], reply[COMLEN];
|
char command[COMLEN], reply[COMLEN];
|
||||||
|
|
||||||
|
updateMsgTxtFromDriver("");
|
||||||
|
|
||||||
sprintf(command, "#%dD%d", busAddress, (int)position);
|
sprintf(command, "#%dD%d", busAddress, (int)position);
|
||||||
status = pC_->transactController(command,reply);
|
status = pC_->transactController(axisNo_,command,reply);
|
||||||
next_poll = -1;
|
next_poll = -1;
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
@ -380,28 +389,28 @@ asynStatus NanotecAxis::poll(bool *moving)
|
|||||||
|
|
||||||
// Read the current motor position
|
// Read the current motor position
|
||||||
sprintf(command,"#%dC", busAddress);
|
sprintf(command,"#%dC", busAddress);
|
||||||
comStatus = pC_->transactController(command,reply);
|
comStatus = pC_->transactController(axisNo_,command,reply);
|
||||||
if(comStatus) goto skip;
|
if(comStatus) goto skip;
|
||||||
|
|
||||||
pPtr = strchr(reply,'C');
|
pPtr = strchr(reply,'C');
|
||||||
pPtr++;
|
pPtr++;
|
||||||
posVal = atoi(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_->motorPosition_, (double)posVal);
|
||||||
//setDoubleParam(pC_->motorEncoderPosition_, position);
|
//setDoubleParam(pC_->motorEncoderPosition_, position);
|
||||||
|
|
||||||
|
|
||||||
// Read the moving status of this motor
|
// Read the moving status of this motor
|
||||||
sprintf(command,"#%d$",busAddress);
|
sprintf(command,"#%d$",busAddress);
|
||||||
comStatus = pC_->transactController(command,reply);
|
comStatus = pC_->transactController(axisNo_,command,reply);
|
||||||
if(comStatus) goto skip;
|
if(comStatus) goto skip;
|
||||||
|
|
||||||
pPtr = strchr(reply,'$');
|
pPtr = strchr(reply,'$');
|
||||||
pPtr++;
|
pPtr++;
|
||||||
statVal = atoi(pPtr);
|
statVal = atoi(pPtr);
|
||||||
errlogPrintf("Axis %d, reply %s, statVal = %d\n",
|
//errlogPrintf("Axis %d, reply %s, statVal = %d\n",
|
||||||
axisNo_, reply, statVal);
|
// axisNo_, reply, statVal);
|
||||||
|
|
||||||
setIntegerParam(pC_->motorStatusDone_, false);
|
setIntegerParam(pC_->motorStatusDone_, false);
|
||||||
*moving = true;
|
*moving = true;
|
||||||
@ -438,10 +447,13 @@ asynStatus NanotecAxis::poll(bool *moving)
|
|||||||
setIntegerParam(pC_->motorStatusDone_, true);
|
setIntegerParam(pC_->motorStatusDone_, true);
|
||||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||||
errlogSevPrintf(errlogMajor, "Limit or other positioning problem at %d", axisNo_);
|
errlogSevPrintf(errlogMajor, "Limit or other positioning problem at %d", axisNo_);
|
||||||
|
updateMsgTxtFromDriver("Positioning problem");
|
||||||
if(ABS(posVal - lowLim) < ABS(posVal - highLim)){
|
if(ABS(posVal - lowLim) < ABS(posVal - highLim)){
|
||||||
setIntegerParam(pC_->motorStatusLowLimit_, true);
|
setIntegerParam(pC_->motorStatusLowLimit_, true);
|
||||||
|
updateMsgTxtFromDriver("Low Limit Hit");
|
||||||
} else {
|
} else {
|
||||||
setIntegerParam(pC_->motorStatusHighLimit_, true);
|
setIntegerParam(pC_->motorStatusHighLimit_, true);
|
||||||
|
updateMsgTxtFromDriver("High Limit Hit");
|
||||||
}
|
}
|
||||||
*moving = false;
|
*moving = false;
|
||||||
}
|
}
|
||||||
|
@ -5,15 +5,18 @@ USAGE... Motor driver support for the Nanotec SMCI controller.
|
|||||||
Mark Koennecke
|
Mark Koennecke
|
||||||
July 2015
|
July 2015
|
||||||
|
|
||||||
|
Modified to use the MsgTxt field for SINQ
|
||||||
|
|
||||||
|
Mark Koennecke, January 2019
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "asynMotorController.h"
|
#include "SINQController.h"
|
||||||
#include "asynMotorAxis.h"
|
#include "SINQAxis.h"
|
||||||
|
|
||||||
#define COMLEN 80
|
#define COMLEN 80
|
||||||
#define MAXMOT 99
|
#define MAXMOT 99
|
||||||
|
|
||||||
class NanotecAxis : public asynMotorAxis
|
class NanotecAxis : public SINQAxis
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/* These are the methods we override from the base class */
|
/* These are the methods we override from the base class */
|
||||||
@ -38,7 +41,7 @@ private:
|
|||||||
friend class NanotecController;
|
friend class NanotecController;
|
||||||
};
|
};
|
||||||
|
|
||||||
class NanotecController : public asynMotorController {
|
class NanotecController : public SINQController {
|
||||||
public:
|
public:
|
||||||
NanotecController(const char *portName, const char *NanotecPortName, int numMot, const char *busAddresses);
|
NanotecController(const char *portName, const char *NanotecPortName, int numMot, const char *busAddresses);
|
||||||
|
|
||||||
@ -50,7 +53,7 @@ friend class NanotecAxis;
|
|||||||
private:
|
private:
|
||||||
asynUser *pasynUserController_;
|
asynUser *pasynUserController_;
|
||||||
|
|
||||||
asynStatus transactController(char command[COMLEN], char reply[COMLEN]);
|
asynStatus transactController(int axisNo, char command[COMLEN], char reply[COMLEN]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,6 +23,12 @@ Though this driver has been written in 2016, the MCC-2 version used is probably
|
|||||||
Mark Koennecke
|
Mark Koennecke
|
||||||
September 2016
|
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
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@ -49,19 +55,16 @@ September 2016
|
|||||||
* \param[in] PhytronPortName The name of the drvAsynSerialPort that was created previously to connect to the Phytron controller
|
* \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
|
* \param[in] numAxes The number of axes that this controller supports
|
||||||
*/
|
*/
|
||||||
PhytronController::PhytronController(const char *portName, const char *PhytronPortName, int encX, int encY)
|
PhytronController::PhytronController(const char *portName, const char *PhytronPortName, const char *sel ,
|
||||||
: asynMotorController(portName, 3, 0,
|
int encX, int encY)
|
||||||
0, // No additional interfaces beyond those in base class
|
: SINQController(portName, PhytronPortName,2)
|
||||||
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;
|
asynStatus status;
|
||||||
PhytronAxis *pAxis;
|
|
||||||
static const char *functionName = "PhytronController::PhytronController";
|
static const char *functionName = "PhytronController::PhytronController";
|
||||||
char etx[2];
|
char etx[2];
|
||||||
|
|
||||||
|
selector = strdup(sel);
|
||||||
|
|
||||||
/* Connect to Phytron controller */
|
/* Connect to Phytron controller */
|
||||||
status = pasynOctetSyncIO->connect(PhytronPortName, 0, &pasynUserController_, NULL);
|
status = pasynOctetSyncIO->connect(PhytronPortName, 0, &pasynUserController_, NULL);
|
||||||
if (status) {
|
if (status) {
|
||||||
@ -74,8 +77,8 @@ PhytronController::PhytronController(const char *portName, const char *PhytronPo
|
|||||||
pasynOctetSyncIO->setOutputEos(pasynUserController_,etx,strlen(etx));
|
pasynOctetSyncIO->setOutputEos(pasynUserController_,etx,strlen(etx));
|
||||||
pasynOctetSyncIO->setInputEos(pasynUserController_,etx,strlen(etx));
|
pasynOctetSyncIO->setInputEos(pasynUserController_,etx,strlen(etx));
|
||||||
|
|
||||||
pAxis = new PhytronAxis(this, 1, encX);
|
new PhytronAxis(this, 1, encX);
|
||||||
pAxis = new PhytronAxis(this, 2, encY);
|
new PhytronAxis(this, 2, encY);
|
||||||
|
|
||||||
startPoller(1000./1000., IDLEPOLL, 2);
|
startPoller(1000./1000., IDLEPOLL, 2);
|
||||||
}
|
}
|
||||||
@ -87,11 +90,10 @@ PhytronController::PhytronController(const char *portName, const char *PhytronPo
|
|||||||
* \param[in] PhytronPortName The name of the drvAsynIPPPort that was created previously to connect to the Phytron controller
|
* \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
|
* \param[in] numAxes The number of axes that this controller supports
|
||||||
*/
|
*/
|
||||||
extern "C" int PhytronCreateController(const char *portName, const char *PhytronPortName, int encX, int encY)
|
extern "C" int PhytronCreateController(const char *portName, const char *PhytronPortName, const char *selector,
|
||||||
|
int encX, int encY)
|
||||||
{
|
{
|
||||||
PhytronController *pPhytronController
|
new PhytronController(portName, PhytronPortName,selector, encX, encY);
|
||||||
= new PhytronController(portName, PhytronPortName, encX, encY);
|
|
||||||
pPhytronController = NULL;
|
|
||||||
return(asynSuccess);
|
return(asynSuccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,12 +136,14 @@ PhytronAxis* PhytronController::getAxis(int axisNo)
|
|||||||
* \param[out] reply The controllers reply
|
* \param[out] reply The controllers reply
|
||||||
*/
|
*/
|
||||||
|
|
||||||
asynStatus PhytronController::transactController(char command[COMLEN], char reply[COMLEN])
|
asynStatus PhytronController::transactController(int axisNo,char command[COMLEN], char reply[COMLEN])
|
||||||
{
|
{
|
||||||
asynStatus status;
|
asynStatus status;
|
||||||
size_t in, out;
|
size_t in, out;
|
||||||
int reason;
|
int reason;
|
||||||
char myReply[COMLEN+10], myCommand[COMLEN+10], *pPtr;
|
char myReply[COMLEN+10], myCommand[COMLEN+10], *pPtr;
|
||||||
|
SINQAxis *axis = getAxis(axisNo);
|
||||||
|
|
||||||
|
|
||||||
pasynOctetSyncIO->flush(pasynUserController_);
|
pasynOctetSyncIO->flush(pasynUserController_);
|
||||||
|
|
||||||
@ -155,6 +159,9 @@ asynStatus PhytronController::transactController(char command[COMLEN], char repl
|
|||||||
status = pasynOctetSyncIO->writeRead(pasynUserController_, myCommand, strlen(myCommand),
|
status = pasynOctetSyncIO->writeRead(pasynUserController_, myCommand, strlen(myCommand),
|
||||||
myReply,sizeof(myReply), 1.,&out,&in,&reason);
|
myReply,sizeof(myReply), 1.,&out,&in,&reason);
|
||||||
if(status != asynSuccess){
|
if(status != asynSuccess){
|
||||||
|
if(axis!= NULL){
|
||||||
|
axis->updateMsgTxtFromDriver("Lost connection to motor controller");
|
||||||
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,7 +183,7 @@ asynStatus PhytronController::transactController(char command[COMLEN], char repl
|
|||||||
I may need to replace the ETX. But I am not sure if asyn did
|
I may need to replace the ETX. But I am not sure if asyn did
|
||||||
not remove it for me.
|
not remove it for me.
|
||||||
*/
|
*/
|
||||||
strncat(reply,pPtr,sizeof(reply));
|
strncat(reply,pPtr,COMLEN-1);
|
||||||
|
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
@ -191,7 +198,7 @@ asynStatus PhytronController::transactController(char command[COMLEN], char repl
|
|||||||
* Initializes register numbers, etc.
|
* Initializes register numbers, etc.
|
||||||
*/
|
*/
|
||||||
PhytronAxis::PhytronAxis(PhytronController *pC, int axisNo, int enc)
|
PhytronAxis::PhytronAxis(PhytronController *pC, int axisNo, int enc)
|
||||||
: asynMotorAxis(pC, axisNo),
|
: SINQAxis(pC, axisNo),
|
||||||
pC_(pC)
|
pC_(pC)
|
||||||
{
|
{
|
||||||
encoder = enc;
|
encoder = enc;
|
||||||
@ -200,10 +207,20 @@ PhytronAxis::PhytronAxis(PhytronController *pC, int axisNo, int enc)
|
|||||||
} else {
|
} else {
|
||||||
phytronChar = 'Y';
|
phytronChar = 'Y';
|
||||||
}
|
}
|
||||||
|
haveBrake = 0;
|
||||||
|
brakeIO = -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
|
/** Reports on status of the axis
|
||||||
* \param[in] fp The file pointer on which report information will be written
|
* \param[in] fp The file pointer on which report information will be written
|
||||||
@ -229,15 +246,46 @@ asynStatus PhytronAxis::move(double position, int relative, double minVelocity,
|
|||||||
//static const char *functionName = "PhytronAxis::move";
|
//static const char *functionName = "PhytronAxis::move";
|
||||||
char command[COMLEN], reply[COMLEN];
|
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) {
|
if (relative) {
|
||||||
position += this->position;
|
position += this->position;
|
||||||
}
|
}
|
||||||
homing = 0;
|
homing = 0;
|
||||||
sprintf(command, "0%cA%f", phytronChar,position/1000.);
|
sprintf(command, "%s%cA%f", pC_->selector,phytronChar,position/1000.);
|
||||||
status = pC_->transactController(command,reply);
|
status = pC_->transactController(axisNo_,command,reply);
|
||||||
if(strstr(reply,"NACK") != NULL){
|
if(strstr(reply,"NACK") != NULL){
|
||||||
errlogSevPrintf(errlogMajor, "Drive command not acknowledged on %d", axisNo_);
|
errlogSevPrintf(errlogMajor, "Drive command not acknowledged on %d", axisNo_);
|
||||||
|
updateMsgTxtFromDriver("Drive command not acknowledged");
|
||||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||||
return asynError;
|
return asynError;
|
||||||
}
|
}
|
||||||
@ -251,13 +299,47 @@ asynStatus PhytronAxis::home(double minVelocity, double maxVelocity, double acce
|
|||||||
//static const char *functionName = "PhytronAxis::home";
|
//static const char *functionName = "PhytronAxis::home";
|
||||||
char command[COMLEN], reply[COMLEN];
|
char command[COMLEN], reply[COMLEN];
|
||||||
|
|
||||||
sprintf(command, "0%cO-",phytronChar);
|
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);
|
||||||
|
}
|
||||||
homing = 1;
|
homing = 1;
|
||||||
next_poll= -1;
|
next_poll= -1;
|
||||||
status = pC_->transactController(command,reply);
|
status = pC_->transactController(axisNo_,command,reply);
|
||||||
if(strstr(reply,"NACK") != NULL){
|
if(strstr(reply,"NACK") != NULL){
|
||||||
errlogSevPrintf(errlogMajor, "Home command not acknowledged on %d", axisNo_);
|
errlogSevPrintf(errlogMajor, "Home command not acknowledged on %d", axisNo_);
|
||||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||||
|
updateMsgTxtFromDriver("Home command not acknowledged");
|
||||||
return asynError;
|
return asynError;
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
@ -274,6 +356,7 @@ asynStatus PhytronAxis::moveVelocity(double minVelocity, double maxVelocity, dou
|
|||||||
// "%s: minVelocity=%f, maxVelocity=%f, acceleration=%f\n",
|
// "%s: minVelocity=%f, maxVelocity=%f, acceleration=%f\n",
|
||||||
// functionName, minVelocity, maxVelocity, acceleration);
|
// functionName, minVelocity, maxVelocity, acceleration);
|
||||||
|
|
||||||
|
updateMsgTxtFromDriver("");
|
||||||
|
|
||||||
|
|
||||||
if (maxVelocity > 0.) {
|
if (maxVelocity > 0.) {
|
||||||
@ -294,9 +377,10 @@ asynStatus PhytronAxis::stop(double acceleration )
|
|||||||
//static const char *functionName = "PhytronAxis::stop";
|
//static const char *functionName = "PhytronAxis::stop";
|
||||||
char command[COMLEN], reply[COMLEN];
|
char command[COMLEN], reply[COMLEN];
|
||||||
|
|
||||||
sprintf(command, "0%cSN", phytronChar);
|
sprintf(command, "%s%cSN", pC_->selector,phytronChar);
|
||||||
status = pC_->transactController(command,reply);
|
status = pC_->transactController(axisNo_,command,reply);
|
||||||
errlogPrintf("Sent STOP on Axis %d\n", axisNo_);
|
errlogPrintf("Sent STOP on Axis %d\n", axisNo_);
|
||||||
|
updateMsgTxtFromDriver("Axis interrupted");
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -307,10 +391,12 @@ asynStatus PhytronAxis::setPosition(double position)
|
|||||||
//static const char *functionName = "PhytronAxis::setPosition";
|
//static const char *functionName = "PhytronAxis::setPosition";
|
||||||
char command[COMLEN], reply[COMLEN];
|
char command[COMLEN], reply[COMLEN];
|
||||||
|
|
||||||
sprintf(command, "0%cP22S%f", phytronChar, position/1000.);
|
errlogPrintf("PhytronAxis::setPosition called with %lf\n", position);
|
||||||
status = pC_->transactController(command,reply);
|
|
||||||
sprintf(command, "0%cP20S%f", phytronChar, position/1000.);
|
sprintf(command, "%s%cP22S%f", pC_->selector,phytronChar, position/1000.);
|
||||||
status = pC_->transactController(command,reply);
|
status = pC_->transactController(axisNo_,command,reply);
|
||||||
|
sprintf(command, "%s%cP20S%f", pC_->selector,phytronChar, position/1000.);
|
||||||
|
status = pC_->transactController(axisNo_,command,reply);
|
||||||
next_poll = -1;
|
next_poll = -1;
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
@ -336,7 +422,7 @@ asynStatus PhytronAxis::setClosedLoop(bool closedLoop)
|
|||||||
* \param[out] moving A flag that is set indicating that the axis is moving (true) or done (false). */
|
* \param[out] moving A flag that is set indicating that the axis is moving (true) or done (false). */
|
||||||
asynStatus PhytronAxis::poll(bool *moving)
|
asynStatus PhytronAxis::poll(bool *moving)
|
||||||
{
|
{
|
||||||
asynStatus comStatus;
|
asynStatus comStatus = asynSuccess;
|
||||||
char command[COMLEN], reply[COMLEN];
|
char command[COMLEN], reply[COMLEN];
|
||||||
double lowlim;
|
double lowlim;
|
||||||
|
|
||||||
@ -347,19 +433,24 @@ asynStatus PhytronAxis::poll(bool *moving)
|
|||||||
return asynSuccess;
|
return asynSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setIntegerParam(pC_->motorStatusProblem_, false);
|
||||||
// Read the current motor position
|
// Read the current motor position
|
||||||
if(encoder) {
|
if(encoder) {
|
||||||
sprintf(command,"0%cP22R",phytronChar);
|
sprintf(command,"%s%cP22R",pC_->selector,phytronChar);
|
||||||
} else {
|
} else {
|
||||||
sprintf(command,"0%cP20R",phytronChar);
|
sprintf(command,"%s%cP20R",pC_->selector,phytronChar);
|
||||||
}
|
}
|
||||||
|
|
||||||
comStatus = pC_->transactController(command,reply);
|
comStatus = pC_->transactController(axisNo_,command,reply);
|
||||||
if(comStatus) goto skip;
|
if(comStatus == asynError) {
|
||||||
|
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||||
|
updateMsgTxtFromDriver("No connection to phytron controller");
|
||||||
|
goto skip;
|
||||||
|
}
|
||||||
if(strstr(reply,"NACK") != NULL){
|
if(strstr(reply,"NACK") != NULL){
|
||||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||||
errlogSevPrintf(errlogMajor, "Bad reply for position on %d", axisNo_);
|
errlogSevPrintf(errlogMajor, "Bad reply for position on %d", axisNo_);
|
||||||
|
updateMsgTxtFromDriver("Bad reply reading position");
|
||||||
goto skip;
|
goto skip;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -372,9 +463,13 @@ asynStatus PhytronAxis::poll(bool *moving)
|
|||||||
|
|
||||||
|
|
||||||
// Read the moving status of this motor
|
// Read the moving status of this motor
|
||||||
sprintf(command,"0%c=H",phytronChar);
|
sprintf(command,"%s%c=H",pC_->selector,phytronChar);
|
||||||
comStatus = pC_->transactController(command,reply);
|
comStatus = pC_->transactController(axisNo_,command,reply);
|
||||||
if(comStatus) goto skip;
|
if(comStatus == asynError){
|
||||||
|
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||||
|
updateMsgTxtFromDriver("No connection to phytron controller");
|
||||||
|
goto skip;
|
||||||
|
}
|
||||||
/* errlogPrintf("Axis %d, status reply %s, position %lf\n", axisNo_, reply, position); */
|
/* errlogPrintf("Axis %d, status reply %s, position %lf\n", axisNo_, reply, position); */
|
||||||
if(strstr(reply,"ACKN") != NULL){
|
if(strstr(reply,"ACKN") != NULL){
|
||||||
*moving = true;
|
*moving = true;
|
||||||
@ -384,23 +479,45 @@ asynStatus PhytronAxis::poll(bool *moving)
|
|||||||
*moving = false;
|
*moving = false;
|
||||||
next_poll = time(NULL)+IDLEPOLL;
|
next_poll = time(NULL)+IDLEPOLL;
|
||||||
setIntegerParam(pC_->motorStatusDone_, true);
|
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(!*moving) {
|
||||||
if(homing){
|
if(homing){
|
||||||
pC_->getDoubleParam(axisNo_,pC_->motorLowLimit_,&lowlim);
|
if(homing_direction) {
|
||||||
|
pC_->getDoubleParam(axisNo_,pC_->motorHighLimit_,&lowlim);
|
||||||
|
} else {
|
||||||
|
pC_->getDoubleParam(axisNo_,pC_->motorLowLimit_,&lowlim);
|
||||||
|
}
|
||||||
setPosition(lowlim);
|
setPosition(lowlim);
|
||||||
setIntegerParam(pC_->motorStatusAtHome_, true);
|
setIntegerParam(pC_->motorStatusAtHome_, true);
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
check limits and errors, upper
|
check limits and errors, upper
|
||||||
*/
|
*/
|
||||||
sprintf(command,"0%c=I+",phytronChar);
|
sprintf(command,"%s%c=I+",pC_->selector,phytronChar);
|
||||||
comStatus = pC_->transactController(command,reply);
|
comStatus = pC_->transactController(axisNo_,command,reply);
|
||||||
if(comStatus) goto skip;
|
if(comStatus == asynError) {
|
||||||
|
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||||
|
updateMsgTxtFromDriver("No connection to phytron controller");
|
||||||
|
goto skip;
|
||||||
|
}
|
||||||
if(strstr(reply,"ACKE") != NULL){
|
if(strstr(reply,"ACKE") != NULL){
|
||||||
setIntegerParam(pC_->motorStatusHighLimit_, true);
|
setIntegerParam(pC_->motorStatusHighLimit_, true);
|
||||||
|
updateMsgTxtFromDriver("Hit High Limit");
|
||||||
|
comStatus = asynError;
|
||||||
|
goto skip;
|
||||||
} else {
|
} else {
|
||||||
setIntegerParam(pC_->motorStatusHighLimit_, false);
|
setIntegerParam(pC_->motorStatusHighLimit_, false);
|
||||||
}
|
}
|
||||||
@ -408,11 +525,18 @@ asynStatus PhytronAxis::poll(bool *moving)
|
|||||||
/*
|
/*
|
||||||
lower limit
|
lower limit
|
||||||
*/
|
*/
|
||||||
sprintf(command,"0%c=I-",phytronChar);
|
sprintf(command,"%s%c=I-",pC_->selector,phytronChar);
|
||||||
comStatus = pC_->transactController(command,reply);
|
comStatus = pC_->transactController(axisNo_,command,reply);
|
||||||
if(comStatus) goto skip;
|
if(comStatus == asynError){
|
||||||
|
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||||
|
updateMsgTxtFromDriver("No connection to phytron controller");
|
||||||
|
goto skip;
|
||||||
|
}
|
||||||
if(strstr(reply,"ACKE") != NULL){
|
if(strstr(reply,"ACKE") != NULL){
|
||||||
setIntegerParam(pC_->motorStatusLowLimit_, true);
|
setIntegerParam(pC_->motorStatusLowLimit_, true);
|
||||||
|
updateMsgTxtFromDriver("Low Limit Hit");
|
||||||
|
comStatus = asynError;
|
||||||
|
goto skip;
|
||||||
} else {
|
} else {
|
||||||
setIntegerParam(pC_->motorStatusLowLimit_, false);
|
setIntegerParam(pC_->motorStatusLowLimit_, false);
|
||||||
}
|
}
|
||||||
@ -420,12 +544,19 @@ asynStatus PhytronAxis::poll(bool *moving)
|
|||||||
/*
|
/*
|
||||||
error
|
error
|
||||||
*/
|
*/
|
||||||
sprintf(command,"0%c=E",phytronChar);
|
sprintf(command,"%s%c=E",pC_->selector,phytronChar);
|
||||||
comStatus = pC_->transactController(command,reply);
|
comStatus = pC_->transactController(axisNo_,command,reply);
|
||||||
if(comStatus) goto skip;
|
if(comStatus == asynError) {
|
||||||
|
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||||
|
updateMsgTxtFromDriver("No connection to phytron controller");
|
||||||
|
goto skip;
|
||||||
|
}
|
||||||
if(strstr(reply,"ACKE") != NULL){
|
if(strstr(reply,"ACKE") != NULL){
|
||||||
setIntegerParam(pC_->motorStatusProblem_, true);
|
setIntegerParam(pC_->motorStatusProblem_, true);
|
||||||
errlogSevPrintf(errlogMajor, "Electronics on %d", axisNo_);
|
errlogSevPrintf(errlogMajor, "Electronics on %d", axisNo_);
|
||||||
|
updateMsgTxtFromDriver("Electronics error");
|
||||||
|
comStatus = asynError;
|
||||||
|
goto skip;
|
||||||
} else {
|
} else {
|
||||||
setIntegerParam(pC_->motorStatusProblem_, false);
|
setIntegerParam(pC_->motorStatusProblem_, false);
|
||||||
}
|
}
|
||||||
@ -434,29 +565,76 @@ asynStatus PhytronAxis::poll(bool *moving)
|
|||||||
|
|
||||||
|
|
||||||
skip:
|
skip:
|
||||||
setIntegerParam(pC_->motorStatusProblem_, comStatus ? 1:0);
|
|
||||||
callParamCallbacks();
|
callParamCallbacks();
|
||||||
return comStatus ? asynError : asynSuccess;
|
return comStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Code for iocsh registration */
|
/** Code for iocsh registration */
|
||||||
static const iocshArg PhytronCreateControllerArg0 = {"Port name", iocshArgString};
|
static const iocshArg PhytronCreateControllerArg0 = {"Port name", iocshArgString};
|
||||||
static const iocshArg PhytronCreateControllerArg1 = {"Phytron port name", iocshArgString};
|
static const iocshArg PhytronCreateControllerArg1 = {"Phytron port name", iocshArgString};
|
||||||
static const iocshArg PhytronCreateControllerArg2 = {"EnoderX", iocshArgInt};
|
static const iocshArg PhytronCreateControllerArg2 = {"Phytron Selector", iocshArgString};
|
||||||
static const iocshArg PhytronCreateControllerArg3 = {"EnoderY", iocshArgInt};
|
static const iocshArg PhytronCreateControllerArg3 = {"EncoderX", iocshArgInt};
|
||||||
|
static const iocshArg PhytronCreateControllerArg4 = {"EncoderY", iocshArgInt};
|
||||||
static const iocshArg * const PhytronCreateControllerArgs[] = {&PhytronCreateControllerArg0,
|
static const iocshArg * const PhytronCreateControllerArgs[] = {&PhytronCreateControllerArg0,
|
||||||
&PhytronCreateControllerArg1,
|
&PhytronCreateControllerArg1,
|
||||||
&PhytronCreateControllerArg2,
|
&PhytronCreateControllerArg2,
|
||||||
&PhytronCreateControllerArg3};
|
&PhytronCreateControllerArg3,
|
||||||
static const iocshFuncDef PhytronCreateControllerDef = {"PhytronCreateController", 4, PhytronCreateControllerArgs};
|
&PhytronCreateControllerArg4};
|
||||||
|
static const iocshFuncDef PhytronCreateControllerDef = {"PhytronCreateController", 5, PhytronCreateControllerArgs};
|
||||||
static void PhytronCreateContollerCallFunc(const iocshArgBuf *args)
|
static void PhytronCreateContollerCallFunc(const iocshArgBuf *args)
|
||||||
{
|
{
|
||||||
PhytronCreateController(args[0].sval, args[1].sval, args[2].ival,args[3].ival);
|
PhytronCreateController(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)
|
static void PhytronRegister(void)
|
||||||
{
|
{
|
||||||
iocshRegister(&PhytronCreateControllerDef, PhytronCreateContollerCallFunc);
|
iocshRegister(&PhytronCreateControllerDef, PhytronCreateContollerCallFunc);
|
||||||
|
iocshRegister(&phytronBrakeDef, phytronBrakeCallFunc);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -5,14 +5,19 @@ USAGE... Motor driver support for the Phytron MCC-2 motor controller.
|
|||||||
Mark Koennecke
|
Mark Koennecke
|
||||||
September 2016
|
September 2016
|
||||||
|
|
||||||
|
|
||||||
|
Updated to go through SINQAxis for -MsgTxt support
|
||||||
|
Added a selector to support multiple phytrons on a connection
|
||||||
|
|
||||||
|
Mark Koennecke, January 2019
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "asynMotorController.h"
|
#include "SINQController.h"
|
||||||
#include "asynMotorAxis.h"
|
#include "SINQAxis.h"
|
||||||
|
|
||||||
#define COMLEN 80
|
#define COMLEN 80
|
||||||
|
|
||||||
class PhytronAxis : public asynMotorAxis
|
class PhytronAxis : public SINQAxis
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/* These are the methods we override from the base class */
|
/* These are the methods we override from the base class */
|
||||||
@ -25,6 +30,7 @@ public:
|
|||||||
asynStatus poll(bool *moving);
|
asynStatus poll(bool *moving);
|
||||||
asynStatus setPosition(double position);
|
asynStatus setPosition(double position);
|
||||||
asynStatus setClosedLoop(bool closedLoop);
|
asynStatus setClosedLoop(bool closedLoop);
|
||||||
|
int setBrake(int brakeIO);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char phytronChar;
|
char phytronChar;
|
||||||
@ -32,15 +38,19 @@ private:
|
|||||||
* Abbreviated because it is used very frequently */
|
* Abbreviated because it is used very frequently */
|
||||||
double position;
|
double position;
|
||||||
int homing;
|
int homing;
|
||||||
|
int homing_direction; /*1 forward, 0 backwards */
|
||||||
time_t next_poll;
|
time_t next_poll;
|
||||||
int encoder;
|
int encoder;
|
||||||
|
int haveBrake;
|
||||||
|
int brakeIO;
|
||||||
|
|
||||||
friend class PhytronController;
|
friend class PhytronController;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PhytronController : public asynMotorController {
|
class PhytronController : public SINQController {
|
||||||
public:
|
public:
|
||||||
PhytronController(const char *portName, const char *PhytronPortName, int encX, int encY);
|
PhytronController(const char *portName, const char *PhytronPortName, const char *selector,
|
||||||
|
int encX, int encY);
|
||||||
|
|
||||||
void report(FILE *fp, int level);
|
void report(FILE *fp, int level);
|
||||||
PhytronAxis* getAxis(asynUser *pasynUser);
|
PhytronAxis* getAxis(asynUser *pasynUser);
|
||||||
@ -50,7 +60,8 @@ friend class PhytronAxis;
|
|||||||
private:
|
private:
|
||||||
asynUser *pasynUserController_;
|
asynUser *pasynUserController_;
|
||||||
|
|
||||||
asynStatus transactController(char command[COMLEN], char reply[COMLEN]);
|
asynStatus transactController(int axisNo, char command[COMLEN], char reply[COMLEN]);
|
||||||
|
|
||||||
|
const char *selector;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
38
sinqEPICSApp/src/SINQAxis.cpp
Normal file
38
sinqEPICSApp/src/SINQAxis.cpp
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
This is a version of the motor axis record which adds code for having an
|
||||||
|
text field with an error message to go with the motor. The code is
|
||||||
|
courtesey Torsten Boergershausen from ESS and from the axisRecord.
|
||||||
|
|
||||||
|
Mark Koennecke, March 2017
|
||||||
|
*/
|
||||||
|
#include "SINQAxis.h"
|
||||||
|
#include "SINQController.h"
|
||||||
|
|
||||||
|
SINQAxis::SINQAxis(class SINQController *pC, int axis)
|
||||||
|
: asynMotorAxis((asynMotorController *)pC, axis),
|
||||||
|
pC_(pC)
|
||||||
|
{
|
||||||
|
updateMsgTxtFromDriver("");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SINQAxis::updateMsgTxtFromDriver(const char *value)
|
||||||
|
{
|
||||||
|
if (value && value[0]) {
|
||||||
|
pC_->setIntegerParam(axisNo_,pC_->motorMessageIsFromDriver_, 1);
|
||||||
|
setStringParam(pC_->motorMessageText_,value);
|
||||||
|
} else {
|
||||||
|
pC_->setIntegerParam(axisNo_,pC_->motorMessageIsFromDriver_, 0);
|
||||||
|
setStringParam(pC_->motorMessageText_,"");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value for a string for this axis in the parameter library.
|
||||||
|
* \param[in] function The function (parameter) number
|
||||||
|
* \param[in] value Value to set */
|
||||||
|
asynStatus SINQAxis::setStringParam(int function, const char *value)
|
||||||
|
{
|
||||||
|
// Call the base class method
|
||||||
|
return pC_->setStringParam(axisNo_, function, value);
|
||||||
|
}
|
30
sinqEPICSApp/src/SINQAxis.h
Normal file
30
sinqEPICSApp/src/SINQAxis.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
This is a version of the motor axis record which adds code for having an
|
||||||
|
text field with an error message to go with the motor. The code is
|
||||||
|
courtesey Torsten Boergershausen from ESS and from the axisRecord.
|
||||||
|
|
||||||
|
Mark Koennecke, March 2017
|
||||||
|
*/
|
||||||
|
#ifndef __SINQDRIVER
|
||||||
|
#define __SINQDRIVER
|
||||||
|
#include "asynMotorAxis.h"
|
||||||
|
|
||||||
|
class epicsShareClass SINQAxis : public asynMotorAxis
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SINQAxis(class SINQController *pC_, int axis);
|
||||||
|
asynStatus setStringParam(int function, const char *value);
|
||||||
|
|
||||||
|
friend class SINQController;
|
||||||
|
void updateMsgTxtFromDriver(const char *value);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
private:
|
||||||
|
SINQController *pC_;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
25
sinqEPICSApp/src/SINQController.cpp
Normal file
25
sinqEPICSApp/src/SINQController.cpp
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
This class contains the necessary changes to have an additional text fields for messages
|
||||||
|
with each axis.
|
||||||
|
|
||||||
|
Code lifted from Torsten Boegershausen ESS code.
|
||||||
|
|
||||||
|
Mark Koennecke, March 2017
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "SINQController.h"
|
||||||
|
#include "asynMotorController.h"
|
||||||
|
|
||||||
|
SINQController::SINQController(const char *portName, const char *SINQPortName, int numAxes, const int& extraParams)
|
||||||
|
: asynMotorController(portName, numAxes+1, NUM_MOTOR_DRIVER_PARAMS+extraParams,
|
||||||
|
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
|
||||||
|
{
|
||||||
|
createParam(motorMessageIsFromDriverString, asynParamInt32, &motorMessageIsFromDriver_);
|
||||||
|
createParam(motorMessageTextString, asynParamOctet, &motorMessageText_);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
30
sinqEPICSApp/src/SINQController.h
Normal file
30
sinqEPICSApp/src/SINQController.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
This class contains the necessary changes to have an additional text fields for messages
|
||||||
|
with each axis.
|
||||||
|
|
||||||
|
Code lifted from Torsten Boegershausens ESS code.
|
||||||
|
|
||||||
|
Mark Koennecke, March 2017
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __SINQCONTROLLER
|
||||||
|
#define __SINQCONTROLLER
|
||||||
|
#include "asynMotorController.h"
|
||||||
|
|
||||||
|
#define motorMessageIsFromDriverString "MOTOR_MESSAGE_DRIVER"
|
||||||
|
#define motorMessageTextString "MOTOR_MESSAGE_TEXT"
|
||||||
|
|
||||||
|
class epicsShareClass SINQController : public asynMotorController
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SINQController(const char *portName, const char *SINQPortName, int numAxes, const int& extraParams=2);
|
||||||
|
|
||||||
|
friend class SINQAxis;
|
||||||
|
protected:
|
||||||
|
int motorMessageIsFromDriver_;
|
||||||
|
int motorMessageText_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -19,7 +19,7 @@
|
|||||||
* - Thresholding
|
* - Thresholding
|
||||||
* - two count modes
|
* - two count modes
|
||||||
* A better solution would be to extend the scalar record to have a proper status and count
|
* A better solution would be to extend the scalar record to have a proper status and count
|
||||||
* mode field. And threshold control fileds too. But this is much more work, breaks
|
* mode field. And threshold control fields too. But this is much more work, breaks
|
||||||
* compatability with the scalar record completely and thus was not done for now.
|
* compatability with the scalar record completely and thus was not done for now.
|
||||||
*
|
*
|
||||||
* The driver will run a separate thread which does all the
|
* The driver will run a separate thread which does all the
|
||||||
@ -27,6 +27,16 @@
|
|||||||
*
|
*
|
||||||
* Mark Koennecke, February 2013
|
* Mark Koennecke, February 2013
|
||||||
*
|
*
|
||||||
|
* Enhanced by adding an addtional external pause and status flag in the database 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
|
||||||
|
*
|
||||||
|
* Enhanced with a separate thresholdCounter and threshold field in order to replace the
|
||||||
|
* hack for threshold handling. If these fields are present, the hack with presets 2 and
|
||||||
|
* 3 as described above is ignored.
|
||||||
|
*
|
||||||
|
* Mark Koennecke, August 2017
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -40,6 +50,10 @@
|
|||||||
#include <recSup.h>
|
#include <recSup.h>
|
||||||
#include <devSup.h>
|
#include <devSup.h>
|
||||||
#include <cantProceed.h>
|
#include <cantProceed.h>
|
||||||
|
#include <dbDefs.h>
|
||||||
|
#include <dbFldTypes.h>
|
||||||
|
#include <dbAccess.h>
|
||||||
|
#include <errlog.h>
|
||||||
|
|
||||||
#include <scalerRecord.h>
|
#include <scalerRecord.h>
|
||||||
#include <devScaler.h>
|
#include <devScaler.h>
|
||||||
@ -49,7 +63,7 @@
|
|||||||
/* dset functions */
|
/* dset functions */
|
||||||
static long el737_init_record(struct scalerRecord *psr, CALLBACK *pcallback);
|
static long el737_init_record(struct scalerRecord *psr, CALLBACK *pcallback);
|
||||||
static long el737_reset(scalerRecord *psr);
|
static long el737_reset(scalerRecord *psr);
|
||||||
static long el737_read(scalerRecord *psr, unsigned long *val);
|
static long el737_read(scalerRecord *psr, epicsUInt32 *val);
|
||||||
static long el737_write_preset(scalerRecord *psr, int signal, unsigned long val);
|
static long el737_write_preset(scalerRecord *psr, int signal, unsigned long val);
|
||||||
static long el737_arm(scalerRecord *psr, int val);
|
static long el737_arm(scalerRecord *psr, int val);
|
||||||
static long el737_done(scalerRecord *psr);
|
static long el737_done(scalerRecord *psr);
|
||||||
@ -84,17 +98,87 @@ typedef struct {
|
|||||||
unsigned long values[NCOUNT];
|
unsigned long values[NCOUNT];
|
||||||
unsigned int countCommand;
|
unsigned int countCommand;
|
||||||
unsigned int counting;
|
unsigned int counting;
|
||||||
|
unsigned long thresholdValue;
|
||||||
unsigned int sendThreshold;
|
unsigned int sendThreshold;
|
||||||
scalerRecord *psr;
|
scalerRecord *psr;
|
||||||
epicsEventId wakeUp;
|
epicsEventId wakeUp;
|
||||||
asynUser *asynContext;
|
asynUser *asynContext;
|
||||||
CALLBACK *pcallback;
|
CALLBACK *pcallback;
|
||||||
|
DBADDR pause;
|
||||||
|
DBADDR status;
|
||||||
|
DBADDR msgTxt;
|
||||||
|
DBADDR threshCounter;
|
||||||
|
DBADDR threshold;
|
||||||
|
unsigned int dbInit;
|
||||||
}EL737priv;
|
}EL737priv;
|
||||||
|
|
||||||
static void dummyAsynCallback(asynUser *pasynUser)
|
static void dummyAsynCallback(asynUser *pasynUser)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void connectSlaveRecords(EL737priv *priv)
|
||||||
|
{
|
||||||
|
char slaveName[PVNAME_SZ], errName[256];
|
||||||
|
long status;
|
||||||
|
|
||||||
|
priv->dbInit = 1;
|
||||||
|
snprintf(slaveName,sizeof(slaveName),"%s:Pause", priv->psr->name);
|
||||||
|
errlogPrintf("Name of pause variable: %s\n", slaveName);
|
||||||
|
status = dbNameToAddr(slaveName,&priv->pause);
|
||||||
|
if(status!= 0){
|
||||||
|
errSymLookup(status,errName,sizeof(errName));
|
||||||
|
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->pause.precord->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(slaveName,sizeof(slaveName),"%s:MsgTxt", priv->psr->name);
|
||||||
|
errlogPrintf("Name of MsgTxt variable: %s\n", slaveName);
|
||||||
|
status = dbNameToAddr(slaveName,&priv->msgTxt);
|
||||||
|
if(status!= 0){
|
||||||
|
errSymLookup(status,errName,sizeof(errName));
|
||||||
|
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->msgTxt.precord->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(slaveName,sizeof(slaveName),"%s:Status", priv->psr->name);
|
||||||
|
errlogPrintf("Name of status variable: %s\n", slaveName);
|
||||||
|
status = dbNameToAddr(slaveName,&priv->status);
|
||||||
|
if(status!= 0){
|
||||||
|
errSymLookup(status,errName,sizeof(errName));
|
||||||
|
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->status.precord->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(slaveName,sizeof(slaveName),"%s:ThresholdCounter", priv->psr->name);
|
||||||
|
errlogPrintf("Name of thresholdCounter variable: %s\n", slaveName);
|
||||||
|
status = dbNameToAddr(slaveName,&priv->threshCounter);
|
||||||
|
if(status!= 0){
|
||||||
|
errSymLookup(status,errName,sizeof(errName));
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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){
|
||||||
|
errSymLookup(status,errName,sizeof(errName));
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
priv->thresholdValue = -999;
|
||||||
|
}
|
||||||
|
|
||||||
static long el737_init_record(scalerRecord *psr, CALLBACK *pcallback)
|
static long el737_init_record(scalerRecord *psr, CALLBACK *pcallback)
|
||||||
{
|
{
|
||||||
EL737priv *priv = NULL;
|
EL737priv *priv = NULL;
|
||||||
@ -122,7 +206,9 @@ static long el737_init_record(scalerRecord *psr, CALLBACK *pcallback)
|
|||||||
priv->psr = psr;
|
priv->psr = psr;
|
||||||
priv->wakeUp = epicsEventCreate(epicsEventEmpty);
|
priv->wakeUp = epicsEventCreate(epicsEventEmpty);
|
||||||
priv->pcallback = pcallback;
|
priv->pcallback = pcallback;
|
||||||
|
priv->dbInit = 0;
|
||||||
psr->dpvt = priv;
|
psr->dpvt = priv;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hook up with device
|
* Hook up with device
|
||||||
@ -139,15 +225,17 @@ static long el737_init_record(scalerRecord *psr, CALLBACK *pcallback)
|
|||||||
status = pasynOctetSyncIO->connect(port, 0, &priv->asynContext, NULL);
|
status = pasynOctetSyncIO->connect(port, 0, &priv->asynContext, NULL);
|
||||||
if (status) {
|
if (status) {
|
||||||
asynPrint(dummyUser, ASYN_TRACE_ERROR,
|
asynPrint(dummyUser, ASYN_TRACE_ERROR,
|
||||||
"%s: cannot connect to EL734 controller\n",
|
"%s: cannot connect to EL737 controller\n",
|
||||||
"el737_init_scaler");
|
"el737_init_scaler");
|
||||||
psr->pact = 1;
|
psr->pact = 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
pasynOctetSyncIO->setOutputEos(priv->asynContext,"\r",strlen("\r"));
|
pasynOctetSyncIO->setOutputEos(priv->asynContext,"\r",strlen("\r"));
|
||||||
pasynOctetSyncIO->setInputEos(priv->asynContext,"\r",strlen("\r"));
|
pasynOctetSyncIO->setInputEos(priv->asynContext,"\r",strlen("\r"));
|
||||||
priv->asynContext->timeout = 1.0;
|
priv->asynContext->timeout = 2.0;
|
||||||
strcpy(command,"RMT 1");
|
strcpy(command,"RMT 1");
|
||||||
|
pasynOctetSyncIO->writeRead(priv->asynContext, command, strlen(command),
|
||||||
|
reply,sizeof(reply), 1.,&out,&in,&reason);
|
||||||
pasynOctetSyncIO->writeRead(priv->asynContext, command, strlen(command),
|
pasynOctetSyncIO->writeRead(priv->asynContext, command, strlen(command),
|
||||||
reply,sizeof(reply), 1.,&out,&in,&reason);
|
reply,sizeof(reply), 1.,&out,&in,&reason);
|
||||||
strcpy(command,"ECHO 2");
|
strcpy(command,"ECHO 2");
|
||||||
@ -155,6 +243,7 @@ static long el737_init_record(scalerRecord *psr, CALLBACK *pcallback)
|
|||||||
reply,sizeof(reply), 1.,&out,&in,&reason);
|
reply,sizeof(reply), 1.,&out,&in,&reason);
|
||||||
pasynManager->freeAsynUser(dummyUser);
|
pasynManager->freeAsynUser(dummyUser);
|
||||||
|
|
||||||
|
connectSlaveRecords(priv);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
start the thread which actually runs the device
|
start the thread which actually runs the device
|
||||||
@ -181,14 +270,14 @@ static long el737_reset(scalerRecord *psr)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long el737_read(scalerRecord *psr, unsigned long *val)
|
static long el737_read(scalerRecord *psr, epicsUInt32 *val)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
EL737priv *priv;
|
EL737priv *priv;
|
||||||
|
|
||||||
priv = (EL737priv *)psr->dpvt;
|
priv = (EL737priv *)psr->dpvt;
|
||||||
for(i = 0; i < NCOUNT; i++){
|
for(i = 0; i < NCOUNT; i++){
|
||||||
val[i] = priv->values[i];
|
val[i] = (epicsUInt32)priv->values[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -245,27 +334,63 @@ static long el737_done(scalerRecord *psr)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static asynStatus el737_transactCommand(asynUser *asynContext, char command[COMLEN],char reply[COMLEN])
|
static asynStatus el737_transactCommand(EL737priv *priv,char command[COMLEN],char reply[COMLEN])
|
||||||
{
|
{
|
||||||
asynStatus status;
|
asynStatus status;
|
||||||
size_t in, out;
|
size_t in, out;
|
||||||
int reason;
|
int reason, dbStatus;
|
||||||
char myCommand[COMLEN];
|
char myCommand[COMLEN], message[40];
|
||||||
|
|
||||||
pasynOctetSyncIO->flush(asynContext);
|
pasynOctetSyncIO->flush(priv->asynContext);
|
||||||
|
|
||||||
status = pasynOctetSyncIO->writeRead(asynContext, command, strlen(command),
|
strcpy(message,"");
|
||||||
|
status = pasynOctetSyncIO->writeRead(priv->asynContext, command, strlen(command),
|
||||||
reply,COMLEN, 1.,&out,&in,&reason);
|
reply,COMLEN, 1.,&out,&in,&reason);
|
||||||
if(status == asynSuccess){
|
if(status == asynSuccess){
|
||||||
if(strstr(reply,"?OF") != NULL){
|
if(strstr(reply,"?OF") != NULL){
|
||||||
strcpy(myCommand,"RMT 1");
|
strcpy(myCommand,"RMT 1");
|
||||||
status = pasynOctetSyncIO->writeRead(asynContext, myCommand, strlen(myCommand),
|
status = pasynOctetSyncIO->writeRead(priv->asynContext, myCommand, strlen(myCommand),
|
||||||
reply,COMLEN, 1.,&out,&in,&reason);
|
reply,COMLEN, 1.,&out,&in,&reason);
|
||||||
strcpy(myCommand,"ECHO 2");
|
strcpy(myCommand,"ECHO 2");
|
||||||
status = pasynOctetSyncIO->writeRead(asynContext, myCommand, strlen(myCommand),
|
status = pasynOctetSyncIO->writeRead(priv->asynContext, myCommand, strlen(myCommand),
|
||||||
reply,COMLEN, 1.,&out,&in,&reason);
|
reply,COMLEN, 1.,&out,&in,&reason);
|
||||||
return pasynOctetSyncIO->writeRead(asynContext, command, strlen(command),
|
return pasynOctetSyncIO->writeRead(priv->asynContext, command, strlen(command),
|
||||||
reply,COMLEN, 1.,&out,&in,&reason);
|
reply,COMLEN, 1.,&out,&in,&reason);
|
||||||
|
} else {
|
||||||
|
if(strstr(reply,"?OV") != NULL){
|
||||||
|
strncpy(message,"Overflow",sizeof(message));
|
||||||
|
} else if(strstr(reply,"?1") != NULL) {
|
||||||
|
strncpy(message,"Par out of range",sizeof(message));
|
||||||
|
} else if(strstr(reply,"?2") != NULL){
|
||||||
|
strncpy(message,"Bad command",sizeof(message));
|
||||||
|
} else if(strstr(reply,"?3") != NULL){
|
||||||
|
strncpy(message,"Bad parameter",sizeof(message));
|
||||||
|
} else if(strstr(reply,"?4") != NULL){
|
||||||
|
strncpy(message,"Bad counter",sizeof(message));
|
||||||
|
} else if(strstr(reply,"?5") != NULL){
|
||||||
|
strncpy(message,"Parameter missing",sizeof(message));
|
||||||
|
} else if(strstr(reply,"?6") != NULL){
|
||||||
|
strncpy(message,"to many counts",sizeof(message));
|
||||||
|
} else if(strstr(reply,"?91") != NULL){
|
||||||
|
strncpy(message,"Start Failure",sizeof(message));
|
||||||
|
} else if(strstr(reply,"?92") != NULL){
|
||||||
|
strncpy(message,"Failure while counting",sizeof(message));
|
||||||
|
} else if(strstr(reply,"?93") != NULL){
|
||||||
|
strncpy(message,"Read Failure",sizeof(message));
|
||||||
|
} else {
|
||||||
|
if(strstr(reply,"?") != NULL) {
|
||||||
|
snprintf(message,sizeof(message),"HW error: %s", reply);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
strncpy(message,"Lost communication",sizeof(message));
|
||||||
|
}
|
||||||
|
if(priv->dbInit){
|
||||||
|
dbStatus = dbPutField(&priv->msgTxt, DBR_STRING,message, 1);
|
||||||
|
if(dbStatus!= 0){
|
||||||
|
errSymLookup(dbStatus,message,sizeof(message));
|
||||||
|
errlogPrintf("Setting external count message failed with %s\n", message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
@ -276,23 +401,66 @@ static asynStatus sendStop(EL737priv *priv)
|
|||||||
char command[COMLEN], reply[COMLEN];
|
char command[COMLEN], reply[COMLEN];
|
||||||
//errlogPrintf("Sending stop\n");
|
//errlogPrintf("Sending stop\n");
|
||||||
strcpy(command,"S");
|
strcpy(command,"S");
|
||||||
return el737_transactCommand(priv->asynContext,command,reply);
|
return el737_transactCommand(priv,command,reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void runEvents(EL737priv *priv)
|
static void runEvents(EL737priv *priv)
|
||||||
{
|
{
|
||||||
char command[COMLEN], reply[COMLEN];
|
char command[COMLEN], reply[COMLEN], errName[256];
|
||||||
int status;
|
int status;
|
||||||
|
long dbStatus, myThreshold, nElements = 1, options = 0, threshCounter;
|
||||||
|
|
||||||
if(priv->sendThreshold == 1){
|
/*
|
||||||
sprintf(command,"DL %d %d", (int)priv->presets[THRESHMON],
|
This is the better way to set the threshold rather then the old way below which uses
|
||||||
(int)priv->presets[THRESHVAL]);
|
presets for that function. This one uses separate fields.
|
||||||
//errlogPrintf("Sending threshold command %s\n", command);
|
*/
|
||||||
status = el737_transactCommand(priv->asynContext,command,reply);
|
if(priv->dbInit == 1 && priv->sendThreshold) {
|
||||||
sprintf(command,"DR %d", (int)priv->presets[THRESHMON]);
|
dbStatus = dbGetField(&priv->threshold,DBR_LONG,&myThreshold,&options, &nElements,NULL);
|
||||||
status = el737_transactCommand(priv->asynContext,command,reply);
|
if(dbStatus != 0){
|
||||||
if(status == asynSuccess){
|
errSymLookup(dbStatus,errName,sizeof(errName));
|
||||||
priv->sendThreshold = 0;
|
errlogPrintf("Reading threshold failed with %s\n", errName);
|
||||||
|
} else {
|
||||||
|
if(myThreshold != priv->thresholdValue){
|
||||||
|
/*
|
||||||
|
we have to set the threshold
|
||||||
|
*/
|
||||||
|
dbStatus = dbGetField(&priv->threshCounter,DBR_LONG,&threshCounter, &options, &nElements,NULL);
|
||||||
|
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);
|
||||||
|
status = el737_transactCommand(priv,command,reply);
|
||||||
|
sprintf(command,"DR %d", (int)threshCounter);
|
||||||
|
status = el737_transactCommand(priv, command,reply);
|
||||||
|
if(status == asynSuccess){
|
||||||
|
priv->sendThreshold = 0;
|
||||||
|
priv->thresholdValue = myThreshold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(priv->sendThreshold == 1) {
|
||||||
|
// fallback when we do not have the DB fields or threshCounter is invalid
|
||||||
|
if(priv->presets[THRESHMON] <= 0) {
|
||||||
|
errlogPrintf("Invalid threshold preset monitor %ld, no threshold sent", priv->presets[THRESHMON]);
|
||||||
|
} else {
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,7 +475,7 @@ static void runEvents(EL737priv *priv)
|
|||||||
sprintf(command,"TP %f", priv->presets[TIMER]/1000.);
|
sprintf(command,"TP %f", priv->presets[TIMER]/1000.);
|
||||||
//errlogPrintf("Starting preset timer\n");
|
//errlogPrintf("Starting preset timer\n");
|
||||||
}
|
}
|
||||||
status = el737_transactCommand(priv->asynContext,command,reply);
|
status = el737_transactCommand(priv,command,reply);
|
||||||
if(status == asynSuccess){
|
if(status == asynSuccess){
|
||||||
priv->counting = 1;
|
priv->counting = 1;
|
||||||
}
|
}
|
||||||
@ -335,7 +503,7 @@ static void updateValues(EL737priv *priv)
|
|||||||
long m1, m2 ,m3, m4, m5, m6 ,m7, m8;
|
long m1, m2 ,m3, m4, m5, m6 ,m7, m8;
|
||||||
|
|
||||||
strcpy(command,"RA");
|
strcpy(command,"RA");
|
||||||
status = el737_transactCommand(priv->asynContext,command,reply);
|
status = el737_transactCommand(priv,command,reply);
|
||||||
if(status != asynSuccess){
|
if(status != asynSuccess){
|
||||||
errlogPrintf("devScalerEL737::el737Thread communication problem %s\n",
|
errlogPrintf("devScalerEL737::el737Thread communication problem %s\n",
|
||||||
priv->asynContext->errorMessage);
|
priv->asynContext->errorMessage);
|
||||||
@ -371,9 +539,10 @@ static void el737Thread(void *param)
|
|||||||
EL737priv *priv = (EL737priv *)param;
|
EL737priv *priv = (EL737priv *)param;
|
||||||
epicsEventWaitStatus evStatus;
|
epicsEventWaitStatus evStatus;
|
||||||
double timeout = 60.;
|
double timeout = 60.;
|
||||||
char command[COMLEN], reply[COMLEN];
|
char command[COMLEN], reply[COMLEN], errName[256];
|
||||||
asynStatus status;
|
asynStatus status;
|
||||||
int rs;
|
int rs, ctStatus;
|
||||||
|
long dbStatus, options, nElements = 1, pauseFlag = 0;
|
||||||
|
|
||||||
//errlogPrintf("Within EL737 thread \n");
|
//errlogPrintf("Within EL737 thread \n");
|
||||||
|
|
||||||
@ -402,7 +571,7 @@ static void el737Thread(void *param)
|
|||||||
|
|
||||||
if(priv->counting) {
|
if(priv->counting) {
|
||||||
strcpy(command,"RS");
|
strcpy(command,"RS");
|
||||||
status = el737_transactCommand(priv->asynContext,command,reply);
|
status = el737_transactCommand(priv, command,reply);
|
||||||
if(status != asynSuccess){
|
if(status != asynSuccess){
|
||||||
errlogPrintf("devScalerEL737::el737Thread communication problem %s\n",
|
errlogPrintf("devScalerEL737::el737Thread communication problem %s\n",
|
||||||
priv->asynContext->errorMessage);
|
priv->asynContext->errorMessage);
|
||||||
@ -414,15 +583,57 @@ static void el737Thread(void *param)
|
|||||||
priv->counting = 0;
|
priv->counting = 0;
|
||||||
timeout = 60.;
|
timeout = 60.;
|
||||||
priv->values[9] = 0;
|
priv->values[9] = 0;
|
||||||
|
ctStatus = 0;
|
||||||
} else if(rs == 1 || rs == 2){
|
} else if(rs == 1 || rs == 2){
|
||||||
/* counting */
|
/* counting */
|
||||||
priv->values[9] = 1;
|
priv->values[9] = 1;
|
||||||
|
ctStatus = 1;
|
||||||
} else if(rs == 5 || rs == 6){
|
} else if(rs == 5 || rs == 6){
|
||||||
/* low rate */
|
/* low rate */
|
||||||
priv->values[9] = 2;
|
priv->values[9] = 2;
|
||||||
|
ctStatus = 2;
|
||||||
} else if(rs == 9 || rs == 13 || rs == 10 || rs == 14){
|
} else if(rs == 9 || rs == 13 || rs == 10 || rs == 14){
|
||||||
/* low rate */
|
/* paused states */
|
||||||
priv->values[9] = 2;
|
priv->values[9] = 3;
|
||||||
|
ctStatus = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(priv->dbInit){
|
||||||
|
/*
|
||||||
|
update the external status field
|
||||||
|
*/
|
||||||
|
dbStatus = dbPutField(&priv->status, DBR_LONG,&ctStatus, 1);
|
||||||
|
if(dbStatus!= 0){
|
||||||
|
errSymLookup(dbStatus,errName,sizeof(errName));
|
||||||
|
errlogPrintf("Setting external count status failed with %s\n", errName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
check and handle pause flag
|
||||||
|
*/
|
||||||
|
dbStatus = dbGetField(&priv->pause, DBR_LONG,&pauseFlag,&options, &nElements, NULL);
|
||||||
|
if(dbStatus!= 0){
|
||||||
|
errSymLookup(dbStatus,errName,sizeof(errName));
|
||||||
|
errlogPrintf("Reading pauseFlag failed with %s\n", errName);
|
||||||
|
}
|
||||||
|
/* errlogPrintf("Successfully read %ld pause flags as %d\n",nElements, pauseFlag); */
|
||||||
|
if(pauseFlag == 1 && ctStatus == 1){
|
||||||
|
strcpy(command,"PS");
|
||||||
|
status = el737_transactCommand(priv, command,reply);
|
||||||
|
if(status != asynSuccess){
|
||||||
|
errlogPrintf("devScalerEL737::el737Thread communication problem %s\n",
|
||||||
|
priv->asynContext->errorMessage);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if(pauseFlag == 0 && ctStatus == 3){
|
||||||
|
strcpy(command,"CO");
|
||||||
|
status = el737_transactCommand(priv,command,reply);
|
||||||
|
if(status != asynSuccess){
|
||||||
|
errlogPrintf("devScalerEL737::el737Thread communication problem %s\n",
|
||||||
|
priv->asynContext->errorMessage);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,9 +1,19 @@
|
|||||||
|
|
||||||
record(scaler,"")
|
record(bo,"$(P):Pause")
|
||||||
{
|
{
|
||||||
field(NAME,"NZ:counter")
|
field(DTYP,"Soft Channel")
|
||||||
field(DESC,"NARZIS EL737 counter")
|
}
|
||||||
field(DTYP,"asynScalerEL737")
|
record(longin,"$(P):Status")
|
||||||
field(OUT,"INST_IO @asyn(cter1,0)"
|
{
|
||||||
|
field(DTYP,"Soft Channel")
|
||||||
|
}
|
||||||
|
record(stringin,"$(P):MsgTxt")
|
||||||
|
{
|
||||||
|
field(DTYP,"Soft Channel")
|
||||||
|
}
|
||||||
|
record(scaler,"$(P)")
|
||||||
|
{
|
||||||
|
field(DESC,"$(DESC)")
|
||||||
|
field(DTYP,"asynScalerEL737")
|
||||||
|
field(OUT,"INST_IO @asyn($(PORT),0)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -7,21 +7,28 @@
|
|||||||
* Matthew Pearson
|
* Matthew Pearson
|
||||||
* 23 May 2012
|
* 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
|
#ifndef pmacAxis_H
|
||||||
#define pmacAxis_H
|
#define pmacAxis_H
|
||||||
|
|
||||||
#include "asynMotorController.h"
|
#include "SINQController.h"
|
||||||
#include "asynMotorAxis.h"
|
#include "SINQAxis.h"
|
||||||
|
|
||||||
class pmacController;
|
class pmacController;
|
||||||
|
class SeleneController;
|
||||||
|
|
||||||
class pmacAxis : public asynMotorAxis
|
class pmacAxis : public SINQAxis
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/* These are the methods we override from the base class */
|
/* These are the methods we override from the base class */
|
||||||
pmacAxis(pmacController *pController, int axisNo);
|
pmacAxis(pmacController *pController, int axisNo, bool enable=true);
|
||||||
virtual ~pmacAxis();
|
virtual ~pmacAxis();
|
||||||
asynStatus move(double position, int relative, double min_velocity, double max_velocity, double acceleration);
|
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 moveVelocity(double min_velocity, double max_velocity, double acceleration);
|
||||||
@ -29,8 +36,9 @@ class pmacAxis : public asynMotorAxis
|
|||||||
asynStatus stop(double acceleration);
|
asynStatus stop(double acceleration);
|
||||||
asynStatus poll(bool *moving);
|
asynStatus poll(bool *moving);
|
||||||
asynStatus setPosition(double position);
|
asynStatus setPosition(double position);
|
||||||
|
asynStatus enable(int on);
|
||||||
private:
|
|
||||||
|
protected:
|
||||||
pmacController *pC_;
|
pmacController *pC_;
|
||||||
|
|
||||||
asynStatus getAxisStatus(bool *moving);
|
asynStatus getAxisStatus(bool *moving);
|
||||||
@ -53,9 +61,100 @@ class pmacAxis : public asynMotorAxis
|
|||||||
time_t status6Time;
|
time_t status6Time;
|
||||||
int starting;
|
int starting;
|
||||||
int homing;
|
int homing;
|
||||||
|
double statusPos;
|
||||||
|
|
||||||
|
time_t next_poll;
|
||||||
|
|
||||||
|
bool autoEnable;
|
||||||
|
|
||||||
friend class pmacController;
|
friend class pmacController;
|
||||||
|
friend class pmacV3Controller;
|
||||||
|
};
|
||||||
|
/*----------------------------------------------------------------------------------------------*/
|
||||||
|
class pmacHRPTAxis : public pmacAxis
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
pmacHRPTAxis(pmacController *pController, int axisNo) : pmacAxis(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;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------------------------*/
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* pmacAxis_H */
|
#endif /* pmacAxis_H */
|
||||||
|
@ -13,6 +13,11 @@
|
|||||||
* This affects also the commands they understand.
|
* This affects also the commands they understand.
|
||||||
*
|
*
|
||||||
* Mark Koennecke, February 2013
|
* Mark Koennecke, February 2013
|
||||||
|
*
|
||||||
|
* Updated to use the MsgTxt field for error messages as
|
||||||
|
* used at ESS and SINQ
|
||||||
|
*
|
||||||
|
* Mark Koennecke, January 2019
|
||||||
********************************************/
|
********************************************/
|
||||||
|
|
||||||
|
|
||||||
@ -27,17 +32,19 @@
|
|||||||
using std::cout;
|
using std::cout;
|
||||||
using std::endl;
|
using std::endl;
|
||||||
|
|
||||||
#include <epicsTime.h>
|
#include "epicsTime.h"
|
||||||
#include <epicsThread.h>
|
#include <epicsThread.h>
|
||||||
#include <epicsExport.h>
|
#include <epicsExport.h>
|
||||||
#include <epicsString.h>
|
#include <epicsString.h>
|
||||||
#include <iocsh.h>
|
#include <iocsh.h>
|
||||||
#include <drvSup.h>
|
#include <drvSup.h>
|
||||||
#include <registryFunction.h>
|
#include <registryFunction.h>
|
||||||
|
#include <errlog.h>
|
||||||
|
|
||||||
#include "asynOctetSyncIO.h"
|
#include "asynOctetSyncIO.h"
|
||||||
|
|
||||||
#include "pmacController.h"
|
#include "pmacController.h"
|
||||||
|
#include "pmacAxis.h"
|
||||||
|
|
||||||
#define MULT 1000.
|
#define MULT 1000.
|
||||||
|
|
||||||
@ -124,25 +131,23 @@ const epicsUInt32 pmacController::PMAX_AXIS_GENERAL_PROB2 = (PMAC_STATUS2_DESIRE
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
asynStatus pmacCreateController(const char *portName, const char *lowLevelPortName, int lowLevelPortAddress,
|
asynStatus pmacCreateController(const char *portName, const char *lowLevelPortName, int lowLevelPortAddress,
|
||||||
int numAxes, int movingPollPeriod, int idlePollPeriod);
|
int numAxes, int movingPollPeriod, int idlePollPeriod);
|
||||||
|
asynStatus SeleneCreateController(const char *portName, const char *lowLevelPortName, int lowLevelPortAddress,
|
||||||
|
int numAxes, int movingPollPeriod, int idlePollPeriod);
|
||||||
|
asynStatus pmacV3CreateController(const char *portName,
|
||||||
|
const char *lowLevelPortName,
|
||||||
|
int lowLevelPortAddress, int numAxes,
|
||||||
|
int movingPollPeriod, int idlePollPeriod);
|
||||||
asynStatus pmacCreateAxis(const char *pmacName, int axis);
|
asynStatus pmacCreateAxis(const char *pmacName, int axis);
|
||||||
asynStatus pmacCreateAxis(const char *pmacName, int numAxis);
|
asynStatus pmacCreateAxis(const char *pmacName, int numAxis);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pmacController::pmacController(const char *portName, const char *lowLevelPortName, int lowLevelPortAddress,
|
pmacController::pmacController(const char *portName, const char *lowLevelPortName, int lowLevelPortAddress,
|
||||||
int numAxes, double movingPollPeriod, double idlePollPeriod)
|
int numAxes, double movingPollPeriod, double idlePollPeriod, const int& extraParams)
|
||||||
: asynMotorController(portName, numAxes+1, NUM_MOTOR_DRIVER_PARAMS,
|
: SINQController(portName, lowLevelPortName, numAxes+1, extraParams)
|
||||||
0, // No additional interfaces
|
|
||||||
0, // No addition interrupt interfaces
|
|
||||||
ASYN_CANBLOCK | ASYN_MULTIDEVICE,
|
|
||||||
1, // autoconnect
|
|
||||||
0, 0) // Default priority and stack size
|
|
||||||
{
|
{
|
||||||
static const char *functionName = "pmacController::pmacController";
|
static const char *functionName = "pmacController::pmacController";
|
||||||
|
|
||||||
printf(" Constructor: %s\n", functionName);
|
|
||||||
|
|
||||||
//Initialize non static data members
|
//Initialize non static data members
|
||||||
lowLevelPortUser_ = NULL;
|
lowLevelPortUser_ = NULL;
|
||||||
debugFlag_ = 0;
|
debugFlag_ = 0;
|
||||||
@ -153,7 +158,7 @@ pmacController::pmacController(const char *portName, const char *lowLevelPortNam
|
|||||||
createParam(PMAC_C_CommsErrorString, asynParamInt32, &PMAC_C_CommsError_);
|
createParam(PMAC_C_CommsErrorString, asynParamInt32, &PMAC_C_CommsError_);
|
||||||
|
|
||||||
// Connect our Asyn user to the low level port that is a parameter to this constructor
|
// Connect our Asyn user to the low level port that is a parameter to this constructor
|
||||||
if (lowLevelPortConnect(lowLevelPortName, lowLevelPortAddress, &lowLevelPortUser_, "\006", "\r") != asynSuccess) {
|
if (lowLevelPortConnect(lowLevelPortName, lowLevelPortAddress, &lowLevelPortUser_, "\006", (char *)"\r") != asynSuccess) {
|
||||||
printf("%s: Failed to connect to low level asynOctetSyncIO port %s\n", functionName, lowLevelPortName);
|
printf("%s: Failed to connect to low level asynOctetSyncIO port %s\n", functionName, lowLevelPortName);
|
||||||
setIntegerParam(PMAC_C_CommsError_, 1);
|
setIntegerParam(PMAC_C_CommsError_, 1);
|
||||||
} else {
|
} else {
|
||||||
@ -251,7 +256,7 @@ asynStatus pmacController::printConnectedStatus()
|
|||||||
* @param command - String command to send.
|
* @param command - String command to send.
|
||||||
* @response response - String response back.
|
* @response response - String response back.
|
||||||
*/
|
*/
|
||||||
asynStatus pmacController::lowLevelWriteRead(const char *command, char *response)
|
asynStatus pmacController::lowLevelWriteRead(int axisNo, const char *command, char *response)
|
||||||
{
|
{
|
||||||
asynStatus status = asynSuccess;
|
asynStatus status = asynSuccess;
|
||||||
|
|
||||||
@ -260,6 +265,7 @@ asynStatus pmacController::lowLevelWriteRead(const char *command, char *response
|
|||||||
size_t nread = 0;
|
size_t nread = 0;
|
||||||
int commsError = 0;
|
int commsError = 0;
|
||||||
static const char *functionName = "pmacController::lowLevelWriteRead";
|
static const char *functionName = "pmacController::lowLevelWriteRead";
|
||||||
|
pmacAxis *axis = getAxis(axisNo);
|
||||||
|
|
||||||
debugFlow(functionName);
|
debugFlow(functionName);
|
||||||
|
|
||||||
@ -286,6 +292,9 @@ asynStatus pmacController::lowLevelWriteRead(const char *command, char *response
|
|||||||
if (status) {
|
if (status) {
|
||||||
asynPrint(lowLevelPortUser_, ASYN_TRACE_ERROR, "%s: Error from pasynOctetSyncIO->writeRead. command: %s\n", functionName, command);
|
asynPrint(lowLevelPortUser_, ASYN_TRACE_ERROR, "%s: Error from pasynOctetSyncIO->writeRead. command: %s\n", functionName, command);
|
||||||
setIntegerParam(this->motorStatusCommsError_, 1);
|
setIntegerParam(this->motorStatusCommsError_, 1);
|
||||||
|
if(axis!= NULL){
|
||||||
|
axis->updateMsgTxtFromDriver("Lost connection to motor controller");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
setIntegerParam(this->motorStatusCommsError_, 0);
|
setIntegerParam(this->motorStatusCommsError_, 0);
|
||||||
}
|
}
|
||||||
@ -339,8 +348,6 @@ asynStatus pmacController::writeFloat64(asynUser *pasynUser, epicsFloat64 value)
|
|||||||
pmacAxis *pAxis = NULL;
|
pmacAxis *pAxis = NULL;
|
||||||
char command[64] = {0};
|
char command[64] = {0};
|
||||||
char response[64] = {0};
|
char response[64] = {0};
|
||||||
double encRatio = 1.0;
|
|
||||||
epicsInt32 encposition = 0;
|
|
||||||
char message[132];
|
char message[132];
|
||||||
|
|
||||||
static const char *functionName = "pmacController::writeFloat64";
|
static const char *functionName = "pmacController::writeFloat64";
|
||||||
@ -408,6 +415,7 @@ asynStatus pmacController::writeFloat64(asynUser *pasynUser, epicsFloat64 value)
|
|||||||
// bool moving = true;
|
// bool moving = true;
|
||||||
// pAxis->getAxisStatus(&moving);
|
// pAxis->getAxisStatus(&moving);
|
||||||
// } else
|
// } else
|
||||||
|
/*
|
||||||
if (function == motorLowLimit_) {
|
if (function == motorLowLimit_) {
|
||||||
sprintf(command, "I%d14=%d", pAxis->axisNo_, (int)(value/pAxis->scale_/MULT));
|
sprintf(command, "I%d14=%d", pAxis->axisNo_, (int)(value/pAxis->scale_/MULT));
|
||||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
|
||||||
@ -422,8 +430,9 @@ asynStatus pmacController::writeFloat64(asynUser *pasynUser, epicsFloat64 value)
|
|||||||
|
|
||||||
//Execute the command.
|
//Execute the command.
|
||||||
if (command[0] != 0 && status == asynSuccess) {
|
if (command[0] != 0 && status == asynSuccess) {
|
||||||
status = lowLevelWriteRead(command, response);
|
status = lowLevelWriteRead(pAxis->axisNo_,command, response);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
//Call base class method
|
//Call base class method
|
||||||
//This will handle callCallbacks even if the function was handled here.
|
//This will handle callCallbacks even if the function was handled here.
|
||||||
@ -461,7 +470,6 @@ asynStatus pmacController::writeInt32(asynUser *pasynUser, epicsInt32 value)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/** Returns a pointer to an pmacAxis object.
|
/** Returns a pointer to an pmacAxis object.
|
||||||
* Returns NULL if the axis number encoded in pasynUser is invalid.
|
* Returns NULL if the axis number encoded in pasynUser is invalid.
|
||||||
* \param[in] pasynUser asynUser structure that encodes the axis index number. */
|
* \param[in] pasynUser asynUser structure that encodes the axis index number. */
|
||||||
@ -527,18 +535,92 @@ asynStatus pmacCreateController(const char *portName, const char *lowLevelPortNa
|
|||||||
return asynSuccess;
|
return asynSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
asynStatus SeleneCreateController(const char *portName, const char *lowLevelPortName, int lowLevelPortAddress,
|
||||||
|
int numAxes, int movingPollPeriod, int idlePollPeriod)
|
||||||
|
{
|
||||||
|
|
||||||
|
SeleneController *ppmacController
|
||||||
|
= new SeleneController(portName, lowLevelPortName, lowLevelPortAddress, numAxes, movingPollPeriod/1000., idlePollPeriod/1000.);
|
||||||
|
ppmacController = NULL;
|
||||||
|
|
||||||
|
return asynSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
asynStatus pmacV3CreateController(const char *portName, const char *lowLevelPortName, int lowLevelPortAddress,
|
||||||
|
int numAxes, int movingPollPeriod, int idlePollPeriod)
|
||||||
|
{
|
||||||
|
|
||||||
|
pmacController *ppmacController = new pmacV3Controller(portName, lowLevelPortName, lowLevelPortAddress, numAxes, movingPollPeriod/1000., idlePollPeriod/1000.);
|
||||||
|
ppmacController = NULL;
|
||||||
|
|
||||||
|
return asynSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------------------------------------------------*/
|
||||||
|
SeleneController::SeleneController(const char *portName, const char *lowLevelPortName, int lowLevelPortAddress,
|
||||||
|
int numAxes, double movingPollPeriod, double idlePollPeriod) : pmacController(portName,
|
||||||
|
lowLevelPortName,
|
||||||
|
lowLevelPortAddress,
|
||||||
|
numAxes,
|
||||||
|
movingPollPeriod,
|
||||||
|
idlePollPeriod, 3) {
|
||||||
|
static const char *functionName = "seleneController::seleneController";
|
||||||
|
createParam(MotorSetPositionString, asynParamFloat64, &setMotorPosition_);
|
||||||
|
callParamCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
pmacV3Controller::pmacV3Controller(const char *portName,
|
||||||
|
const char *lowLevelPortName,
|
||||||
|
int lowLevelPortAddress, int numAxes,
|
||||||
|
double movingPollPeriod,
|
||||||
|
double idlePollPeriod,
|
||||||
|
const int &extraParams) :
|
||||||
|
pmacController(portName, lowLevelPortName, lowLevelPortAddress, numAxes, movingPollPeriod, idlePollPeriod, extraParams) {
|
||||||
|
static const char *functionName = "pmacV3Controller::pmacV3Controller";
|
||||||
|
createParam(EnableAxisString, asynParamInt32, &enableAxis_);
|
||||||
|
createParam(AxisEnabledString, asynParamInt32, &axisEnabled_);
|
||||||
|
callParamCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* C wrapper for the pmacAxis constructor.
|
||||||
|
* See pmacAxis::pmacAxis.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
asynStatus pmacCreateAxis(
|
||||||
|
const char *pmacName, /* specify which controller by port name */
|
||||||
|
int axis) /* axis number (start from 1). */
|
||||||
|
{
|
||||||
|
pmacController *pC;
|
||||||
|
pmacAxis *pAxis;
|
||||||
|
|
||||||
|
static const char *functionName = "pmacCreateAxis";
|
||||||
|
|
||||||
|
pC = (pmacController *)findAsynPortDriver(pmacName);
|
||||||
|
if (!pC) {
|
||||||
|
printf("%s:%s: Error port %s not found\n", driverName, functionName,
|
||||||
|
pmacName);
|
||||||
|
return asynError;
|
||||||
|
}
|
||||||
|
|
||||||
|
pC->lock();
|
||||||
|
pAxis = new pmacAxis(pC, axis);
|
||||||
|
pAxis = NULL;
|
||||||
|
pC->unlock();
|
||||||
|
return asynSuccess;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* C wrapper for the pmacAxis constructor.
|
* C wrapper for the pmacHRPTAxis constructor.
|
||||||
* See pmacAxis::pmacAxis.
|
* See pmacHRPTAxis::pmacHRPTAxis.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
asynStatus pmacCreateAxis(const char *pmacName, /* specify which controller by port name */
|
asynStatus pmacCreateHRPTAxis(const char *pmacName, /* specify which controller by port name */
|
||||||
int axis) /* axis number (start from 1). */
|
int axis) /* axis number (start from 1). */
|
||||||
{
|
{
|
||||||
pmacController *pC;
|
pmacController *pC;
|
||||||
pmacAxis *pAxis;
|
pmacAxis *pAxis;
|
||||||
|
|
||||||
static const char *functionName = "pmacCreateAxis";
|
static const char *functionName = "pmacCreateHRPTAxis";
|
||||||
|
|
||||||
pC = (pmacController*) findAsynPortDriver(pmacName);
|
pC = (pmacController*) findAsynPortDriver(pmacName);
|
||||||
if (!pC) {
|
if (!pC) {
|
||||||
@ -548,14 +630,97 @@ asynStatus pmacCreateAxis(const char *pmacName, /* specify which control
|
|||||||
}
|
}
|
||||||
|
|
||||||
pC->lock();
|
pC->lock();
|
||||||
pAxis = new pmacAxis(pC, axis);
|
pAxis = new pmacHRPTAxis(pC, axis);
|
||||||
pAxis = NULL;
|
pAxis = NULL;
|
||||||
pC->unlock();
|
pC->unlock();
|
||||||
return asynSuccess;
|
return asynSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* C Wrapper function for pmacAxis constructor.
|
* C wrapper for the SeleneAxis constructor.
|
||||||
|
* See SeleneAxis::SeleneAxis.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
asynStatus SeleneCreateAxis(const char *pmacName, /* specify which controller by port name */
|
||||||
|
int axis, /* axis number (start from 1). */
|
||||||
|
double limitTarget)
|
||||||
|
{
|
||||||
|
SeleneController *pC;
|
||||||
|
SeleneAxis *pAxis;
|
||||||
|
|
||||||
|
static const char *functionName = "SeleneCreateAxis";
|
||||||
|
|
||||||
|
pC = (SeleneController*) findAsynPortDriver(pmacName);
|
||||||
|
if (!pC) {
|
||||||
|
printf("%s:%s: Error port %s not found\n",
|
||||||
|
driverName, functionName, pmacName);
|
||||||
|
return asynError;
|
||||||
|
}
|
||||||
|
|
||||||
|
pC->lock();
|
||||||
|
pAxis = new SeleneAxis(pC, axis, limitTarget);
|
||||||
|
pAxis = NULL;
|
||||||
|
pC->unlock();
|
||||||
|
return asynSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* C wrapper for the Selene LiftAxis constructor.
|
||||||
|
* See LiftAxis::LiftAxis.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
asynStatus LiftCreateAxis(const char *pmacName, /* specify which controller by port name */
|
||||||
|
int axis) /* axis number (start from 1). */
|
||||||
|
{
|
||||||
|
pmacController *pC;
|
||||||
|
LiftAxis *pAxis;
|
||||||
|
|
||||||
|
static const char *functionName = "LiftCreateAxis";
|
||||||
|
|
||||||
|
pC = (pmacController*) findAsynPortDriver(pmacName);
|
||||||
|
if (!pC) {
|
||||||
|
printf("%s:%s: Error port %s not found\n",
|
||||||
|
driverName, functionName, pmacName);
|
||||||
|
return asynError;
|
||||||
|
}
|
||||||
|
|
||||||
|
pC->lock();
|
||||||
|
pAxis = new LiftAxis(pC, axis);
|
||||||
|
pAxis = NULL;
|
||||||
|
pC->unlock();
|
||||||
|
return asynSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* C wrapper for the pmacV3Axis constructor.
|
||||||
|
* See pmacAxis::pmacV3Axis.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
asynStatus pmacV3CreateAxis(
|
||||||
|
const char *pmacName, /* specify which controller by port name */
|
||||||
|
int axis) /* axis number (start from 1). */
|
||||||
|
{
|
||||||
|
pmacController *pC;
|
||||||
|
pmacAxis *pAxis;
|
||||||
|
|
||||||
|
static const char *functionName = "pmacV3CreateAxis";
|
||||||
|
|
||||||
|
pC = (pmacController *)findAsynPortDriver(pmacName);
|
||||||
|
if (!pC) {
|
||||||
|
printf("%s:%s: Error port %s not found\n", driverName, functionName,
|
||||||
|
pmacName);
|
||||||
|
return asynError;
|
||||||
|
}
|
||||||
|
|
||||||
|
pC->lock();
|
||||||
|
pAxis = new pmacV3Axis(pC, axis);
|
||||||
|
pAxis = NULL;
|
||||||
|
pC->unlock();
|
||||||
|
return asynSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* C Wrapper function for pmacHRPTAxis constructor.
|
||||||
* See pmacAxis::pmacAxis.
|
* See pmacAxis::pmacAxis.
|
||||||
* This function allows creation of multiple pmacAxis objects with axis numbers 1 to numAxes.
|
* This function allows creation of multiple pmacAxis objects with axis numbers 1 to numAxes.
|
||||||
* @param pmacName Asyn port name for the controller (const char *)
|
* @param pmacName Asyn port name for the controller (const char *)
|
||||||
@ -586,6 +751,137 @@ asynStatus pmacCreateAxes(const char *pmacName,
|
|||||||
return asynSuccess;
|
return asynSuccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*================================ SeleneController ===============================================*/
|
||||||
|
|
||||||
|
asynStatus SeleneController::writeFloat64(asynUser *pasynUser, epicsFloat64 value)
|
||||||
|
{
|
||||||
|
int function = pasynUser->reason;
|
||||||
|
asynStatus status = asynError;
|
||||||
|
SeleneAxis *pAxis = NULL;
|
||||||
|
char command[64] = {0};
|
||||||
|
char response[64] = {0};
|
||||||
|
char message[132];
|
||||||
|
|
||||||
|
static const char *functionName = "SeleneController::writeFloat64";
|
||||||
|
|
||||||
|
sprintf(message,"%s, reason %d", functionName, function);
|
||||||
|
|
||||||
|
pAxis = (SeleneAxis *)this->getAxis(pasynUser);
|
||||||
|
if (!pAxis) {
|
||||||
|
return asynError;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Set the parameter and readback in the parameter library. */
|
||||||
|
status = pAxis->setDoubleParam(function, value);
|
||||||
|
|
||||||
|
if (function == motorLowLimit_) {
|
||||||
|
sprintf(command, "Q%d54=%f", pAxis->axisNo_, (float)value/(float)MULT);
|
||||||
|
// sprintf(command, "Q%d54=%d", pAxis->axisNo_, (int)(value/pAxis->scale_/MULT));
|
||||||
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
|
||||||
|
"%s: Setting low limit on controller %s, axis %d to %f\n",
|
||||||
|
functionName, portName, pAxis->axisNo_, value);
|
||||||
|
errlogPrintf("Setting low limit of axis %d to %f, command = %s\n", pAxis->axisNo_, value, command);
|
||||||
|
} else if (function == motorHighLimit_) {
|
||||||
|
sprintf(command, "Q%d53=%f", pAxis->axisNo_, (float)value/(float)MULT);
|
||||||
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
|
||||||
|
"%s: Setting high limit on controller %s, axis %d to %f\n",
|
||||||
|
functionName, portName, pAxis->axisNo_, value);
|
||||||
|
errlogPrintf("Setting high limit of axis %d to %f, command = %s\n", pAxis->axisNo_, value, command);
|
||||||
|
} else if(function == setMotorPosition_){
|
||||||
|
snprintf(command,sizeof(command),"Q%d59=%f", pAxis->axisNo_, value);
|
||||||
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
|
||||||
|
"%s: Defining position of axis%d to %f\n",
|
||||||
|
functionName, pAxis->axisNo_, value);
|
||||||
|
errlogPrintf("Defining position of axis %d to %f, command = %s\n", pAxis->axisNo_, value, command);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Execute the command.
|
||||||
|
if (command[0] != 0 && status == asynSuccess) {
|
||||||
|
status = lowLevelWriteRead(pAxis->axisNo_,command, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
// What if now status != asynSuccess
|
||||||
|
|
||||||
|
//Call base class method
|
||||||
|
//This will handle callCallbacks even if the function was handled here.
|
||||||
|
status = asynMotorController::writeFloat64(pasynUser, value);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
asynStatus pmacV3Controller::writeInt32(asynUser *pasynUser, epicsInt32 value) {
|
||||||
|
int function = pasynUser->reason;
|
||||||
|
asynStatus status = asynSuccess;
|
||||||
|
pmacV3Axis *pAxis = NULL;
|
||||||
|
char command[64] = {0};
|
||||||
|
char response[64] = {0};
|
||||||
|
static const char *functionName = "pmacV3Controller::writeInt32";
|
||||||
|
|
||||||
|
debugFlow(functionName);
|
||||||
|
|
||||||
|
pAxis = (pmacV3Axis*)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 == enableAxis_) {
|
||||||
|
if(value == 1) {
|
||||||
|
sprintf(command, "M%2.2d=15\n", pAxis->axisNo_);
|
||||||
|
lowLevelWriteRead(pAxis->axisNo_, command, response);
|
||||||
|
}
|
||||||
|
sprintf(command, "M%2.2d14=%d\n", pAxis->axisNo_, value);
|
||||||
|
asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
|
||||||
|
"%s: Enable axis on controller %s, axis %d enable=%d\n",
|
||||||
|
functionName, portName, pAxis->axisNo_, value);
|
||||||
|
if(value){
|
||||||
|
pAxis->updateMsgTxtFromDriver("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute the command.
|
||||||
|
if (command[0] != 0 && status == asynSuccess) {
|
||||||
|
lowLevelWriteRead(pAxis->axisNo_, command, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pmacController::writeInt32(pasynUser, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
asynStatus pmacV3Controller::readInt32(asynUser *pasynUser, epicsInt32 *value) {
|
||||||
|
|
||||||
|
int function = pasynUser->reason;
|
||||||
|
asynStatus status = asynError;
|
||||||
|
pmacV3Axis *pAxis = NULL;
|
||||||
|
static const char *functionName = "pmacV3Controller::readInt32";
|
||||||
|
char command[128];
|
||||||
|
char response[128];
|
||||||
|
|
||||||
|
debugFlow(functionName);
|
||||||
|
|
||||||
|
pAxis = (pmacV3Axis*)(this->getAxis(pasynUser));
|
||||||
|
if (!pAxis) {
|
||||||
|
return asynError;
|
||||||
|
}
|
||||||
|
if (function == axisEnabled_) {
|
||||||
|
snprintf(command, sizeof(command), "P%2.2d00", pAxis->axisNo_);
|
||||||
|
status = this->lowLevelWriteRead(pAxis->axisNo_, command, response);
|
||||||
|
*value = strtol(response, NULL, 10);
|
||||||
|
|
||||||
|
int st = setIntegerParam(axisEnabled_, *value);
|
||||||
|
callParamCallbacks();
|
||||||
|
}
|
||||||
|
return pmacController::readInt32(pasynUser, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Code for iocsh registration */
|
/* Code for iocsh registration */
|
||||||
|
|
||||||
#ifdef vxWorks
|
#ifdef vxWorks
|
||||||
@ -610,6 +906,18 @@ static void configpmacCreateControllerCallFunc(const iocshArgBuf *args)
|
|||||||
pmacCreateController(args[0].sval, args[1].sval, args[2].ival, args[3].ival, args[4].ival, args[5].ival);
|
pmacCreateController(args[0].sval, args[1].sval, args[2].ival, args[3].ival, args[4].ival, args[5].ival);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const iocshFuncDef configSeleneCreateController = {"SeleneCreateController", 6, pmacCreateControllerArgs};
|
||||||
|
static void configSeleneCreateControllerCallFunc(const iocshArgBuf *args)
|
||||||
|
{
|
||||||
|
SeleneCreateController(args[0].sval, args[1].sval, args[2].ival, args[3].ival, args[4].ival, args[5].ival);
|
||||||
|
}
|
||||||
|
static const iocshFuncDef configpmacV3CreateController = {
|
||||||
|
"pmacV3CreateController", 6, pmacCreateControllerArgs
|
||||||
|
};
|
||||||
|
static void configpmacV3CreateControllerCallFunc(const iocshArgBuf *args) {
|
||||||
|
pmacV3CreateController(args[0].sval, args[1].sval, args[2].ival, args[3].ival,
|
||||||
|
args[4].ival, args[5].ival);
|
||||||
|
}
|
||||||
|
|
||||||
/* pmacCreateAxis */
|
/* pmacCreateAxis */
|
||||||
static const iocshArg pmacCreateAxisArg0 = {"Controller port name", iocshArgString};
|
static const iocshArg pmacCreateAxisArg0 = {"Controller port name", iocshArgString};
|
||||||
@ -623,6 +931,58 @@ static void configpmacAxisCallFunc(const iocshArgBuf *args)
|
|||||||
pmacCreateAxis(args[0].sval, args[1].ival);
|
pmacCreateAxis(args[0].sval, args[1].ival);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* pmacCreateHRPTAxis */
|
||||||
|
static const iocshArg pmacCreateHRPTAxisArg0 = {"Controller port name", iocshArgString};
|
||||||
|
static const iocshArg pmacCreateHRPTAxisArg1 = {"Axis number", iocshArgInt};
|
||||||
|
static const iocshArg * const pmacCreateHRPTAxisArgs[] = {&pmacCreateAxisArg0,
|
||||||
|
&pmacCreateAxisArg1};
|
||||||
|
static const iocshFuncDef configpmacHRPTAxis = {"pmacCreateHRPTAxis", 2, pmacCreateHRPTAxisArgs};
|
||||||
|
|
||||||
|
static void configpmacHRPTAxisCallFunc(const iocshArgBuf *args)
|
||||||
|
{
|
||||||
|
pmacCreateHRPTAxis(args[0].sval, args[1].ival);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* SeleneCreateAxis */
|
||||||
|
static const iocshArg SeleneCreateAxisArg0 = {"Controller port name", iocshArgString};
|
||||||
|
static const iocshArg SeleneCreateAxisArg1 = {"Axis number", iocshArgInt};
|
||||||
|
static const iocshArg SeleneCreateAxisArg2 = {"limitTraget", iocshArgDouble};
|
||||||
|
static const iocshArg * const SeleneCreateAxisArgs[] = {&SeleneCreateAxisArg0,
|
||||||
|
&SeleneCreateAxisArg1,
|
||||||
|
&SeleneCreateAxisArg2};
|
||||||
|
static const iocshFuncDef configSeleneCreateAxis = {"SeleneCreateAxis", 3, SeleneCreateAxisArgs};
|
||||||
|
|
||||||
|
static void configSeleneCreateAxisCallFunc(const iocshArgBuf *args)
|
||||||
|
{
|
||||||
|
SeleneCreateAxis(args[0].sval, args[1].ival,args[2].dval);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* LiftCreateAxis */
|
||||||
|
static const iocshArg LiftCreateAxisArg0 = {"Controller port name", iocshArgString};
|
||||||
|
static const iocshArg LiftCreateAxisArg1 = {"Axis number", iocshArgInt};
|
||||||
|
static const iocshArg * const LiftCreateAxisArgs[] = {&LiftCreateAxisArg0,
|
||||||
|
&LiftCreateAxisArg1};
|
||||||
|
static const iocshFuncDef configLiftAxis = {"LiftCreateAxis", 2, LiftCreateAxisArgs};
|
||||||
|
|
||||||
|
static void configLiftAxisCallFunc(const iocshArgBuf *args)
|
||||||
|
{
|
||||||
|
LiftCreateAxis(args[0].sval, args[1].ival);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pmacV3CreateAxis */
|
||||||
|
static const iocshArg pmacV3CreateAxisArg0 = {"Controller port name",
|
||||||
|
iocshArgString};
|
||||||
|
static const iocshArg pmacV3CreateAxisArg1 = {"Axis number", iocshArgInt};
|
||||||
|
static const iocshArg *const pmacV3CreateAxisArgs[] = {&pmacV3CreateAxisArg0,
|
||||||
|
&pmacV3CreateAxisArg1};
|
||||||
|
static const iocshFuncDef configpmacV3Axis = {"pmacV3CreateAxis", 2,
|
||||||
|
pmacV3CreateAxisArgs};
|
||||||
|
|
||||||
|
static void configpmacV3AxisCallFunc(const iocshArgBuf *args) {
|
||||||
|
pmacV3CreateAxis(args[0].sval, args[1].ival);
|
||||||
|
}
|
||||||
|
|
||||||
/* pmacCreateAxes */
|
/* pmacCreateAxes */
|
||||||
static const iocshArg pmacCreateAxesArg0 = {"Controller port name", iocshArgString};
|
static const iocshArg pmacCreateAxesArg0 = {"Controller port name", iocshArgString};
|
||||||
static const iocshArg pmacCreateAxesArg1 = {"Num Axes", iocshArgInt};
|
static const iocshArg pmacCreateAxesArg1 = {"Num Axes", iocshArgInt};
|
||||||
@ -640,7 +1000,13 @@ static void configpmacAxesCallFunc(const iocshArgBuf *args)
|
|||||||
static void pmacControllerRegister(void)
|
static void pmacControllerRegister(void)
|
||||||
{
|
{
|
||||||
iocshRegister(&configpmacCreateController, configpmacCreateControllerCallFunc);
|
iocshRegister(&configpmacCreateController, configpmacCreateControllerCallFunc);
|
||||||
|
iocshRegister(&configSeleneCreateController, configSeleneCreateControllerCallFunc);
|
||||||
|
iocshRegister(&configpmacV3CreateController, configpmacV3CreateControllerCallFunc);
|
||||||
iocshRegister(&configpmacAxis, configpmacAxisCallFunc);
|
iocshRegister(&configpmacAxis, configpmacAxisCallFunc);
|
||||||
|
iocshRegister(&configpmacHRPTAxis, configpmacHRPTAxisCallFunc);
|
||||||
|
iocshRegister(&configSeleneCreateAxis, configSeleneCreateAxisCallFunc);
|
||||||
|
iocshRegister(&configLiftAxis, configLiftAxisCallFunc);
|
||||||
|
iocshRegister(&configpmacV3Axis, configpmacV3AxisCallFunc);
|
||||||
iocshRegister(&configpmacAxes, configpmacAxesCallFunc);
|
iocshRegister(&configpmacAxes, configpmacAxesCallFunc);
|
||||||
}
|
}
|
||||||
epicsExportRegistrar(pmacControllerRegister);
|
epicsExportRegistrar(pmacControllerRegister);
|
||||||
@ -649,3 +1015,4 @@ epicsExportRegistrar(pmacControllerRegister);
|
|||||||
|
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,23 +7,27 @@
|
|||||||
* Matthew Pearson
|
* Matthew Pearson
|
||||||
* 23 May 2012
|
* 23 May 2012
|
||||||
*
|
*
|
||||||
|
*
|
||||||
|
* Modified to use the MsgTxt field for SINQ
|
||||||
|
*
|
||||||
|
* Mark Koennecke, January 2019
|
||||||
********************************************/
|
********************************************/
|
||||||
|
|
||||||
#ifndef pmacController_H
|
#ifndef pmacController_H
|
||||||
#define pmacController_H
|
#define pmacController_H
|
||||||
|
|
||||||
#include "asynMotorController.h"
|
#include "SINQController.h"
|
||||||
#include "asynMotorAxis.h"
|
#include "asynMotorAxis.h"
|
||||||
#include "pmacAxis.h"
|
#include "pmacAxis.h"
|
||||||
|
|
||||||
#define PMAC_C_GlobalStatusString "PMAC_C_GLOBALSTATUS"
|
#define PMAC_C_GlobalStatusString "PMAC_C_GLOBALSTATUS"
|
||||||
#define PMAC_C_CommsErrorString "PMAC_C_COMMSERROR"
|
#define PMAC_C_CommsErrorString "PMAC_C_COMMSERROR"
|
||||||
|
|
||||||
class pmacController : public asynMotorController {
|
class pmacController : public SINQController {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
pmacController(const char *portName, const char *lowLevelPortName, int lowLevelPortAddress, int numAxes, double movingPollPeriod,
|
pmacController(const char *portName, const char *lowLevelPortName, int lowLevelPortAddress, int numAxes, double movingPollPeriod,
|
||||||
double idlePollPeriod);
|
double idlePollPeriod, const int& extraParams=2);
|
||||||
|
|
||||||
virtual ~pmacController();
|
virtual ~pmacController();
|
||||||
|
|
||||||
@ -45,13 +49,13 @@ class pmacController : public asynMotorController {
|
|||||||
int PMAC_C_GlobalStatus_;
|
int PMAC_C_GlobalStatus_;
|
||||||
int PMAC_C_CommsError_;
|
int PMAC_C_CommsError_;
|
||||||
#define LAST_PMAC_PARAM 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:
|
private:
|
||||||
asynUser* lowLevelPortUser_;
|
asynUser* lowLevelPortUser_;
|
||||||
epicsUInt32 debugFlag_;
|
epicsUInt32 debugFlag_;
|
||||||
asynStatus lowLevelWriteRead(const char *command, char *response);
|
|
||||||
int lowLevelPortConnect(const char *port, int addr, asynUser **ppasynUser, char *inputEos, char *outputEos);
|
int lowLevelPortConnect(const char *port, int addr, asynUser **ppasynUser, char *inputEos, char *outputEos);
|
||||||
void debugFlow(const char *message);
|
|
||||||
|
|
||||||
//static class data members
|
//static class data members
|
||||||
|
|
||||||
@ -132,9 +136,57 @@ class pmacController : public asynMotorController {
|
|||||||
static const epicsUInt32 PMAX_AXIS_GENERAL_PROB2;
|
static const epicsUInt32 PMAX_AXIS_GENERAL_PROB2;
|
||||||
|
|
||||||
friend class pmacAxis;
|
friend class pmacAxis;
|
||||||
|
friend class pmacHRPTAxis;
|
||||||
|
friend class SeleneAxis;
|
||||||
|
friend class LiftAxis;
|
||||||
|
friend class pmacV3Axis;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NUM_PMAC_PARAMS (&LAST_PMAC_PARAM - &FIRST_PMAC_PARAM + 1)
|
#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"
|
||||||
|
|
||||||
|
class pmacV3Controller : public pmacController {
|
||||||
|
public:
|
||||||
|
pmacV3Controller(const char *portName, const char *lowLevelPortName,
|
||||||
|
int lowLevelPortAddress, int numAxes, double movingPollPeriod,
|
||||||
|
double idlePollPeriod, const int &extraParams = 2);
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
pmacV3Axis **pAxes_; /**< Array of pointers to axis objects */
|
||||||
|
|
||||||
|
int enableAxis_;
|
||||||
|
int axisEnabled_;
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* pmacController_H */
|
#endif /* pmacController_H */
|
||||||
|
@ -3,22 +3,22 @@
|
|||||||
#---------------------------------------------
|
#---------------------------------------------
|
||||||
registrar(EL734Register)
|
registrar(EL734Register)
|
||||||
registrar(PhytronRegister)
|
registrar(PhytronRegister)
|
||||||
|
registrar(EuroMoveRegister)
|
||||||
registrar(NanotecRegister)
|
registrar(NanotecRegister)
|
||||||
addpath "/usr/local/epics/support/asyn-4-18/dbd"
|
registrar(pmacControllerRegister)
|
||||||
addpath "/usr/local/epics/dbd"
|
registrar(pmacAsynIPPortRegister)
|
||||||
addpath "/usr/local/epics/support/motor-6-7/dbd"
|
|
||||||
addpath "/usr/local/epics/support/std-3-1/dbd"
|
#--------------------------------------------------------
|
||||||
addpath "/usr/local/epics/anc350v17/dbd"
|
# With the PSI module build system, including these items actually
|
||||||
include "drvAsynIPPort.dbd"
|
# hurts. It causes missing symbols when loading the shared lib.
|
||||||
include "motorRecord.dbd"
|
#------------------------------------------------------------------
|
||||||
include "motorSupport.dbd"
|
#include "/ioc/modules/asyn/427.0.1/R3.14.12/dbd/asyn.dbd"
|
||||||
include "anc350AsynMotor.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"
|
||||||
|
|
||||||
include "scalerRecord.dbd"
|
|
||||||
device(scaler,INST_IO,devScalerEL737,"asynScalerEL737")
|
device(scaler,INST_IO,devScalerEL737,"asynScalerEL737")
|
||||||
|
|
||||||
#--------- For lakeshore
|
#--------- For lakeshore and magnets
|
||||||
addpath "/usr/local/epics/support/StreamDevice-2-6/dbd"
|
#include "/ioc/modules/stream/2.7.9/R3.14.12/dbd/stream.dbd"
|
||||||
include "stream.dbd"
|
#include "busy.dbd"
|
||||||
addpath "/usr/local/epics/support/busy-1-4/dbd"
|
|
||||||
include "busySupport.dbd"
|
|
||||||
|
88
testEuroMoveUsb.py
Executable file
88
testEuroMoveUsb.py
Executable file
@ -0,0 +1,88 @@
|
|||||||
|
#!/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)
|
7
testcter/startcter.cmd
Normal file
7
testcter/startcter.cmd
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
require sinq,koennecke
|
||||||
|
|
||||||
|
epicsEnvSet("TOP","/afs/psi.ch/project/sinqdev/sinqepicsapp")
|
||||||
|
|
||||||
|
drvAsynIPPortConfigure("cter1","localhost:62000",0,0,0)
|
||||||
|
dbLoadRecords("asynRecord.db","P=KM36:,R=cter1,PORT=cter1,ADDR=0,OMAX=80,IMAX=80")
|
||||||
|
dbLoadRecords("${TOP}/sinqEPICSApp/Db/el737Record.db","P=KM36:counter,PORT=cter1,DESC=KM36Counter")
|
Reference in New Issue
Block a user