20 Commits

Author SHA1 Message Date
7023f52336 Modified devScalerEL737 to process threshold and thresholdcounter as fields external to
the scaler record. This is to replace the preset hack previously used to implement this
functionality.
2017-08-21 16:30:15 +02:00
83a995a16d Fixed the value reading bug in devScalerEL737 (wrong function signature)
Nihkil added mor error codes to devScalerEL737
2017-08-21 14:42:09 +02:00
124aa97cd6 Fixed a bug in el737_read which had a wrong function signature. May have changed over the years.
This caused every second monitor to be 0. A number type mismatch.
2017-08-14 14:52:04 +02:00
bd3b808312 Commented the various Makefiles to say what they are for. 2017-08-09 16:51:38 +02:00
9a3b0f7666 Improved error reporting to the MsgTxt additional field 2017-08-08 17:32:32 +02:00
0eed0c9357 Fixed bad logic in devScalerEL7373.c:connectSlaveRecords() which caused a core dump when accessing non existing
slave records
2017-07-25 08:01:27 +02:00
7263a0772f Added support for an addition Pause, Status and MsgTxt field to the EL737 scaler driver 2017-07-24 09:45:57 +02:00
9c507a05ba Merge branch 'errtxt'
Also made sinqepicsApp work with the module based build system now being operational at PSI
Conflicts:
	iocBoot/iocsinqEPICS/envPaths
	iocBoot/iocsinqEPICS/st.cmd
	sinqEPICSApp/src/Makefile
2017-07-04 08:38:40 +02:00
dc966bc976 Merge branch 'ess' 2017-05-17 11:23:50 +02:00
edd3005f85 Merge branch 'phytron' 2017-05-17 11:22:43 +02:00
af4d16d25f Implemented a feature which allows for an additional field for having a text message
with a motor axis. To this purpose a new derived class SINQAxis and SINQController were
added which other drivers using this feature can derive from. The proof of concept and
test platform is the EL734 driver.
2017-03-20 16:40:25 +01:00
6ea6fdcb85 I added a driver for the EL755 magnet controller using streamdevice 2017-03-07 16:37:19 +01:00
389e7f9157 The ESS module version is now working!
References DM-89
2017-02-17 11:09:23 +01:00
8858761e74 I now have a ESS style module Makefile.EEE which compiles.... I just do not yet know if it
works.....
2017-02-14 17:21:39 +01:00
2950f21353 Added support for the dimetix distance measurement device
Refs #DM-93
2016-08-09 15:36:22 +02:00
28999f2212 Added support for the AMOR SPS-S5 using streamdevice 2016-08-04 14:38:50 +02:00
7c1693e606 Added support for the AMOR SLS VME Magnet controllers to the sinq IOC application
refs #DM-91
2016-07-08 13:53:21 +02:00
c75957f284 The SINQ IOC working in the ESS EPICS environment 2016-06-16 15:20:55 +02:00
8f0c240e76 Removed unnecessary stuff from the Makefile which was introduced while trying to get this to compile 2016-06-03 16:54:30 +02:00
5dff3bc23b First compile on the ESS EPICS environment. Success for the motor code.
Still missing:
   * scaler support
   * cleanup of Makefile
2016-06-03 16:52:02 +02:00
36 changed files with 1101 additions and 112 deletions

View File

@ -1,3 +1,4 @@
# This is for building the IOC application against the EEE-setup
#Makefile at top of application tree
TOP = .
include $(TOP)/configure/CONFIG

33
Makefile.EEE Normal file
View 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

33
Makefile.RHEL7 Normal file
View File

@ -0,0 +1,33 @@
# This build the sinq extensions for the PSI EPICS setup
include /ioc/tools/driver.makefile
MODULE=sinq
BUILDCLASSES=Linux
# additional module dependencies
REQUIRED+=SynApps
REQUIRED+=stream
# 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/pmacAsynIPPort.c
SOURCES += sinqEPICSApp/src/pmacAxis.cpp
SOURCES += sinqEPICSApp/src/pmacController.cpp
# MISCS would be the place to keep the stream device template files

View File

@ -32,3 +32,5 @@ INSTALL_LOCATION=/afs/psi.ch/project/sinqdev/sinqepicsapp
# You must rebuild in the iocBoot directory for this to
# take effect.
#IOCS_APPL_TOP = </IOC/path/to/application/top>
STATIC_BUILD=NO
SHARED_LIBRARIES=YES

View File

@ -25,16 +25,17 @@ TEMPLATE_TOP=$(EPICS_BASE)/templates/makeBaseApp/top
#SNCSEQ=$(EPICS_BASE)/../modules/soft/seq
# EPICS_BASE usually appears last so other apps can override stuff:
EPICS_BASE=/usr/local/epics
EPICS_BASE=/opt/epics/bases/base-3.14.12.5
# Set RULES here if you want to take build rules from somewhere
# other than EPICS_BASE:
#RULES=/path/to/epics/support/module/rules/x-y
MOTOR=/usr/local/epics/support/motor-6-7
ASYN=/usr/local/epics/support/asyn-4-18
STD=/usr/local/epics/support/std-3-1
ANC=/usr/local/epics/anc350v17
STREAMS=/usr/local/epics/support/StreamDevice-2-6
LAKESHORE336=/usr/local/epics/support/lakeshore336
BUSY=/usr/local/epics/support/busy-1-4
OXINSTCRYOJET=/usr/local/epics/support/OxInstCryojet-2-18-3
MOTOR=/opt/epics/modules/motor/6.10.0/3.14.12.5
ASYN=/opt/epics/modules/asyn/4.27.0/3.14.12.5
SYNAPPSSTD=/opt/epics/modules/synAppsStd/3.4.1/3.14.12.5/
#ANC=/usr/local/epics/anc350v17
STREAMS=/opt/epics/modules/streamdevice/2.6.0/3.14.12.5
#LAKESHORE336=/usr/local/epics/support/lakeshore336
BUSY=/opt/epics/modules/busy/1.6.0/3.14.12.5
#OXINSTCRYOJET=/usr/local/epics/support/OxInstCryojet-2-18-3
PCRE=/opt/epics/modules/pcre/8.36.0/3.14.12.5

61
essst.cmd Executable file
View 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"

View File

@ -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")

View File

@ -1,10 +1,21 @@
file "$(MOTOR)/db/basic_asyn_motor.db"
{
pattern
{P, N, M, DTYP, PORT, ADDR, DESC, EGU, DIR, VELO, VBAS, ACCL, BDST, BVEL, BACC, MRES, PREC, DHLM, DLLM, INIT}
{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:, 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:, 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, ""}
}
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}
}

View File

@ -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
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")
#---------- load EL734 motor controller
drvAsynIPPortConfigure("serial1", "narziss-ts:3002",0,0,0)
#drvAsynIPPortConfigure("serial1", "localhost:8080",0,0,0)
EL734CreateController("mota","serial1",6);
#---------- 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("$(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")
cd ${TOP}/iocBoot/${IOC}
dbLoadTemplate "motor.substitutions.el734"
dbLoadTemplate "mota.substitutions"
dbLoadTemplate "motb.substitutions"
dbLoadTemplate "motc.substitutions"
#--------- load EL737 counter box
drvAsynIPPortConfigure("cter1","narziss-ts:3003",0,0,0)
dbLoadRecords("$(ASYN)/db/asynRecord.db","P=NZ:,R=cter1,PORT=cter1,ADDR=0,OMAX=80,IMAX=80")
drvAsynIPPortConfigure("cter1","localhost:62000",0,0,0)
dbLoadRecords("$(ASYN)/db/asynRecord.db","P=SQ:AMOR:,R=cter1,PORT=cter1,ADDR=0,OMAX=80,IMAX=80")
dbLoadRecords("${TOP}/db/el737Record.db")
asynSetTraceIOMask("cter1",0,2)
#asynSetTraceIOMask("cter1",0,2)
iocInit

View 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"

View 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"

View 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
View 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
View 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

View File

@ -10,7 +10,7 @@ include $(TOP)/configure/CONFIG
#----------------------------------------------------
# Create and install (or just install) into <top>/db
# databases, templates, substitutions like this
#DB += xxx.db
DB_INSTALL += slsvme.proto
#----------------------------------------------------
# If <anyname>.db template is not named <anyname>*.template add

View 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")
}

View 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"}
}

View 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
View 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")
}

View 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 "";
}

View File

@ -0,0 +1,9 @@
# 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")
}

94
sinqEPICSApp/Db/slsvme.db Normal file
View 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")
}

View 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";
}

View 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")
}

View 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";
}

View File

@ -5,6 +5,10 @@ USAGE... Motor driver support for the PSI EL734 controller.
Mark Koennecke
February 2013
Updated to have an MsgTxt field through SINQAxis, error handling
Mark Koennecke, May, August 2017
*/
@ -33,18 +37,14 @@ February 2013
* \param[in] numAxes The number of axes that this controller supports
*/
EL734Controller::EL734Controller(const char *portName, const char *EL734PortName, int numAxes)
: asynMotorController(portName, numAxes+1, 0,
0, // No additional interfaces beyond those in base class
0, // No additional callback interfaces beyond those in base class
ASYN_CANBLOCK | ASYN_MULTIDEVICE,
1, // autoconnect
0, 0) // Default priority and stack size
: SINQController(portName, EL734PortName, numAxes)
{
int axis;
asynStatus status;
EL734Axis *pAxis;
static const char *functionName = "EL734Controller::EL734Controller";
/* Connect to EL734 controller */
status = pasynOctetSyncIO->connect(EL734PortName, 0, &pasynUserController_, NULL);
if (status) {
@ -138,18 +138,22 @@ void EL734Controller::switchRemote()
* \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;
size_t in, out, i;
int reason;
char myReply[COMLEN];
char myReply[COMLEN], errTxt[256];
SINQAxis *axis = getAxis(axisNo);
pasynOctetSyncIO->flush(pasynUserController_);
status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
reply,COMLEN, 1.,&out,&in,&reason);
if(status != asynSuccess){
if(axis!= NULL){
axis->updateMsgTxtFromDriver("Lost connection to motor controller");
}
return status;
}
@ -178,13 +182,25 @@ asynStatus EL734Controller::transactController(char command[COMLEN], char reply[
myReply[i] = (char)tolower((int)reply[i]);
}
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;
} 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;
} 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;
}
@ -200,8 +216,7 @@ asynStatus EL734Controller::transactController(char command[COMLEN], char reply[
* Initializes register numbers, etc.
*/
EL734Axis::EL734Axis(EL734Controller *pC, int axisNo)
: asynMotorAxis(pC, axisNo),
pC_(pC)
: SINQAxis(pC, axisNo), pC_(pC)
{
}
@ -239,7 +254,7 @@ asynStatus EL734Axis::move(double position, int relative, double minVelocity, do
oredMSR = 0;
homing = 0;
sprintf(command, "p %d %.3f", axisNo_, position/1000.);
status = pC_->transactController(command,reply);
status = pC_->transactController(axisNo_,command,reply);
next_poll = -1;
return status;
}
@ -255,7 +270,7 @@ asynStatus EL734Axis::home(double minVelocity, double maxVelocity, double accele
sprintf(command, "R %d", axisNo_);
homing = 1;
next_poll= -1;
status = pC_->transactController(command,reply);
status = pC_->transactController(axisNo_,command,reply);
return status;
}
@ -277,7 +292,7 @@ asynStatus EL734Axis::moveVelocity(double minVelocity, double maxVelocity, doubl
/* This is a negative move */
sprintf(command, "FB %d", axisNo_);
}
status = pC_->transactController(command,reply);
status = pC_->transactController(axisNo_,command,reply);
next_poll = -1;
return status;
}
@ -289,8 +304,9 @@ asynStatus EL734Axis::stop(double acceleration )
char command[COMLEN], reply[COMLEN];
sprintf(command, "S %d", axisNo_);
status = pC_->transactController(command,reply);
status = pC_->transactController(axisNo_,command,reply);
errlogPrintf("Sent STOP on Axis %d\n", axisNo_);
updateMsgTxtFromDriver("Axis interrupted");
return status;
}
@ -302,7 +318,7 @@ asynStatus EL734Axis::setPosition(double position)
char command[COMLEN], reply[COMLEN];
sprintf(command, "P %d %f", axisNo_, position/1000.);
status = pC_->transactController(command,reply);
status = pC_->transactController(axisNo_,command,reply);
next_poll = -1;
return status;
@ -328,9 +344,10 @@ asynStatus EL734Axis::setClosedLoop(bool closedLoop)
* \param[out] moving A flag that is set indicating that the axis is moving (true) or done (false). */
asynStatus EL734Axis::poll(bool *moving)
{
int msr;
int msr, count;
asynStatus comStatus;
char command[COMLEN], reply[COMLEN];
char command[COMLEN], reply[COMLEN], errTxt[256];
int driverError = 0;
// protect against excessive polling
@ -341,19 +358,32 @@ asynStatus EL734Axis::poll(bool *moving)
// Read the current motor position
sprintf(command,"u %d", axisNo_);
comStatus = pC_->transactController(command,reply);
comStatus = pC_->transactController(axisNo_,command,reply);
if(comStatus == asynError){
driverError = 1;
}
if(comStatus) goto skip;
if(strstr(reply,"*ES") != NULL){
*moving = false;
setIntegerParam(pC_->motorStatusDone_, true);
setIntegerParam(pC_->motorStatusProblem_, true);
updateMsgTxtFromDriver("Emergency Stop Engaged");
driverError = 1;
goto skip;
} else if(strstr(reply,"?BSY") != NULL){
*moving = true;
setIntegerParam(pC_->motorStatusDone_, false);
updateMsgTxtFromDriver(NULL);
goto skip;
}
count = sscanf(reply,"%lf", &position);
if(count != 1) {
snprintf(errTxt,sizeof(errTxt),"Bad reply %s when reading position for %d", reply, axisNo_);
updateMsgTxtFromDriver(errTxt);
comStatus = asynError;
driverError =1;
goto skip;
}
sscanf(reply,"%lf", &position);
//errlogPrintf("Axis %d, reply %s, position %lf\n", axisNo_, reply, position);
setDoubleParam(pC_->motorPosition_, position*1000);
//setDoubleParam(pC_->motorEncoderPosition_, position);
@ -361,7 +391,7 @@ asynStatus EL734Axis::poll(bool *moving)
// Read the moving status of this motor
sprintf(command,"msr %d",axisNo_);
comStatus = pC_->transactController(command,reply);
comStatus = pC_->transactController(axisNo_,command,reply);
if(comStatus) goto skip;
sscanf(reply,"%x",&msr);
// errlogPrintf("Axis %d, reply %s, msr %d, position = %lf\n",
@ -373,11 +403,15 @@ asynStatus EL734Axis::poll(bool *moving)
next_poll = time(NULL)+IDLEPOLL;
if(oredMSR & 0x10){
setIntegerParam(pC_->motorStatusLowLimit_, true);
updateMsgTxtFromDriver("Lower Limit Hit");
driverError = 1;
} else {
setIntegerParam(pC_->motorStatusLowLimit_, false);
}
if(oredMSR & 0x20){
setIntegerParam(pC_->motorStatusHighLimit_, true);
updateMsgTxtFromDriver("Upper Limit Hit");
driverError = 1;
} else {
setIntegerParam(pC_->motorStatusHighLimit_, false);
}
@ -388,20 +422,29 @@ asynStatus EL734Axis::poll(bool *moving)
if(oredMSR &0x1000){
setIntegerParam(pC_->motorStatusProblem_, true);
errlogSevPrintf(errlogMajor, "Air cushion problem on %d", axisNo_);
updateMsgTxtFromDriver("Air cushion error");
driverError = 1;
}
if(oredMSR &0x80){
setIntegerParam(pC_->motorStatusProblem_, true);
errlogSevPrintf(errlogMajor, "Positioning fault at %d", axisNo_);
updateMsgTxtFromDriver("Positioning fault");
driverError = 1;
}
*moving = false;
setIntegerParam(pC_->motorStatusDone_, true);
//updateMsgTxtFromDriver("Believed to be on position");
} else {
*moving = true;
next_poll = -1;
setIntegerParam(pC_->motorStatusDone_, false);
//updateMsgTxtFromDriver("Creeping");
}
skip:
if(driverError == 0){
updateMsgTxtFromDriver(NULL);
}
setIntegerParam(pC_->motorStatusProblem_, comStatus ? 1:0);
callParamCallbacks();
return comStatus ? asynError : asynSuccess;

View File

@ -7,13 +7,13 @@ February 2013
*/
#include "asynMotorController.h"
#include "asynMotorAxis.h"
#include "SINQController.h"
#include "SINQAxis.h"
#define MAX_EL734_AXES 12
#define COMLEN 80
class EL734Axis : public asynMotorAxis
class EL734Axis : public SINQAxis
{
public:
/* These are the methods we override from the base class */
@ -34,11 +34,14 @@ private:
double position;
int homing;
time_t next_poll;
int ErrTxtIdx;
void forwardErrorTxt(EL734Axis *axis);
friend class EL734Controller;
};
class EL734Controller : public asynMotorController {
class EL734Controller : public SINQController {
public:
EL734Controller(const char *portName, const char *EL734PortName, int numAxes);
@ -50,7 +53,7 @@ friend class EL734Axis;
private:
asynUser *pasynUserController_;
asynStatus transactController(char command[COMLEN], char reply[COMLEN]);
asynStatus transactController(int axis, char command[COMLEN], char reply[COMLEN]);
void switchRemote();

View File

@ -17,14 +17,14 @@ sinqEPICS_DBD += base.dbd
# Include dbd files from all support applications:
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
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_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 += NanotecDriver.cpp stptok.cpp
sinqEPICS_SRCS += PhytronDriver.cpp

View File

@ -0,0 +1,36 @@
/*
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)
{
}
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);
}
}
/**
* 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);
}

View 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

View 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)
: asynMotorController(portName, numAxes+1, NUM_MOTOR_DRIVER_PARAMS+2,
0, // No additional interfaces beyond those in base class
0, // No additional callback interfaces beyond those in base class
ASYN_CANBLOCK | ASYN_MULTIDEVICE,
1, // autoconnect
0, 0) // Default priority and stack size
{
createParam(motorMessageIsFromDriverString, asynParamInt32, &motorMessageIsFromDriver_);
createParam(motorMessageTextString, asynParamOctet, &motorMessageText_);
}

View 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);
friend class SINQAxis;
protected:
int motorMessageIsFromDriver_;
int motorMessageText_;
};
#endif

View File

@ -19,7 +19,7 @@
* - Thresholding
* - two count modes
* 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.
*
* The driver will run a separate thread which does all the
@ -27,6 +27,16 @@
*
* Mark Koennecke, February 2013
*
* Enhanced by adding an addtional external pause and status flag in the databse and code in here
* to handle this. Moreover an external MsgTxt field in the DB can be filled with an error message.
*
* Mark Koennecke, July 2017
*
* 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>
@ -40,6 +50,10 @@
#include <recSup.h>
#include <devSup.h>
#include <cantProceed.h>
#include <dbDefs.h>
#include <dbFldTypes.h>
#include <dbAccess.h>
#include <errlog.h>
#include <scalerRecord.h>
#include <devScaler.h>
@ -49,7 +63,7 @@
/* dset functions */
static long el737_init_record(struct scalerRecord *psr, CALLBACK *pcallback);
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_arm(scalerRecord *psr, int val);
static long el737_done(scalerRecord *psr);
@ -84,17 +98,87 @@ typedef struct {
unsigned long values[NCOUNT];
unsigned int countCommand;
unsigned int counting;
unsigned long thresholdValue;
unsigned int sendThreshold;
scalerRecord *psr;
epicsEventId wakeUp;
asynUser *asynContext;
CALLBACK *pcallback;
DBADDR pause;
DBADDR status;
DBADDR msgTxt;
DBADDR threshCounter;
DBADDR threshold;
unsigned int dbInit;
}EL737priv;
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->status.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->status.precord->name);
}
}
static long el737_init_record(scalerRecord *psr, CALLBACK *pcallback)
{
EL737priv *priv = NULL;
@ -122,7 +206,9 @@ static long el737_init_record(scalerRecord *psr, CALLBACK *pcallback)
priv->psr = psr;
priv->wakeUp = epicsEventCreate(epicsEventEmpty);
priv->pcallback = pcallback;
priv->dbInit = 0;
psr->dpvt = priv;
/*
* Hook up with device
@ -148,6 +234,8 @@ static long el737_init_record(scalerRecord *psr, CALLBACK *pcallback)
pasynOctetSyncIO->setInputEos(priv->asynContext,"\r",strlen("\r"));
priv->asynContext->timeout = 1.0;
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),
reply,sizeof(reply), 1.,&out,&in,&reason);
strcpy(command,"ECHO 2");
@ -155,6 +243,7 @@ static long el737_init_record(scalerRecord *psr, CALLBACK *pcallback)
reply,sizeof(reply), 1.,&out,&in,&reason);
pasynManager->freeAsynUser(dummyUser);
connectSlaveRecords(priv);
/*
start the thread which actually runs the device
@ -181,14 +270,14 @@ static long el737_reset(scalerRecord *psr)
return 0;
}
static long el737_read(scalerRecord *psr, unsigned long *val)
static long el737_read(scalerRecord *psr, epicsUInt32 *val)
{
unsigned int i;
EL737priv *priv;
priv = (EL737priv *)psr->dpvt;
for(i = 0; i < NCOUNT; i++){
val[i] = priv->values[i];
val[i] = (epicsUInt32)priv->values[i];
}
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;
size_t in, out;
int reason;
char myCommand[COMLEN];
int reason, dbStatus;
char myCommand[COMLEN], message[40];
pasynOctetSyncIO->flush(asynContext);
pasynOctetSyncIO->flush(priv->asynContext);
status = pasynOctetSyncIO->writeRead(asynContext, command, strlen(command),
strcpy(message,"OK");
status = pasynOctetSyncIO->writeRead(priv->asynContext, command, strlen(command),
reply,COMLEN, 1.,&out,&in,&reason);
if(status == asynSuccess){
if(strstr(reply,"?OF") != NULL){
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);
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);
return pasynOctetSyncIO->writeRead(asynContext, command, strlen(command),
return pasynOctetSyncIO->writeRead(priv->asynContext, command, strlen(command),
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;
@ -276,21 +401,56 @@ static asynStatus sendStop(EL737priv *priv)
char command[COMLEN], reply[COMLEN];
//errlogPrintf("Sending stop\n");
strcpy(command,"S");
return el737_transactCommand(priv->asynContext,command,reply);
return el737_transactCommand(priv,command,reply);
}
static void runEvents(EL737priv *priv)
{
char command[COMLEN], reply[COMLEN];
char command[COMLEN], reply[COMLEN], errName[256];
int status;
long dbStatus, myThreshold, nElements = 1, options = 0, threshCounter;
/*
This is the better way to set the threshold rather then the old way below which uses
presets for that function. This one uses separate fields.
*/
if(priv->dbInit == 1) {
dbStatus = dbGetField(&priv->threshold,DBR_LONG,&myThreshold,&options, &nElements,NULL);
if(dbStatus != 0){
errSymLookup(dbStatus,errName,sizeof(errName));
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 {
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){
sprintf(command,"DL %d %d", (int)priv->presets[THRESHMON],
(int)priv->presets[THRESHVAL]);
//errlogPrintf("Sending threshold command %s\n", command);
status = el737_transactCommand(priv->asynContext,command,reply);
status = el737_transactCommand(priv,command,reply);
sprintf(command,"DR %d", (int)priv->presets[THRESHMON]);
status = el737_transactCommand(priv->asynContext,command,reply);
status = el737_transactCommand(priv, command,reply);
if(status == asynSuccess){
priv->sendThreshold = 0;
}
@ -307,7 +467,7 @@ static void runEvents(EL737priv *priv)
sprintf(command,"TP %f", priv->presets[TIMER]/1000.);
//errlogPrintf("Starting preset timer\n");
}
status = el737_transactCommand(priv->asynContext,command,reply);
status = el737_transactCommand(priv,command,reply);
if(status == asynSuccess){
priv->counting = 1;
}
@ -335,7 +495,7 @@ static void updateValues(EL737priv *priv)
long m1, m2 ,m3, m4, m5, m6 ,m7, m8;
strcpy(command,"RA");
status = el737_transactCommand(priv->asynContext,command,reply);
status = el737_transactCommand(priv,command,reply);
if(status != asynSuccess){
errlogPrintf("devScalerEL737::el737Thread communication problem %s\n",
priv->asynContext->errorMessage);
@ -371,9 +531,10 @@ static void el737Thread(void *param)
EL737priv *priv = (EL737priv *)param;
epicsEventWaitStatus evStatus;
double timeout = 60.;
char command[COMLEN], reply[COMLEN];
char command[COMLEN], reply[COMLEN], errName[256];
asynStatus status;
int rs;
int rs, ctStatus;
long dbStatus, options, nElements = 1, pauseFlag = 0;
//errlogPrintf("Within EL737 thread \n");
@ -381,6 +542,7 @@ static void el737Thread(void *param)
evStatus = epicsEventWaitWithTimeout(priv->wakeUp,timeout);
//errlogPrintf("EL737 thread woke up with %d\n", evStatus);
if(evStatus == epicsEventWaitOK) {
/*
FEAR: we received a command!!!!
@ -402,7 +564,7 @@ static void el737Thread(void *param)
if(priv->counting) {
strcpy(command,"RS");
status = el737_transactCommand(priv->asynContext,command,reply);
status = el737_transactCommand(priv, command,reply);
if(status != asynSuccess){
errlogPrintf("devScalerEL737::el737Thread communication problem %s\n",
priv->asynContext->errorMessage);
@ -414,15 +576,57 @@ static void el737Thread(void *param)
priv->counting = 0;
timeout = 60.;
priv->values[9] = 0;
ctStatus = 0;
} else if(rs == 1 || rs == 2){
/* counting */
priv->values[9] = 1;
ctStatus = 1;
} else if(rs == 5 || rs == 6){
/* low rate */
priv->values[9] = 2;
ctStatus = 2;
} else if(rs == 9 || rs == 13 || rs == 10 || rs == 14){
/* low rate */
priv->values[9] = 2;
/* paused states */
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;
}
}
}

View File

@ -1,9 +1,19 @@
record(scaler,"")
record(bo,"$(P):Pause")
{
field(NAME,"NZ:counter")
field(DESC,"NARZIS EL737 counter")
field(DTYP,"asynScalerEL737")
field(OUT,"INST_IO @asyn(cter1,0)"
field(DTYP,"Soft Channel")
}
record(longin,"$(P):Status")
{
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)")
}

View File

@ -4,21 +4,19 @@
registrar(EL734Register)
registrar(PhytronRegister)
registrar(NanotecRegister)
addpath "/usr/local/epics/support/asyn-4-18/dbd"
addpath "/usr/local/epics/dbd"
addpath "/usr/local/epics/support/motor-6-7/dbd"
addpath "/usr/local/epics/support/std-3-1/dbd"
addpath "/usr/local/epics/anc350v17/dbd"
include "drvAsynIPPort.dbd"
include "motorRecord.dbd"
include "motorSupport.dbd"
include "anc350AsynMotor.dbd"
registrar(pmacControllerRegister)
#--------------------------------------------------------
# With the PSI module build system, including these items actually
# hurts. It causes missing symbols when loading the shared lib.
#------------------------------------------------------------------
#include "/ioc/modules/asyn/427.0.1/R3.14.12/dbd/asyn.dbd"
#include "/ioc/modules/motorBase/6.9.12/R3.14.12/dbd/motorBase.dbd"
#include "/ioc/modules/SynApps/1.13.0/R3.14.12/dbd/SynApps.dbd"
#include "/ioc/modules/scaler/koennecke/R3.14.12/dbd/scaler.dbd"
include "scalerRecord.dbd"
device(scaler,INST_IO,devScalerEL737,"asynScalerEL737")
#--------- For lakeshore
addpath "/usr/local/epics/support/StreamDevice-2-6/dbd"
include "stream.dbd"
addpath "/usr/local/epics/support/busy-1-4/dbd"
include "busySupport.dbd"
#--------- For lakeshore and magnets
#include "/ioc/modules/stream/2.7.9/R3.14.12/dbd/stream.dbd"
#include "busy.dbd"

7
testcter/startcter.cmd Normal file
View 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")