4 Commits

Author SHA1 Message Date
cc88331652 Merge branch 'el737' into amorsim 2017-08-24 13:50:06 +02:00
c445af75c1 Merge branch 'el737' into amorsim
Port the fix to the el737 driver into this branch
2017-08-14 14:53:35 +02:00
ebc3de1bd2 Merge branch 'master' into amorsim 2017-08-09 16:52:12 +02:00
73c9c98329 Recovered the sinq.dbdb file for the SINQ ioc to work again 2017-08-09 16:48:39 +02:00
40 changed files with 578 additions and 3342 deletions

121
.gitignore vendored
View File

@@ -1,121 +0,0 @@
# Took these from the https://github.com/github/gitignore project on October 21, 2011
# **** 'Personal' entries don't belong in here - put them in your .git/info/exclude file ****
# Ignore text editor (e.g. emacs) autosave files
*~
# 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
._*

View File

@@ -1 +0,0 @@
SUBSYSTEM=="usb", ATTR{idVendor}=="04b4", ATTR{idProduct}=="1002", MODE="0666" GROUP="plugdev", TAG+="uaccess"

View File

@@ -1,22 +0,0 @@
# This Makefile has to be executed in the synApps-xxx/support/autosave-xxx directory.
# It creates a autosave module to load into iocsh
include /ioc/tools/driver.makefile
MODULE=autosave
BUILDCLASSES=Linux
USR_DEPENDENCIES=
SOURCES += asApp/src/dbrestore.c
SOURCES += asApp/src/save_restore.c
SOURCES += asApp/src/initHooks.c
SOURCES += asApp/src/fGetDateStr.c
SOURCES += asApp/src/configMenuSub.c
SOURCES += asApp/src/verify.c
SOURCES += asApp/src/asVerify.c
SOURCES += asApp/src/os/Linux/osdNfs.c
HEADERS += asApp/src/os/Linux/osdNfs.h
DBDS += asApp/src/asSupport.dbd

View File

@@ -1,17 +0,0 @@
include /ioc/tools/driver.makefile
MODULE=scaler
BUILDCLASSES=Linux
USR_DEPENDENCIES = asyn,427.0.1
SOURCES += stdApp/src/scalerRecord.c
SOURCES += stdApp/src/devScalerAsyn.c
SOURCES += stdApp/src/drvScalerSoft.c
HEADERS += devScaler.h
DBDS += stdApp/src/scalerRecord.dbd
DBDS += stdApp/src/scalerSupport.dbd

View File

@@ -2,14 +2,12 @@
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
@@ -28,7 +26,6 @@ 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

View File

@@ -1,37 +0,0 @@
# 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

View File

@@ -1,40 +0,0 @@
# SinqEPICSApp
This is an IOC application which contains the drivers for SINQ hardware.
EPICS purists may find it messy because it contains the drivers for all
SINQ stuff in one package rather then in separate modules. This is just
for ease of distribution. The idea being that all of SINQ shares one
module/IOC application and configures in its startup file what it needs
of it.
Drivers included:
- EL734 motor controller
- SINQ Delta Tau PMAC motor controller. This is a modified version of the Diamond
PMAC code. The modification is necessary because PSI runs a different program in
the MCU at SINQ then Diamond
- Nanotec bus motor driver
- Phytron MCU200 motor driver
- EL737 counter box driver through the scaler record
There are some streamdevice protocol files provided:
- spss5: for the Siemens SPS5 with the PSI custom RS232 module
- slsvme: for the SLS magnet controllers managed by the SINQ special vmemaggi program
- el755: the old SINQ magnet controller
- dimetix: for the deimetix distance measurement device at AMOR
There are two main branches here:
- Of course master from which you can build the PSI RHEL7 module and the EEE module
- The amorsim branch in which you can build the IOC application for ESS against the ICS
setup. This is needed for the sinq-amorsim simulation. This branch exists because of the
political problem to get a module into the ICS EEE setup.
Those political problems require a special development model:
1. If you do something, do it in a separate branch
2. When reasonably sure that what you did works, merge it both into master and amorsim
Take care of the sinqEPICsApp/src/sinq.dbd file. This is the one which differs mostly between
amorsim and master branches.

View File

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

View File

@@ -1,23 +0,0 @@
#!/usr/local/bin/iocsh
require sinq,koennecke
epicsEnvSet("TOP","/afs/psi.ch/project/sinqdev/sinqepicsapp/iocBoot/iocsinqEPICS")
epicsEnvSet("BASE","/afs/psi.ch/project/sinqdev/sinqepicsapp")
cd ${TOP}
drvAsynIPPortConfigure("serial1", "129.129.195.83:1234",0,0,0)
#drvAsynIPPortConfigure("serial1", "amor-ts:3002",0,0,0)
#drvAsynIPPortConfigure("serial1", "localhost:9090",0,0,0)
EuroMoveCreateController("llb","serial1", 10, 1);
### Motors
dbLoadRecords("$(BASE)/sinqEPICSApp/Db/asynRecord.db","P=KM36:,R=serial1,PORT=serial1,ADDR=0,OMAX=80,IMAX=80")
dbLoadTemplate "motor.substitutions.eurollb"
iocInit

View File

@@ -1,4 +1,4 @@
qfile "$(MOTOR)/db/basic_asyn_motor.db"
file "$(MOTOR)/db/basic_asyn_motor.db"
{
pattern
{P, N, M, DTYP, PORT, ADDR, DESC, EGU, DIR, VELO, VBAS, ACCL, BDST, BVEL, BACC, MRES, PREC, DHLM, DLLM, INIT}

View File

@@ -1,13 +0,0 @@
file "$(BASE)/sinqEPICSApp/Db/basic_asyn_motor.db"
{
pattern
{P, N, M, DTYP, PORT, ADDR, DESC, EGU, DIR, VELO, VBAS, ACCL, BDST, BVEL, BACC, MRES, PREC, RDBD, DHLM, DLLM, INIT}
{KM36:llb:, 1, "m$(N)", "asynMotor", llb, 1, "m1", mm, Pos, 2.0, 0.1, .2, 0, 1, .2, .01, 3, 0.2, 1000, 0, "1"}
}
file "$(BASE)/sinqEPICSApp/Db/motorMessage.db"
{
pattern
{P,N, M,PORT}
{KM36:llb:, 1, "m$(N)",llb}
}

View File

@@ -1,15 +1,7 @@
file "$(BASE)/sinqEPICSApp/Db/basic_asyn_motor.db"
file "$(MOTOR)/db/basic_asyn_motor.db"
{
pattern
{P, N, M, DTYP, PORT, ADDR, DESC, EGU, DIR, VELO, VBAS, ACCL, BDST, BVEL, BACC, MRES, PREC, RDBD, DHLM, DLLM, INIT}
{KM36:phytron:, 1, "m$(N)", "asynMotor", phy, 1, "m1", mm, Pos, 2.0, 0.1, .2, 0, 1, .2, .001, 3, 0.2, 100, -100, "1"}
{KM36:phytron:, 2, "m$(N)", "asynMotor", phy, 2, "m2", mm, Pos, 2.0, 0.1, .2, 0, 1, .2, .001, 3, 0.2, 100, -100, "10"}
{P, N, M, DTYP, PORT, ADDR, DESC, EGU, DIR, VELO, VBAS, ACCL, BDST, BVEL, BACC, MRES, PREC, DHLM, DLLM, INIT}
{KM36:phytron:, 1, "m$(N)", "asynMotor", phy, 1, "m1", mm, Pos, 2.0, 0.1, .2, 0, 1, .2, .001, 3, 100, -100, "1"}
{KM36:phytron:, 2, "m$(N)", "asynMotor", phy, 2, "m2", mm, Pos, 2.0, 0.1, .2, 0, 1, .2, .001, 3, 100, -100, "10"}
}
file "$(BASE)/sinqEPICSApp/Db/motorMessage.db"
{
pattern
{P,N, M,PORT}
{KM36:phytron:, 1, "m$(N)",phy}
{KM36:phytron:, 2, "m$(N)",phy}
}

View File

@@ -1,25 +0,0 @@
#!/usr/local/bin/iocsh
require sinq,koennecke
epicsEnvSet("TOP","/afs/psi.ch/project/sinqdev/sinqepicsapp/iocBoot/iocsinqEPICS")
epicsEnvSet("BASE","/afs/psi.ch/project/sinqdev/sinqepicsapp")
epicsEnvSet("dbPATH","${EPICS_BASE}/dbd:${ASYN}/dbd:${MOTOR}/dbd")
cd ${TOP}
## Register all support components
dbLoadDatabase "../../dbd/sinqEPICS.dbd"
drvAsynIPPortConfigure("serial1", "129.129.195.58:22222",0,0,0)
#drvAsynIPPortConfigure("serial1", "localhost:9090",0,0,0)
PhytronCreateController("phy","serial1","0",1,0);
### Motors
dbLoadRecords("$(BASE)/sinqEPICSApp/Db/asynRecord.db","P=KM36:,R=serial1,PORT=serial1,ADDR=0,OMAX=80,IMAX=80")
dbLoadTemplate "motor.substitutions.phytron"
iocInit

View File

@@ -18,16 +18,19 @@ epicsEnvSet("dbPATH","${EPICS_BASE}/dbd::${ASYN}/dbd:${MOTOR}/dbd:${ANC}/dbd")
cd ${TOP}
## Register all support components
dbLoadDatabase "../../sinqEPICSApp/src/sinq.dbd"
dbLoadDatabase "../../dbd/sinqEPICS.dbd"
#dbLoadDatabase "dbd/sinq.dbd"
sinqEPICS_registerRecordDeviceDriver pdbbase
## Load record instances
#dbLoadRecords("db/xxx.db","user=koenneckeHost")
#---------- load Nanotec motor controller
#drvAsynIPPortConfigure("serial1", "narziss-ts:3002",0,0,0)
#drvAsynIPPortConfigure("serial1", "localhost:5050",0,0,0)
drvAsynIPPortConfigure("serial1", "localhost:8080",0,0,0)
PhytronCreateController("phy","serial1","0",1,1);
PhytronCreateController("phy","serial1",1,1);
### Motors

View File

@@ -1,94 +0,0 @@
# Database definition for the SLS VME magnets as installed at AMOR
##
## Read the High Limit
##
record(ai, "$(PREFIX)HighLim") {
field(DTYP, "stream")
field(DESC, "High Current Limit")
field(INP, "@slsvme.proto read($(NO),hl) slsvme 0")
field(SCAN, "1 second")
field(PREC, "3")
field(EGU, "A")
}
##
## Read the High Limit
##
record(ai, "$(PREFIX)LowLim") {
field(DTYP, "stream")
field(DESC, "Low Current Limit")
field(INP, "@slsvme.proto read($(NO),ll) slsvme 0")
field(SCAN, "1 second")
field(PREC, "3")
field(EGU, "A")
}
##
## Read the Error code
##
record(ai, "$(PREFIX)ErrCode") {
field(DTYP, "stream")
field(DESC, "Error Code")
field(INP, "@slsvme.proto read($(NO),err) slsvme 0")
field(SCAN, "1 second")
field(PREC, "3")
field(EGU, "A")
}
##
## Read the textual representation of the error.
##
record(stringin, "$(PREFIX)ErrText") {
field(DTYP, "stream")
field(INP, "@slsvme.proto readErrTxt($(NO)) slsvme 0")
field(SCAN, "1 second")
field(PINI, "YES")
}
##
## Read the Current
##
record(ai, "$(PREFIX)CurRBV") {
field(DTYP, "stream")
field(DESC, "Low Current Limit")
field(INP, "@slsvme.proto read($(NO),cur) slsvme 0")
field(SCAN, "1 second")
field(PREC, "3")
field(EGU, "A")
}
##
## Set the current
##
record(ao, "$(PREFIX)CurSet") {
field(DTYP, "stream")
field(DESC, "Setpoint current")
field(OUT, "@slsvme.proto write($(NO),cur) slsvme 0")
field(PREC, "3")
field(EGU, "A")
}
##
## Read power status of the magnet
##
record(bi, "$(PREFIX)PowerStatusRBV") {
field(DESC, "Readback of the power status")
field(DTYP, "stream")
field(INP, "@slsvme.proto readonoff($(NO)) slsvme 0")
field(SCAN, "1 second")
field(ZNAM, "off")
field(ONAM, "on")
}
##
## Set the power status
##
record(bo, "$(PREFIX)PowerStatus") {
field(DESC, "Set the power status")
field(DTYP, "stream")
field(OUT, "@slsvme.proto setpower($(NO)) slsvme 0")
field(ZNAM, "on")
field(ONAM, "off")
}

View File

@@ -4,4 +4,4 @@ set dir [pwd]
cd /usr/local/ioc
exec /usr/bin/tar czvf $dir/sinqepics.tgz modules/scaler modules/sinq modules/anc350 modules/autosave
exec /usr/bin/tar czvf $dir/sinqepics.tgz modules/scaler modules/sinq modules/anc350

View File

@@ -1,9 +0,0 @@
record(asyn,"$(P)$(R)")
{
field(DTYP,"asynRecordDevice")
field(PORT,"$(PORT)")
field(ADDR,"$(ADDR)")
field(OMAX,"$(OMAX)")
field(IMAX,"$(IMAX)")
}

View File

@@ -1,23 +0,0 @@
record(motor,"$(P)$(M)")
{
field(DESC,"$(DESC)")
field(DTYP,"$(DTYP)")
field(DIR,"$(DIR)")
field(VELO,"$(VELO)")
field(VBAS,"$(VBAS)")
field(ACCL,"$(ACCL)")
field(BDST,"$(BDST)")
field(BVEL,"$(BVEL)")
field(BACC,"$(BACC)")
field(OUT,"@asyn($(PORT),$(ADDR))")
field(MRES,"$(MRES)")
field(PREC,"$(PREC)")
field(EGU,"$(EGU)")
field(DHLM,"$(DHLM)")
field(DLLM,"$(DLLM)")
field(INIT,"$(INIT)")
field(TWV,"1")
field(RDBD,"$(RDBD)")
field(RTRY,"0")
}

View File

@@ -1,21 +0,0 @@
grecord(motor,"$(P)$(M)")
{
field(DESC,"$(DESC)")
field(DTYP,"$(DTYP)")
field(DIR,"$(DIR)")
field(VELO,"$(VELO)")
field(VBAS,"$(VBAS)")
field(ACCL,"$(ACCL)")
field(BDST,"$(BDST)")
field(BVEL,"$(BVEL)")
field(BACC,"$(BACC)")
field(OUT,"#C$(C) S$(S) @")
field(MRES,"$(MRES)")
field(PREC,"$(PREC)")
field(EGU,"$(EGU)")
field(DHLM,"$(DHLM)")
field(DLLM,"$(DLLM)")
field(INIT,"$(INIT)")
field(TWV,"1")
}

View File

@@ -6,13 +6,4 @@ record(waveform, "$(P)$(M)-MsgTxt") {
field(FTVL, "CHAR")
field(NELM, "80")
field(SCAN, "I/O Intr")
}
record(ao,"$(P)m$(N)-Resolution"){
field(DESC,"m$(N) Resolution")
field(DOL,"$(P)m$(N).MRES CP MS")
field(OMSL,"closed_loop")
field(DTYP,"asynFloat64")
field(OUT,"@asyn($(PORT),$(N))MOTOR_RESOLUTION")
field(PREC,"3")
}
}

View File

@@ -1,13 +0,0 @@
# workaround over set position
record(ao, "$(P)$(M)-SetPosition") {
field(DTYP, "asynFloat64")
field(OUT, "@asyn($(PORT),$(N),1) SET_MOTOR_POSITION")
field(PINI, "YES")
}
# enable axis
record(longout, "$(P)$(M):Enable") {
field(DTYP, "asynInt32")
field(OUT, "@asyn($(PORT),$(N),1) ENABLE_AXIS")
field(PINI, "YES")
}

View File

@@ -41,6 +41,7 @@ EL734Controller::EL734Controller(const char *portName, const char *EL734PortName
{
int axis;
asynStatus status;
EL734Axis *pAxis;
static const char *functionName = "EL734Controller::EL734Controller";
@@ -57,7 +58,7 @@ EL734Controller::EL734Controller(const char *portName, const char *EL734PortName
switchRemote();
for (axis=0; axis<numAxes; axis++) {
new EL734Axis(this, axis+1);
pAxis = new EL734Axis(this, axis+1);
}
startPoller(1000./1000., IDLEPOLL, 2);
@@ -113,20 +114,21 @@ EL734Axis* EL734Controller::getAxis(int axisNo)
void EL734Controller::switchRemote()
{
char command[COMLEN], reply[COMLEN];
int status;
size_t in, out;
int reason;
strcpy(command,"RMT 1");
pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
reply,COMLEN, 1.,&out,&in,&reason);
strcpy(command,"ECHO 0");
pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
reply,COMLEN, 1.,&out,&in,&reason);
strcpy(command,"RMT 1");
pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
reply,COMLEN, 1.,&out,&in,&reason);
strcpy(command,"ECHO 0");
pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
reply,COMLEN, 1.,&out,&in,&reason);
}
/**
@@ -147,7 +149,7 @@ asynStatus EL734Controller::transactController(int axisNo,char command[COMLEN],
pasynOctetSyncIO->flush(pasynUserController_);
status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
reply,COMLEN, 2.,&out,&in,&reason);
reply,COMLEN, 1.,&out,&in,&reason);
if(status != asynSuccess){
if(axis!= NULL){
axis->updateMsgTxtFromDriver("Lost connection to motor controller");
@@ -216,27 +218,6 @@ asynStatus EL734Controller::transactController(int axisNo,char command[COMLEN],
EL734Axis::EL734Axis(EL734Controller *pC, int axisNo)
: SINQAxis(pC, axisNo), pC_(pC)
{
char command[COMLEN], reply[COMLEN];
asynStatus status;
int count = 0;
float low, high;
/*
get the hardware limits from the controller
*/
sprintf(command,"H %d",axisNo_);
status = pC_->transactController(axisNo_,command,reply);
if(status == asynSuccess){
count = sscanf(reply,"%f %f",&low, &high);
if(count >= 2){
pC_->setDoubleParam(axisNo_,pC_->motorLowLimit_,low);
pC_->setDoubleParam(axisNo_,pC_->motorHighLimit_,high);
} else {
errlogPrintf("Bad response - %s - requesting limits at axis %d", reply, axisNo_);
}
} else {
errlogPrintf("Failed to read limits at axis %d", axisNo_);
}
}
@@ -272,12 +253,8 @@ asynStatus EL734Axis::move(double position, int relative, double minVelocity, do
}
oredMSR = 0;
homing = 0;
errorReported = 0;
errlogPrintf("Starting axis %d with destination %f", axisNo_,position/1000);
sprintf(command, "p %d %.3f", axisNo_, position/1000.);
status = pC_->transactController(axisNo_,command,reply);
setIntegerParam(pC_->motorStatusProblem_, false);
updateMsgTxtFromDriver("");
next_poll = -1;
return status;
}
@@ -290,10 +267,6 @@ asynStatus EL734Axis::home(double minVelocity, double maxVelocity, double accele
// status = sendAccelAndVelocity(acceleration, maxVelocity);
setIntegerParam(pC_->motorStatusProblem_, false);
updateMsgTxtFromDriver("");
errorReported = 0;
sprintf(command, "R %d", axisNo_);
homing = 1;
next_poll= -1;
@@ -312,7 +285,6 @@ asynStatus EL734Axis::moveVelocity(double minVelocity, double maxVelocity, doubl
// functionName, minVelocity, maxVelocity, acceleration);
errorReported = 0;
if (maxVelocity > 0.) {
/* This is a positive move */
sprintf(command, "FF %d", axisNo_);
@@ -321,24 +293,20 @@ asynStatus EL734Axis::moveVelocity(double minVelocity, double maxVelocity, doubl
sprintf(command, "FB %d", axisNo_);
}
status = pC_->transactController(axisNo_,command,reply);
setIntegerParam(pC_->motorStatusProblem_, false);
updateMsgTxtFromDriver("");
next_poll = -1;
return status;
}
asynStatus EL734Axis::stop(double acceleration )
{
asynStatus status = asynSuccess;
asynStatus status;
//static const char *functionName = "EL734Axis::stop";
char command[COMLEN], reply[COMLEN];
if(errorReported == 0){
sprintf(command, "S %d", axisNo_);
status = pC_->transactController(axisNo_,command,reply);
errlogPrintf("Sent STOP on Axis %d\n", axisNo_);
updateMsgTxtFromDriver("Axis interrupted");
}
sprintf(command, "S %d", axisNo_);
status = pC_->transactController(axisNo_,command,reply);
errlogPrintf("Sent STOP on Axis %d\n", axisNo_);
updateMsgTxtFromDriver("Axis interrupted");
return status;
}
@@ -349,7 +317,7 @@ asynStatus EL734Axis::setPosition(double position)
//static const char *functionName = "EL734Axis::setPosition";
char command[COMLEN], reply[COMLEN];
sprintf(command, "U %d %f", axisNo_, position/1000.);
sprintf(command, "P %d %f", axisNo_, position/1000.);
status = pC_->transactController(axisNo_,command,reply);
next_poll = -1;
@@ -377,8 +345,10 @@ asynStatus EL734Axis::setClosedLoop(bool closedLoop)
asynStatus EL734Axis::poll(bool *moving)
{
int msr, count;
asynStatus comStatus = asynSuccess;
asynStatus comStatus;
char command[COMLEN], reply[COMLEN], errTxt[256];
int driverError = 0;
// protect against excessive polling
if(time(NULL) < next_poll){
@@ -387,121 +357,97 @@ asynStatus EL734Axis::poll(bool *moving)
}
// Read the current motor position
setIntegerParam(pC_->motorStatusProblem_,false);
sprintf(command,"u %d", axisNo_);
comStatus = pC_->transactController(axisNo_,command,reply);
if(comStatus == asynError){
setIntegerParam(pC_->motorStatusProblem_,true);
goto skip;
driverError = 1;
}
if(comStatus) goto skip;
if(strstr(reply,"*ES") != NULL){
*moving = false;
setIntegerParam(pC_->motorStatusDone_, true);
setIntegerParam(pC_->motorStatusProblem_, true);
errorReported = 1;
updateMsgTxtFromDriver("Emergency Stop Engaged");
comStatus = asynError;
driverError = 1;
goto skip;
} else if(strstr(reply,"?BSY") != NULL){
*moving = true;
setIntegerParam(pC_->motorStatusDone_, false);
updateMsgTxtFromDriver(NULL);
goto skip;
}
count = sscanf(reply,"%lf", &position);
if(count != 1) {
if(!homing) {
snprintf(errTxt,sizeof(errTxt),"Bad reply %s when reading position for %d", reply, axisNo_);
setIntegerParam(pC_->motorStatusProblem_, true);
errorReported = 1;
updateMsgTxtFromDriver(errTxt);
comStatus = asynError;
goto skip;
}
} else {
errlogPrintf("Axis %d, reply %s, position %lf\n", axisNo_, reply, position);
setDoubleParam(pC_->motorPosition_, position*1000);
//setDoubleParam(pC_->motorEncoderPosition_, position);
snprintf(errTxt,sizeof(errTxt),"Bad reply %s when reading position for %d", reply, axisNo_);
updateMsgTxtFromDriver(errTxt);
comStatus = asynError;
driverError =1;
goto skip;
}
//errlogPrintf("Axis %d, reply %s, position %lf\n", axisNo_, reply, position);
setDoubleParam(pC_->motorPosition_, position*1000);
//setDoubleParam(pC_->motorEncoderPosition_, position);
// Read the moving status of this motor
sprintf(command,"msr %d",axisNo_);
comStatus = pC_->transactController(axisNo_,command,reply);
if(comStatus == asynError){
setIntegerParam(pC_->motorStatusProblem_,true);
goto skip;
}
if(comStatus) goto skip;
sscanf(reply,"%x",&msr);
//errlogPrintf("Axis %d, reply %s, msr %d, oredmsr = %d, position = %lf\n",
// axisNo_, reply, msr, oredMSR, position);
// errlogPrintf("Axis %d, reply %s, msr %d, position = %lf\n",
// axisNo_, reply, msr, position);
oredMSR |= msr;
if( (msr & 0x1) == 0){
// done: check for trouble
//errlogPrintf("Axis %d finished\n", axisNo_);
*moving = false;
setIntegerParam(pC_->motorStatusDone_, true);
next_poll = time(NULL)+IDLEPOLL;
if(oredMSR & 0x10){
setIntegerParam(pC_->motorStatusLowLimit_, true);
updateMsgTxtFromDriver("Lower Limit Hit");
errorReported = 1;
comStatus = asynError;
goto skip;
driverError = 1;
} else {
setIntegerParam(pC_->motorStatusLowLimit_, false);
}
if(oredMSR & 0x20){
setIntegerParam(pC_->motorStatusHighLimit_, true);
updateMsgTxtFromDriver("Upper Limit Hit");
errorReported = 1;
comStatus = asynError;
goto skip;
driverError = 1;
} else {
setIntegerParam(pC_->motorStatusHighLimit_, false);
}
if(homing){
setIntegerParam(pC_->motorStatusAtHome_, true);
}
if(oredMSR & 0x1000){
setIntegerParam(pC_->motorStatusProblem_, false);
if(oredMSR &0x1000){
setIntegerParam(pC_->motorStatusProblem_, true);
// errlogPrintf("Detected air cushion error on %d", axisNo_);
errlogSevPrintf(errlogMajor, "Air cushion problem on %d", axisNo_);
updateMsgTxtFromDriver("Air cushion error");
errorReported = 1;
comStatus = asynError;
goto skip;
driverError = 1;
}
if(oredMSR & 0x100){
if(oredMSR &0x80){
setIntegerParam(pC_->motorStatusProblem_, true);
errlogSevPrintf(errlogMajor, "Run failure at %d", axisNo_);
updateMsgTxtFromDriver("Run failure");
comStatus = asynError;
errorReported = 1;
goto skip;
errlogSevPrintf(errlogMajor, "Positioning fault at %d", axisNo_);
updateMsgTxtFromDriver("Positioning fault");
driverError = 1;
}
if(oredMSR & 0x400){
setIntegerParam(pC_->motorStatusProblem_, true);
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 = 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;
return comStatus ? asynError : asynSuccess;
}
/** Code for iocsh registration */

View File

@@ -34,7 +34,9 @@ private:
double position;
int homing;
time_t next_poll;
int errorReported;
int ErrTxtIdx;
void forwardErrorTxt(EL734Axis *axis);
friend class EL734Controller;
};

View File

@@ -1,678 +0,0 @@
/*
FILENAME... EuroMoveDriver.cpp
USAGE... Motor driver support for the EuroMove motor controller from LLB.
This is a driver for the EuroMove motor controller from LLB. This device talks to us either via
GPIB or USB. The controller is fairly simple. It can control quite a number of motors.
Reworked in 06/2021 to work with the Prologix GPIV-Ethernet converter
mark.koennecke@psi.ch
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include <time.h>
#include <unistd.h>
#include <iocsh.h>
#include <epicsThread.h>
#include <errlog.h>
#include <asynOctetSyncIO.h>
#include "EuroMoveDriver.h"
#include <epicsExport.h>
#define IDLEPOLL 60
/** Creates a new EuroMoveController object.
* \param[in] portName The name of the asyn port that will be created for this driver
* \param[in] EuroMovePortName The name of the drvAsynSerialPort that was created previously to connect to the EuroMove controller
* \param[in] numAxes The number of axes that this controller supports
*/
EuroMoveController::EuroMoveController(const char *portName, const char *EuroMovePortName, int gpibAddr, int numAxis)
: SINQController(portName, EuroMovePortName,numAxis+1)
{
asynStatus status;
static const char *functionName = "EuroMoveController::EuroMoveController";
size_t out, in;
int reason;
char command[80], reply[80];
/* Connect to EuroMove controller */
status = pasynOctetSyncIO->connect(EuroMovePortName, 0, &pasynUserController_, NULL);
if (status) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"%s: cannot connect to EuroMove controller\n",
functionName);
}
const char *terminator = "\r\n";
pasynOctetSyncIO->setOutputEos(pasynUserController_,terminator,strlen(terminator));
const char *repTerminator = "\r";
pasynOctetSyncIO->setInputEos(pasynUserController_,repTerminator,strlen(repTerminator));
/* Save gpib address and prepare addr string */
this->gpibAddr = gpibAddr;
snprintf(this->addrCommand,sizeof(addrCommand), "++addr %d", gpibAddr);
/*
Configure the Prologix interface to our liking
The thing sends no response on configuration commands
*/
strcpy(command,"++mode 1"); /* Make it a controller */
status = pasynOctetSyncIO->write(pasynUserController_, command, strlen(command), 2, &out);
strcpy(command,"++auto 1"); /* ask for response automatically */
status = pasynOctetSyncIO->write(pasynUserController_, command, strlen(command), 2, &out);
strcpy(command,"++eos 1"); /* CR */
status = pasynOctetSyncIO->write(pasynUserController_, command, strlen(command), 2, &out);
for(int i = 0; i < numAxis; i++){
new EuroMoveAxis(this, i+1);
}
startPoller(1000./1000., IDLEPOLL, 2);
}
/** Creates a new EuroMoveController object.
* Configuration command, called directly or from iocsh
* \param[in] portName The name of the asyn port that will be created for this driver
* \param[in] EuroMovePortName The name of the drvAsynIPPPort that was created previously to connect to the EuroMove controller
* \param[in] gpibAddr The address of the controller on the GPIB bus
* \param[in] numAxes The number of axes that this controller supports
*/
extern "C" int EuroMoveCreateController(const char *portName, const char *EuroMovePortName, const int gpibAddr, const int numAxis)
{
new EuroMoveController(portName, EuroMovePortName, gpibAddr, numAxis);
return(asynSuccess);
}
/** Reports on status of the driver
* \param[in] fp The file pointer on which report information will be written
* \param[in] level The level of report detail desired
*
* If details > 0 then information is printed about each axis.
* After printing controller-specific information it calls asynMotorController::report()
*/
void EuroMoveController::report(FILE *fp, int level)
{
fprintf(fp, "EuroMove motor driver %s, numAxes=%d\n",
this->portName, numAxes_);
// Call the base class method
asynMotorController::report(fp, level);
}
/** Returns a pointer to an EuroMoveAxis object.
* Returns NULL if the axis number encoded in pasynUser is invalid.
* \param[in] pasynUser asynUser structure that encodes the axis index number. */
EuroMoveAxis* EuroMoveController::getAxis(asynUser *pasynUser)
{
return static_cast<EuroMoveAxis*>(asynMotorController::getAxis(pasynUser));
}
/** Returns a pointer to an EuroMoveAxis object.
* Returns NULL if the axis number encoded in pasynUser is invalid.
* \param[in] axisNo Axis index number. */
EuroMoveAxis* EuroMoveController::getAxis(int axisNo)
{
return static_cast<EuroMoveAxis*>(asynMotorController::getAxis(axisNo));
}
/**
* send a command to the EuroMove and read the reply. Do test for errors.
* \param[in] command The command to send
* \param[out] reply The controllers reply
*/
asynStatus EuroMoveController::transactController(int axisNo,char command[COMLEN], char reply[COMLEN])
{
asynStatus status;
SINQAxis *axis = getAxis(axisNo);
size_t out, in;
int reason, errCode, lCode;
char pDummy[50], lReply[50];
const char *lCommand = {"L"};
pasynOctetSyncIO->flush(pasynUserController_);
/* set address first */
status = pasynOctetSyncIO->write(pasynUserController_, this->addrCommand, strlen(this->addrCommand), 2, &out);
if(status != asynSuccess){
if(axis!= NULL){
axis->updateMsgTxtFromDriver("Lost connection to motor controller");
errlogPrintf("Lost connection to motor controller\n");
}
return status;
}
/* now the actual command */
status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
reply,sizeof(reply), 10.,&out,&in,&reason);
if(status != asynSuccess){
if(axis!= NULL){
axis->updateMsgTxtFromDriver("Lost connection to motor controller");
errlogPrintf("Lost connection to motor controller\n");
}
return status;
}
if(strstr(reply,"ERROR") != NULL){
sscanf((const char *)reply, "%s %d", pDummy, &errCode);
switch(errCode){
case 0:
axis->updateMsgTxtFromDriver("Syntax error or parameter out of range");
errlogPrintf("Syntax error or parameter out or range on %d\n", axisNo);
break;
case 1:
axis->updateMsgTxtFromDriver("Timeout communicating with daughter board");
errlogPrintf("Timeout communicating with daughter board on %d\n", axisNo);
break;
case 2:
axis->updateMsgTxtFromDriver("This is not a drivable motor");
errlogPrintf("This is not a drivable motor on %d\n", axisNo);
break;
case 3:
axis->updateMsgTxtFromDriver("Encoder anomaly");
errlogPrintf("Encoder anomaly on %d\n", axisNo);
break;
case 4:
axis->updateMsgTxtFromDriver("Attempt to move across limit switch");
errlogPrintf("Attempt to move across limit switch on %d\n", axisNo);
break;
case 5:
axis->updateMsgTxtFromDriver("Badly configured relay system");
errlogPrintf("Badly configured relay system on %d\n", axisNo);
break;
case 6:
axis->updateMsgTxtFromDriver("Non valid backup");
errlogPrintf("Invalid backup on %d\n", axisNo);
break;
case 7:
axis->updateMsgTxtFromDriver("Backup failed");
errlogPrintf("Backup failed on %d\n", axisNo);
break;
}
return asynError;
}
/*
Test system status
*/
status = pasynOctetSyncIO->writeRead(pasynUserController_, lCommand, strlen(lCommand),
lReply,sizeof(lReply), 1.,&out,&in,&reason);
if(status != asynSuccess){
if(axis!= NULL){
axis->updateMsgTxtFromDriver("Lost connection to motor controller");
errlogPrintf("Lost connection to motor controller\n");
}
return status;
}
sscanf(lReply, "%x", &lCode);
//errlogPrintf("System status returned %s, converted to %d\n", lReply, lCode);
if((lCode & 1) > 0){
axis->updateMsgTxtFromDriver("Syntax error or impossible to execute");
errlogPrintf("Syntax error or impossible to execute for %s on %d\n", command, axisNo);
return asynError;
}
return status;
}
asynStatus EuroMoveController::writeFloat64(asynUser *pasynUser, epicsFloat64 value)
{
int function = pasynUser->reason;
asynStatus status = asynError;
EuroMoveAxis *pAxis = NULL;
static const char *functionName = "EuroMoveController::writeFloat64";
pAxis = (EuroMoveAxis *)this->getAxis(pasynUser);
if (!pAxis) {
return asynError;
}
/* Set the parameter and readback in the parameter library. */
status = pAxis->setDoubleParam(function, value);
errlogPrintf("%s, reason %d, value %f\n", functionName, function, value);
// TODO: somethign is really shitty here: lowLimit and highLimit cannot be on the command
if (function == motorResolution_) {
if(value > .0){
pAxis->resolution = (int)(1./value);
} else {
pAxis->resolution = 1;
}
}
//Call base class method
//This will handle callCallbacks even if the function was handled here.
status = asynMotorController::writeFloat64(pasynUser, value);
return status;
}
// These are the EuroMoveAxis methods
/** Creates a new EuroMoveAxis object.
* \param[in] pC Pointer to the EuroMoveController to which this axis belongs.
* \param[in] axisNo Index number of this axis, range 0 to pC->numAxes_-1.
*
* Initializes register numbers, etc.
*/
EuroMoveAxis::EuroMoveAxis(EuroMoveController *pC, int axisNo)
: SINQAxis(pC, axisNo),
pC_(pC)
{
motNo = axisNo;
}
/** 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);
}

View File

@@ -1,72 +0,0 @@
/*
FILENAME... EuroMoveDriver.h
USAGE... Motor driver support for the LLB EuroMove controller
Mark Koennecke
January 2020
*/
#include "SINQController.h"
#include "SINQAxis.h"
#define COMLEN 80
typedef enum {
HomeIdle,
HomeFastRun,
HomeFastStop,
HomeBackStep,
HomeSlowRun,
HomeSlowStop,
} HomingStatus;
class EuroMoveAxis : public SINQAxis
{
public:
/* These are the methods we override from the base class */
EuroMoveAxis(class EuroMoveController *pC, int axis);
void report(FILE *fp, int level);
asynStatus move(double position, int relative, double min_velocity, double max_velocity, double acceleration);
asynStatus moveVelocity(double min_velocity, double max_velocity, double acceleration);
asynStatus home(double min_velocity, double max_velocity, double acceleration, int forwards);
asynStatus stop(double acceleration);
asynStatus poll(bool *moving);
asynStatus setPosition(double position);
asynStatus setClosedLoop(bool closedLoop);
void setMotNo(unsigned int no){
motNo = no;
}
private:
EuroMoveController *pC_; /**< Pointer to the asynMotorController to which this axis belongs.
* Abbreviated because it is used very frequently */
time_t next_poll;
int motNo; // motor number in the EuroMove controller
int position;
HomingStatus homingStatus;
int homingDirection; // 1 = forward, 0 backwards
asynStatus sendStop();
int resolution;
friend class EuroMoveController;
int targetPosition;
};
class EuroMoveController : public SINQController {
public:
EuroMoveController(const char *portName, const char *EuroMovePortName, const int gpibAddr, const int nAxis);
void report(FILE *fp, int level);
EuroMoveAxis* getAxis(asynUser *pasynUser);
EuroMoveAxis* getAxis(int axisNo);
asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value);
friend class EuroMoveAxis;
private:
asynUser *pasynUserController_;
unsigned int gpibAddr;
char addrCommand[50];
asynStatus transactController(int axisNo, char command[COMLEN], char reply[COMLEN]);
};

View File

@@ -28,7 +28,6 @@ sinqEPICS_SRCS += EL734Driver.cpp devScalerEL737.c pmacAsynIPPort.c SINQAxis.cpp
sinqEPICS_SRCS += pmacController.cpp pmacAxis.cpp
sinqEPICS_SRCS += NanotecDriver.cpp stptok.cpp
sinqEPICS_SRCS += PhytronDriver.cpp
sinqEPICS_SRCS += EuroMoveDriver.cpp
# Build the main IOC entry point on workstation OSs.

View File

@@ -14,9 +14,6 @@ list to the motor controller constructor.
Mark Koennecke
July 2015
Modified to use the MsgTxt field for SINQ
Mark Koennecke, January 2019
*/
@@ -46,7 +43,12 @@ Mark Koennecke, January 2019
* \param[in] NanotecPortName The name of the drvAsynSerialPort that was created previously to connect to the Nanotec controller
*/
NanotecController::NanotecController(const char *portName, const char *NanotecPortName, int motCount, const char *bus)
: SINQController(portName, NanotecPortName, motCount+1)
: asynMotorController(portName, motCount+1, 0,
0, // No additional interfaces beyond those in base class
0, // No additional callback interfaces beyond those in base class
ASYN_CANBLOCK | ASYN_MULTIDEVICE,
1, // autoconnect
0, 0) // Default priority and stack size
{
int axis, busAddress;
asynStatus status;
@@ -134,7 +136,7 @@ NanotecAxis* NanotecController::getAxis(int axisNo)
* Initializes register numbers, etc.
*/
NanotecAxis::NanotecAxis(NanotecController *pC, int axisNo, int busAddress)
: SINQAxis(pC, axisNo),
: asynMotorAxis(pC, axisNo),
pC_(pC)
{
this->busAddress = busAddress;
@@ -160,21 +162,17 @@ void NanotecAxis::report(FILE *fp, int level)
//asynMotorAxis::report(fp, level);
}
asynStatus NanotecController::transactController(int axisNo, char command[COMLEN], char reply[COMLEN])
asynStatus NanotecController::transactController(char command[COMLEN], char reply[COMLEN])
{
asynStatus status;
size_t in, out;
int reason;
SINQAxis *axis = getAxis(axisNo);
pasynOctetSyncIO->flush(pasynUserController_);
status = pasynOctetSyncIO->writeRead(pasynUserController_, command, strlen(command),
reply,COMLEN, 1.,&out,&in,&reason);
if(status != asynSuccess){
if(axis != NULL){
axis->updateMsgTxtFromDriver("Lost connection to motor controller");
}
return status;
}
@@ -202,8 +200,6 @@ asynStatus NanotecAxis::move(double position, int relative, double minVelocity,
size_t in, out;
int reason;
updateMsgTxtFromDriver("");
// status = sendAccelAndVelocity(acceleration, maxVelocity);
if (relative) {
@@ -219,7 +215,7 @@ asynStatus NanotecAxis::move(double position, int relative, double minVelocity,
set mode
*/
snprintf(command,sizeof(command),"#%dp2",busAddress);
status = pC_->transactController(axisNo_,command,reply);
status = pC_->transactController(command,reply);
if(status != asynSuccess){
return status;
}
@@ -228,7 +224,7 @@ asynStatus NanotecAxis::move(double position, int relative, double minVelocity,
set target
*/
snprintf(command,sizeof(command),"#%ds%d",busAddress, (int)position);
status = pC_->transactController(axisNo_,command,reply);
status = pC_->transactController(command,reply);
if(status != asynSuccess){
return status;
}
@@ -237,7 +233,7 @@ asynStatus NanotecAxis::move(double position, int relative, double minVelocity,
and start..
*/
snprintf(command,sizeof(command),"#%dA",busAddress);
status = pC_->transactController(axisNo_,command,reply);
status = pC_->transactController(command,reply);
if(status != asynSuccess){
return status;
}
@@ -254,13 +250,11 @@ asynStatus NanotecAxis::home(double minVelocity, double maxVelocity, double acce
setIntegerParam(pC_->motorStatusAtHome_, false);
updateMsgTxtFromDriver("");
/*
reset positioning errors
*/
snprintf(command,sizeof(command),"#%dD",busAddress);
status = pC_->transactController(axisNo_,command,reply);
status = pC_->transactController(command,reply);
if(status != asynSuccess){
return status;
}
@@ -269,7 +263,7 @@ asynStatus NanotecAxis::home(double minVelocity, double maxVelocity, double acce
set mode
*/
snprintf(command,sizeof(command),"#%dp4",busAddress);
status = pC_->transactController(axisNo_,command,reply);
status = pC_->transactController(command,reply);
if(status != asynSuccess){
return status;
}
@@ -279,7 +273,7 @@ asynStatus NanotecAxis::home(double minVelocity, double maxVelocity, double acce
set direction
*/
snprintf(command,sizeof(command),"#%dd0",busAddress);
status = pC_->transactController(axisNo_,command,reply);
status = pC_->transactController(command,reply);
if(status != asynSuccess){
return status;
}
@@ -289,7 +283,7 @@ asynStatus NanotecAxis::home(double minVelocity, double maxVelocity, double acce
and start..
*/
snprintf(command,sizeof(command),"#%dA",busAddress);
status = pC_->transactController(axisNo_,command,reply);
status = pC_->transactController(command,reply);
if(status != asynSuccess){
return status;
}
@@ -310,7 +304,6 @@ asynStatus NanotecAxis::moveVelocity(double minVelocity, double maxVelocity, dou
// "%s: minVelocity=%f, maxVelocity=%f, acceleration=%f\n",
// functionName, minVelocity, maxVelocity, acceleration);
updateMsgTxtFromDriver("");
if (maxVelocity > 0.) {
@@ -333,7 +326,7 @@ asynStatus NanotecAxis::stop(double acceleration )
char command[COMLEN], reply[COMLEN];
sprintf(command, "#%dS1", busAddress);
status = pC_->transactController(axisNo_,command,reply);
status = pC_->transactController(command,reply);
errlogPrintf("Sent STOP on Axis %d\n", axisNo_);
return status;
@@ -345,10 +338,8 @@ asynStatus NanotecAxis::setPosition(double position)
//static const char *functionName = "NanotecAxis::setPosition";
char command[COMLEN], reply[COMLEN];
updateMsgTxtFromDriver("");
sprintf(command, "#%dD%d", busAddress, (int)position);
status = pC_->transactController(axisNo_,command,reply);
status = pC_->transactController(command,reply);
next_poll = -1;
return status;
@@ -389,28 +380,28 @@ asynStatus NanotecAxis::poll(bool *moving)
// Read the current motor position
sprintf(command,"#%dC", busAddress);
comStatus = pC_->transactController(axisNo_,command,reply);
comStatus = pC_->transactController(command,reply);
if(comStatus) goto skip;
pPtr = strchr(reply,'C');
pPtr++;
posVal = atoi(pPtr);
//errlogPrintf("Axis %d, reply %s, position %d\n", axisNo_, reply, posVal);
errlogPrintf("Axis %d, reply %s, position %d\n", axisNo_, reply, posVal);
setDoubleParam(pC_->motorPosition_, (double)posVal);
//setDoubleParam(pC_->motorEncoderPosition_, position);
// Read the moving status of this motor
sprintf(command,"#%d$",busAddress);
comStatus = pC_->transactController(axisNo_,command,reply);
comStatus = pC_->transactController(command,reply);
if(comStatus) goto skip;
pPtr = strchr(reply,'$');
pPtr++;
statVal = atoi(pPtr);
//errlogPrintf("Axis %d, reply %s, statVal = %d\n",
// axisNo_, reply, statVal);
errlogPrintf("Axis %d, reply %s, statVal = %d\n",
axisNo_, reply, statVal);
setIntegerParam(pC_->motorStatusDone_, false);
*moving = true;
@@ -447,13 +438,10 @@ asynStatus NanotecAxis::poll(bool *moving)
setIntegerParam(pC_->motorStatusDone_, true);
setIntegerParam(pC_->motorStatusProblem_, true);
errlogSevPrintf(errlogMajor, "Limit or other positioning problem at %d", axisNo_);
updateMsgTxtFromDriver("Positioning problem");
if(ABS(posVal - lowLim) < ABS(posVal - highLim)){
setIntegerParam(pC_->motorStatusLowLimit_, true);
updateMsgTxtFromDriver("Low Limit Hit");
} else {
setIntegerParam(pC_->motorStatusHighLimit_, true);
updateMsgTxtFromDriver("High Limit Hit");
}
*moving = false;
}

View File

@@ -5,18 +5,15 @@ USAGE... Motor driver support for the Nanotec SMCI controller.
Mark Koennecke
July 2015
Modified to use the MsgTxt field for SINQ
Mark Koennecke, January 2019
*/
#include "SINQController.h"
#include "SINQAxis.h"
#include "asynMotorController.h"
#include "asynMotorAxis.h"
#define COMLEN 80
#define MAXMOT 99
class NanotecAxis : public SINQAxis
class NanotecAxis : public asynMotorAxis
{
public:
/* These are the methods we override from the base class */
@@ -41,7 +38,7 @@ private:
friend class NanotecController;
};
class NanotecController : public SINQController {
class NanotecController : public asynMotorController {
public:
NanotecController(const char *portName, const char *NanotecPortName, int numMot, const char *busAddresses);
@@ -53,7 +50,7 @@ friend class NanotecAxis;
private:
asynUser *pasynUserController_;
asynStatus transactController(int axisNo, char command[COMLEN], char reply[COMLEN]);
asynStatus transactController(char command[COMLEN], char reply[COMLEN]);

View File

@@ -23,12 +23,6 @@ Though this driver has been written in 2016, the MCC-2 version used is probably
Mark Koennecke
September 2016
Updated to use the new MsgTxt field through SINQAxis
Added a selector to support multiple phytrons on a connection
Mark Koennecke
January 2019
*/
@@ -55,16 +49,19 @@ January 2019
* \param[in] PhytronPortName The name of the drvAsynSerialPort that was created previously to connect to the Phytron controller
* \param[in] numAxes The number of axes that this controller supports
*/
PhytronController::PhytronController(const char *portName, const char *PhytronPortName, const char *sel ,
int encX, int encY)
: SINQController(portName, PhytronPortName,2)
PhytronController::PhytronController(const char *portName, const char *PhytronPortName, int encX, int encY)
: asynMotorController(portName, 3, 0,
0, // No additional interfaces beyond those in base class
0, // No additional callback interfaces beyond those in base class
ASYN_CANBLOCK | ASYN_MULTIDEVICE,
1, // autoconnect
0, 0) // Default priority and stack size
{
asynStatus status;
PhytronAxis *pAxis;
static const char *functionName = "PhytronController::PhytronController";
char etx[2];
selector = strdup(sel);
/* Connect to Phytron controller */
status = pasynOctetSyncIO->connect(PhytronPortName, 0, &pasynUserController_, NULL);
if (status) {
@@ -77,8 +74,8 @@ PhytronController::PhytronController(const char *portName, const char *PhytronPo
pasynOctetSyncIO->setOutputEos(pasynUserController_,etx,strlen(etx));
pasynOctetSyncIO->setInputEos(pasynUserController_,etx,strlen(etx));
new PhytronAxis(this, 1, encX);
new PhytronAxis(this, 2, encY);
pAxis = new PhytronAxis(this, 1, encX);
pAxis = new PhytronAxis(this, 2, encY);
startPoller(1000./1000., IDLEPOLL, 2);
}
@@ -90,10 +87,11 @@ 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] numAxes The number of axes that this controller supports
*/
extern "C" int PhytronCreateController(const char *portName, const char *PhytronPortName, const char *selector,
int encX, int encY)
extern "C" int PhytronCreateController(const char *portName, const char *PhytronPortName, int encX, int encY)
{
new PhytronController(portName, PhytronPortName,selector, encX, encY);
PhytronController *pPhytronController
= new PhytronController(portName, PhytronPortName, encX, encY);
pPhytronController = NULL;
return(asynSuccess);
}
@@ -136,14 +134,12 @@ PhytronAxis* PhytronController::getAxis(int axisNo)
* \param[out] reply The controllers reply
*/
asynStatus PhytronController::transactController(int axisNo,char command[COMLEN], char reply[COMLEN])
asynStatus PhytronController::transactController(char command[COMLEN], char reply[COMLEN])
{
asynStatus status;
size_t in, out;
int reason;
char myReply[COMLEN+10], myCommand[COMLEN+10], *pPtr;
SINQAxis *axis = getAxis(axisNo);
pasynOctetSyncIO->flush(pasynUserController_);
@@ -159,9 +155,6 @@ asynStatus PhytronController::transactController(int axisNo,char command[COMLEN]
status = pasynOctetSyncIO->writeRead(pasynUserController_, myCommand, strlen(myCommand),
myReply,sizeof(myReply), 1.,&out,&in,&reason);
if(status != asynSuccess){
if(axis!= NULL){
axis->updateMsgTxtFromDriver("Lost connection to motor controller");
}
return status;
}
@@ -183,7 +176,7 @@ asynStatus PhytronController::transactController(int axisNo,char command[COMLEN]
I may need to replace the ETX. But I am not sure if asyn did
not remove it for me.
*/
strncat(reply,pPtr,COMLEN-1);
strncat(reply,pPtr,sizeof(reply));
return status;
@@ -198,7 +191,7 @@ asynStatus PhytronController::transactController(int axisNo,char command[COMLEN]
* Initializes register numbers, etc.
*/
PhytronAxis::PhytronAxis(PhytronController *pC, int axisNo, int enc)
: SINQAxis(pC, axisNo),
: asynMotorAxis(pC, axisNo),
pC_(pC)
{
encoder = enc;
@@ -207,20 +200,10 @@ PhytronAxis::PhytronAxis(PhytronController *pC, int axisNo, int enc)
} else {
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
* \param[in] fp The file pointer on which report information will be written
@@ -246,46 +229,15 @@ asynStatus PhytronAxis::move(double position, int relative, double minVelocity,
//static const char *functionName = "PhytronAxis::move";
char command[COMLEN], reply[COMLEN];
updateMsgTxtFromDriver("");
/*
deal with brake
*/
if(haveBrake) {
sprintf(command,"%sA%dS", pC_->selector, brakeIO);
status = pC_->transactController(axisNo_,command,reply);
if(strstr(reply,"NACK") != NULL){
errlogSevPrintf(errlogMajor, "Failed to release brake on %d", axisNo_);
updateMsgTxtFromDriver("Failed to release brake");
setIntegerParam(pC_->motorStatusProblem_, true);
return asynError;
}
}
/*
set speed
*/
sprintf(command, "%s%cP14S%f", pC_->selector, phytronChar, maxVelocity);
status = pC_->transactController(axisNo_,command,reply);
if(strstr(reply,"NACK") != NULL){
errlogSevPrintf(errlogMajor, "Speed not accepted on %d", axisNo_);
updateMsgTxtFromDriver("Invalid speed");
setIntegerParam(pC_->motorStatusProblem_, true);
return asynError;
}
/*
actually send a move command
*/
if (relative) {
position += this->position;
}
homing = 0;
sprintf(command, "%s%cA%f", pC_->selector,phytronChar,position/1000.);
status = pC_->transactController(axisNo_,command,reply);
sprintf(command, "0%cA%f", phytronChar,position/1000.);
status = pC_->transactController(command,reply);
if(strstr(reply,"NACK") != NULL){
errlogSevPrintf(errlogMajor, "Drive command not acknowledged on %d", axisNo_);
updateMsgTxtFromDriver("Drive command not acknowledged");
setIntegerParam(pC_->motorStatusProblem_, true);
return asynError;
}
@@ -299,47 +251,13 @@ asynStatus PhytronAxis::home(double minVelocity, double maxVelocity, double acce
//static const char *functionName = "PhytronAxis::home";
char command[COMLEN], reply[COMLEN];
updateMsgTxtFromDriver("");
/*
handle the fucking brake
*/
if(haveBrake) {
sprintf(command,"%sA%dS", pC_->selector, brakeIO);
status = pC_->transactController(axisNo_,command,reply);
if(strstr(reply,"NACK") != NULL){
errlogSevPrintf(errlogMajor, "Failed to release brake on %d", axisNo_);
updateMsgTxtFromDriver("Failed to release brake");
setIntegerParam(pC_->motorStatusProblem_, true);
return asynError;
}
}
/*
set speed
*/
sprintf(command, "%s%cP14S%f", pC_->selector, phytronChar, maxVelocity);
status = pC_->transactController(axisNo_,command,reply);
if(strstr(reply,"NACK") != NULL){
errlogSevPrintf(errlogMajor, "Speed not accepted on %d", axisNo_);
updateMsgTxtFromDriver("Invalid speed");
setIntegerParam(pC_->motorStatusProblem_, true);
return asynError;
}
homing_direction = forwards;
if(forwards){
sprintf(command, "%s%c0+",pC_->selector,phytronChar);
} else {
sprintf(command, "%s%c0-",pC_->selector,phytronChar);
}
sprintf(command, "0%cO-",phytronChar);
homing = 1;
next_poll= -1;
status = pC_->transactController(axisNo_,command,reply);
status = pC_->transactController(command,reply);
if(strstr(reply,"NACK") != NULL){
errlogSevPrintf(errlogMajor, "Home command not acknowledged on %d", axisNo_);
setIntegerParam(pC_->motorStatusProblem_, true);
updateMsgTxtFromDriver("Home command not acknowledged");
return asynError;
}
return status;
@@ -356,7 +274,6 @@ asynStatus PhytronAxis::moveVelocity(double minVelocity, double maxVelocity, dou
// "%s: minVelocity=%f, maxVelocity=%f, acceleration=%f\n",
// functionName, minVelocity, maxVelocity, acceleration);
updateMsgTxtFromDriver("");
if (maxVelocity > 0.) {
@@ -377,10 +294,9 @@ asynStatus PhytronAxis::stop(double acceleration )
//static const char *functionName = "PhytronAxis::stop";
char command[COMLEN], reply[COMLEN];
sprintf(command, "%s%cSN", pC_->selector,phytronChar);
status = pC_->transactController(axisNo_,command,reply);
sprintf(command, "0%cSN", phytronChar);
status = pC_->transactController(command,reply);
errlogPrintf("Sent STOP on Axis %d\n", axisNo_);
updateMsgTxtFromDriver("Axis interrupted");
return status;
}
@@ -391,12 +307,10 @@ asynStatus PhytronAxis::setPosition(double position)
//static const char *functionName = "PhytronAxis::setPosition";
char command[COMLEN], reply[COMLEN];
errlogPrintf("PhytronAxis::setPosition called with %lf\n", position);
sprintf(command, "%s%cP22S%f", pC_->selector,phytronChar, position/1000.);
status = pC_->transactController(axisNo_,command,reply);
sprintf(command, "%s%cP20S%f", pC_->selector,phytronChar, position/1000.);
status = pC_->transactController(axisNo_,command,reply);
sprintf(command, "0%cP22S%f", phytronChar, position/1000.);
status = pC_->transactController(command,reply);
sprintf(command, "0%cP20S%f", phytronChar, position/1000.);
status = pC_->transactController(command,reply);
next_poll = -1;
return status;
@@ -422,7 +336,7 @@ asynStatus PhytronAxis::setClosedLoop(bool closedLoop)
* \param[out] moving A flag that is set indicating that the axis is moving (true) or done (false). */
asynStatus PhytronAxis::poll(bool *moving)
{
asynStatus comStatus = asynSuccess;
asynStatus comStatus;
char command[COMLEN], reply[COMLEN];
double lowlim;
@@ -433,24 +347,19 @@ asynStatus PhytronAxis::poll(bool *moving)
return asynSuccess;
}
setIntegerParam(pC_->motorStatusProblem_, false);
// Read the current motor position
if(encoder) {
sprintf(command,"%s%cP22R",pC_->selector,phytronChar);
sprintf(command,"0%cP22R",phytronChar);
} else {
sprintf(command,"%s%cP20R",pC_->selector,phytronChar);
sprintf(command,"0%cP20R",phytronChar);
}
comStatus = pC_->transactController(axisNo_,command,reply);
if(comStatus == asynError) {
setIntegerParam(pC_->motorStatusProblem_, true);
updateMsgTxtFromDriver("No connection to phytron controller");
goto skip;
}
comStatus = pC_->transactController(command,reply);
if(comStatus) goto skip;
if(strstr(reply,"NACK") != NULL){
setIntegerParam(pC_->motorStatusProblem_, true);
errlogSevPrintf(errlogMajor, "Bad reply for position on %d", axisNo_);
updateMsgTxtFromDriver("Bad reply reading position");
goto skip;
}
/*
@@ -463,13 +372,9 @@ asynStatus PhytronAxis::poll(bool *moving)
// Read the moving status of this motor
sprintf(command,"%s%c=H",pC_->selector,phytronChar);
comStatus = pC_->transactController(axisNo_,command,reply);
if(comStatus == asynError){
setIntegerParam(pC_->motorStatusProblem_, true);
updateMsgTxtFromDriver("No connection to phytron controller");
goto skip;
}
sprintf(command,"0%c=H",phytronChar);
comStatus = pC_->transactController(command,reply);
if(comStatus) goto skip;
/* errlogPrintf("Axis %d, status reply %s, position %lf\n", axisNo_, reply, position); */
if(strstr(reply,"ACKN") != NULL){
*moving = true;
@@ -479,45 +384,23 @@ asynStatus PhytronAxis::poll(bool *moving)
*moving = false;
next_poll = time(NULL)+IDLEPOLL;
setIntegerParam(pC_->motorStatusDone_, true);
if(haveBrake) {
sprintf(command,"%sA%dR", pC_->selector, brakeIO);
comStatus = pC_->transactController(axisNo_,command,reply);
if(strstr(reply,"NACK") != NULL){
errlogSevPrintf(errlogMajor, "Failed to set brake on %d", axisNo_);
updateMsgTxtFromDriver("Failed to set brake");
setIntegerParam(pC_->motorStatusProblem_, true);
return asynError;
}
}
}
if(!*moving) {
if(homing){
if(homing_direction) {
pC_->getDoubleParam(axisNo_,pC_->motorHighLimit_,&lowlim);
} else {
pC_->getDoubleParam(axisNo_,pC_->motorLowLimit_,&lowlim);
}
pC_->getDoubleParam(axisNo_,pC_->motorLowLimit_,&lowlim);
setPosition(lowlim);
setIntegerParam(pC_->motorStatusAtHome_, true);
} else {
/*
check limits and errors, upper
*/
sprintf(command,"%s%c=I+",pC_->selector,phytronChar);
comStatus = pC_->transactController(axisNo_,command,reply);
if(comStatus == asynError) {
setIntegerParam(pC_->motorStatusProblem_, true);
updateMsgTxtFromDriver("No connection to phytron controller");
goto skip;
}
sprintf(command,"0%c=I+",phytronChar);
comStatus = pC_->transactController(command,reply);
if(comStatus) goto skip;
if(strstr(reply,"ACKE") != NULL){
setIntegerParam(pC_->motorStatusHighLimit_, true);
updateMsgTxtFromDriver("Hit High Limit");
comStatus = asynError;
goto skip;
} else {
setIntegerParam(pC_->motorStatusHighLimit_, false);
}
@@ -525,18 +408,11 @@ asynStatus PhytronAxis::poll(bool *moving)
/*
lower limit
*/
sprintf(command,"%s%c=I-",pC_->selector,phytronChar);
comStatus = pC_->transactController(axisNo_,command,reply);
if(comStatus == asynError){
setIntegerParam(pC_->motorStatusProblem_, true);
updateMsgTxtFromDriver("No connection to phytron controller");
goto skip;
}
sprintf(command,"0%c=I-",phytronChar);
comStatus = pC_->transactController(command,reply);
if(comStatus) goto skip;
if(strstr(reply,"ACKE") != NULL){
setIntegerParam(pC_->motorStatusLowLimit_, true);
updateMsgTxtFromDriver("Low Limit Hit");
comStatus = asynError;
goto skip;
} else {
setIntegerParam(pC_->motorStatusLowLimit_, false);
}
@@ -544,19 +420,12 @@ asynStatus PhytronAxis::poll(bool *moving)
/*
error
*/
sprintf(command,"%s%c=E",pC_->selector,phytronChar);
comStatus = pC_->transactController(axisNo_,command,reply);
if(comStatus == asynError) {
setIntegerParam(pC_->motorStatusProblem_, true);
updateMsgTxtFromDriver("No connection to phytron controller");
goto skip;
}
sprintf(command,"0%c=E",phytronChar);
comStatus = pC_->transactController(command,reply);
if(comStatus) goto skip;
if(strstr(reply,"ACKE") != NULL){
setIntegerParam(pC_->motorStatusProblem_, true);
errlogSevPrintf(errlogMajor, "Electronics on %d", axisNo_);
updateMsgTxtFromDriver("Electronics error");
comStatus = asynError;
goto skip;
} else {
setIntegerParam(pC_->motorStatusProblem_, false);
}
@@ -565,76 +434,29 @@ asynStatus PhytronAxis::poll(bool *moving)
skip:
setIntegerParam(pC_->motorStatusProblem_, comStatus ? 1:0);
callParamCallbacks();
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;
return comStatus ? asynError : asynSuccess;
}
/** Code for iocsh registration */
static const iocshArg PhytronCreateControllerArg0 = {"Port name", iocshArgString};
static const iocshArg PhytronCreateControllerArg1 = {"Phytron port name", iocshArgString};
static const iocshArg PhytronCreateControllerArg2 = {"Phytron Selector", iocshArgString};
static const iocshArg PhytronCreateControllerArg3 = {"EncoderX", iocshArgInt};
static const iocshArg PhytronCreateControllerArg4 = {"EncoderY", iocshArgInt};
static const iocshArg PhytronCreateControllerArg2 = {"EnoderX", iocshArgInt};
static const iocshArg PhytronCreateControllerArg3 = {"EnoderY", iocshArgInt};
static const iocshArg * const PhytronCreateControllerArgs[] = {&PhytronCreateControllerArg0,
&PhytronCreateControllerArg1,
&PhytronCreateControllerArg2,
&PhytronCreateControllerArg3,
&PhytronCreateControllerArg4};
static const iocshFuncDef PhytronCreateControllerDef = {"PhytronCreateController", 5, PhytronCreateControllerArgs};
&PhytronCreateControllerArg3};
static const iocshFuncDef PhytronCreateControllerDef = {"PhytronCreateController", 4, PhytronCreateControllerArgs};
static void PhytronCreateContollerCallFunc(const iocshArgBuf *args)
{
PhytronCreateController(args[0].sval, args[1].sval, args[2].sval, args[3].ival,args[4].ival);
PhytronCreateController(args[0].sval, args[1].sval, args[2].ival,args[3].ival);
}
/* PhytronConfigureBrake */
static const iocshArg phytronBrakeArg0 = {"Controller port name", iocshArgString};
static const iocshArg phytronBrakeArg1 = {"Axis number", iocshArgInt};
static const iocshArg phytronBrakeArg2 = {"Brake IO number", iocshArgInt};
static const iocshArg * const phytronBrakeArgs[] = {&phytronBrakeArg0,
&phytronBrakeArg1,
&phytronBrakeArg2};
static const iocshFuncDef phytronBrakeDef = {"PhytronConfigureBrake", 3, phytronBrakeArgs};
static void phytronBrakeCallFunc(const iocshArgBuf *args)
{
PhytronConfBrake(args[0].sval, args[1].ival, args[2].ival);
}
static void PhytronRegister(void)
{
iocshRegister(&PhytronCreateControllerDef, PhytronCreateContollerCallFunc);
iocshRegister(&phytronBrakeDef, phytronBrakeCallFunc);
}
extern "C" {

View File

@@ -5,19 +5,14 @@ USAGE... Motor driver support for the Phytron MCC-2 motor controller.
Mark Koennecke
September 2016
Updated to go through SINQAxis for -MsgTxt support
Added a selector to support multiple phytrons on a connection
Mark Koennecke, January 2019
*/
#include "SINQController.h"
#include "SINQAxis.h"
#include "asynMotorController.h"
#include "asynMotorAxis.h"
#define COMLEN 80
class PhytronAxis : public SINQAxis
class PhytronAxis : public asynMotorAxis
{
public:
/* These are the methods we override from the base class */
@@ -30,7 +25,6 @@ public:
asynStatus poll(bool *moving);
asynStatus setPosition(double position);
asynStatus setClosedLoop(bool closedLoop);
int setBrake(int brakeIO);
private:
char phytronChar;
@@ -38,19 +32,15 @@ private:
* Abbreviated because it is used very frequently */
double position;
int homing;
int homing_direction; /*1 forward, 0 backwards */
time_t next_poll;
int encoder;
int haveBrake;
int brakeIO;
friend class PhytronController;
};
class PhytronController : public SINQController {
class PhytronController : public asynMotorController {
public:
PhytronController(const char *portName, const char *PhytronPortName, const char *selector,
int encX, int encY);
PhytronController(const char *portName, const char *PhytronPortName, int encX, int encY);
void report(FILE *fp, int level);
PhytronAxis* getAxis(asynUser *pasynUser);
@@ -60,8 +50,7 @@ friend class PhytronAxis;
private:
asynUser *pasynUserController_;
asynStatus transactController(int axisNo, char command[COMLEN], char reply[COMLEN]);
asynStatus transactController(char command[COMLEN], char reply[COMLEN]);
const char *selector;
};

View File

@@ -12,7 +12,6 @@ SINQAxis::SINQAxis(class SINQController *pC, int axis)
: asynMotorAxis((asynMotorController *)pC, axis),
pC_(pC)
{
updateMsgTxtFromDriver("");
}
@@ -23,7 +22,6 @@ void SINQAxis::updateMsgTxtFromDriver(const char *value)
setStringParam(pC_->motorMessageText_,value);
} else {
pC_->setIntegerParam(axisNo_,pC_->motorMessageIsFromDriver_, 0);
setStringParam(pC_->motorMessageText_,"");
}
}

View File

@@ -10,8 +10,8 @@
#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,
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,

View File

@@ -17,7 +17,7 @@
class epicsShareClass SINQController : public asynMotorController
{
public:
SINQController(const char *portName, const char *SINQPortName, int numAxes, const int& extraParams=2);
SINQController(const char *portName, const char *SINQPortName, int numAxes);
friend class SINQAxis;
protected:

View File

@@ -27,7 +27,7 @@
*
* Mark Koennecke, February 2013
*
* Enhanced by adding an addtional external pause and status flag in the database and code in here
* Enhanced by adding an addtional external pause and status flag in the databse and code in here
* to handle this. Moreover an external MsgTxt field in the DB can be filled with an error message.
*
* Mark Koennecke, July 2017
@@ -163,7 +163,7 @@ static void connectSlaveRecords(EL737priv *priv)
errlogPrintf("dbNameToAddr failed for %s with %s\n", slaveName, errName);
priv->dbInit = 0;
} else {
errlogPrintf("dbNameToAddr succeded for %s, record access %s\n",slaveName, priv->threshCounter.precord->name);
errlogPrintf("dbNameToAddr succeded for %s, record access %s\n",slaveName, priv->status.precord->name);
}
snprintf(slaveName,sizeof(slaveName),"%s:Threshold", priv->psr->name);
@@ -174,9 +174,9 @@ static void connectSlaveRecords(EL737priv *priv)
errlogPrintf("dbNameToAddr failed for %s with %s\n", slaveName, errName);
priv->dbInit = 0;
} else {
errlogPrintf("dbNameToAddr succeded for %s, record access %s\n",slaveName, priv->threshold.precord->name);
errlogPrintf("dbNameToAddr succeded for %s, record access %s\n",slaveName, priv->status.precord->name);
}
priv->thresholdValue = -999;
}
static long el737_init_record(scalerRecord *psr, CALLBACK *pcallback)
@@ -225,14 +225,14 @@ static long el737_init_record(scalerRecord *psr, CALLBACK *pcallback)
status = pasynOctetSyncIO->connect(port, 0, &priv->asynContext, NULL);
if (status) {
asynPrint(dummyUser, ASYN_TRACE_ERROR,
"%s: cannot connect to EL737 controller\n",
"%s: cannot connect to EL734 controller\n",
"el737_init_scaler");
psr->pact = 1;
return 0;
}
pasynOctetSyncIO->setOutputEos(priv->asynContext,"\r",strlen("\r"));
pasynOctetSyncIO->setInputEos(priv->asynContext,"\r",strlen("\r"));
priv->asynContext->timeout = 2.0;
priv->asynContext->timeout = 1.0;
strcpy(command,"RMT 1");
pasynOctetSyncIO->writeRead(priv->asynContext, command, strlen(command),
reply,sizeof(reply), 1.,&out,&in,&reason);
@@ -343,7 +343,7 @@ static asynStatus el737_transactCommand(EL737priv *priv,char command[COMLEN],cha
pasynOctetSyncIO->flush(priv->asynContext);
strcpy(message,"");
strcpy(message,"OK");
status = pasynOctetSyncIO->writeRead(priv->asynContext, command, strlen(command),
reply,COMLEN, 1.,&out,&in,&reason);
if(status == asynSuccess){
@@ -414,7 +414,7 @@ static void runEvents(EL737priv *priv)
This is the better way to set the threshold rather then the old way below which uses
presets for that function. This one uses separate fields.
*/
if(priv->dbInit == 1 && priv->sendThreshold) {
if(priv->dbInit == 1) {
dbStatus = dbGetField(&priv->threshold,DBR_LONG,&myThreshold,&options, &nElements,NULL);
if(dbStatus != 0){
errSymLookup(dbStatus,errName,sizeof(errName));
@@ -425,16 +425,13 @@ static void runEvents(EL737priv *priv)
we have to set the threshold
*/
dbStatus = dbGetField(&priv->threshCounter,DBR_LONG,&threshCounter, &options, &nElements,NULL);
if(dbStatus != 0) {
if(dbStatus != 0){
errSymLookup(dbStatus,errName,sizeof(errName));
errlogPrintf("Reading thresholdCounter failed with %s\n", errName);
} else {
if(threshCounter == 0){
threshCounter = 1;
}
sprintf(command,"DL %d %d", (int)threshCounter,
(int)myThreshold);
errlogPrintf("Sending threshold command %s\n", command);
//errlogPrintf("Sending threshold command %s\n", command);
status = el737_transactCommand(priv,command,reply);
sprintf(command,"DR %d", (int)threshCounter);
status = el737_transactCommand(priv, command,reply);
@@ -445,22 +442,17 @@ static void runEvents(EL737priv *priv)
}
}
}
}
}
if(priv->sendThreshold == 1) {
// fallback when we do not have the DB fields or threshCounter is invalid
if(priv->presets[THRESHMON] <= 0) {
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;
}
if(priv->sendThreshold == 1){
sprintf(command,"DL %d %d", (int)priv->presets[THRESHMON],
(int)priv->presets[THRESHVAL]);
//errlogPrintf("Sending threshold command %s\n", command);
status = el737_transactCommand(priv,command,reply);
sprintf(command,"DR %d", (int)priv->presets[THRESHMON]);
status = el737_transactCommand(priv, command,reply);
if(status == asynSuccess){
priv->sendThreshold = 0;
}
}
@@ -550,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!!!!

File diff suppressed because it is too large Load Diff

View File

@@ -7,28 +7,21 @@
* Matthew Pearson
* 23 May 2012
*
* Modified to use the MsgTxt field for SINQ
*
* Mark Koennecke, January 2019
*
* EXtended with special motor axis for the Selene
* guide, Mark Koennecke, February 2020
********************************************/
#ifndef pmacAxis_H
#define pmacAxis_H
#include "SINQController.h"
#include "SINQAxis.h"
#include "asynMotorController.h"
#include "asynMotorAxis.h"
class pmacController;
class SeleneController;
class pmacAxis : public SINQAxis
class pmacAxis : public asynMotorAxis
{
public:
/* These are the methods we override from the base class */
pmacAxis(pmacController *pController, int axisNo, bool enable=true);
pmacAxis(pmacController *pController, int axisNo);
virtual ~pmacAxis();
asynStatus move(double position, int relative, double min_velocity, double max_velocity, double acceleration);
asynStatus moveVelocity(double min_velocity, double max_velocity, double acceleration);
@@ -36,9 +29,8 @@ class pmacAxis : public SINQAxis
asynStatus stop(double acceleration);
asynStatus poll(bool *moving);
asynStatus setPosition(double position);
asynStatus enable(int on);
protected:
private:
pmacController *pC_;
asynStatus getAxisStatus(bool *moving);
@@ -61,100 +53,9 @@ protected:
time_t status6Time;
int starting;
int homing;
double statusPos;
time_t next_poll;
bool autoEnable;
friend class pmacController;
friend class pmacV3Controller;
};
/*----------------------------------------------------------------------------------------------*/
class 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 */

View File

@@ -13,11 +13,6 @@
* This affects also the commands they understand.
*
* Mark Koennecke, February 2013
*
* Updated to use the MsgTxt field for error messages as
* used at ESS and SINQ
*
* Mark Koennecke, January 2019
********************************************/
@@ -32,19 +27,17 @@
using std::cout;
using std::endl;
#include "epicsTime.h"
#include <epicsTime.h>
#include <epicsThread.h>
#include <epicsExport.h>
#include <epicsString.h>
#include <iocsh.h>
#include <drvSup.h>
#include <registryFunction.h>
#include <errlog.h>
#include "asynOctetSyncIO.h"
#include "pmacController.h"
#include "pmacAxis.h"
#define MULT 1000.
@@ -131,23 +124,25 @@ const epicsUInt32 pmacController::PMAX_AXIS_GENERAL_PROB2 = (PMAC_STATUS2_DESIRE
extern "C" {
asynStatus pmacCreateController(const char *portName, const char *lowLevelPortName, int lowLevelPortAddress,
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 numAxis);
}
pmacController::pmacController(const char *portName, const char *lowLevelPortName, int lowLevelPortAddress,
int numAxes, double movingPollPeriod, double idlePollPeriod, const int& extraParams)
: SINQController(portName, lowLevelPortName, numAxes+1, extraParams)
int numAxes, double movingPollPeriod, double idlePollPeriod)
: asynMotorController(portName, numAxes+1, NUM_MOTOR_DRIVER_PARAMS,
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";
printf(" Constructor: %s\n", functionName);
//Initialize non static data members
lowLevelPortUser_ = NULL;
debugFlag_ = 0;
@@ -158,7 +153,7 @@ pmacController::pmacController(const char *portName, const char *lowLevelPortNam
createParam(PMAC_C_CommsErrorString, asynParamInt32, &PMAC_C_CommsError_);
// Connect our Asyn user to the low level port that is a parameter to this constructor
if (lowLevelPortConnect(lowLevelPortName, lowLevelPortAddress, &lowLevelPortUser_, "\006", (char *)"\r") != asynSuccess) {
if (lowLevelPortConnect(lowLevelPortName, lowLevelPortAddress, &lowLevelPortUser_, "\006", "\r") != asynSuccess) {
printf("%s: Failed to connect to low level asynOctetSyncIO port %s\n", functionName, lowLevelPortName);
setIntegerParam(PMAC_C_CommsError_, 1);
} else {
@@ -256,7 +251,7 @@ asynStatus pmacController::printConnectedStatus()
* @param command - String command to send.
* @response response - String response back.
*/
asynStatus pmacController::lowLevelWriteRead(int axisNo, const char *command, char *response)
asynStatus pmacController::lowLevelWriteRead(const char *command, char *response)
{
asynStatus status = asynSuccess;
@@ -265,7 +260,6 @@ asynStatus pmacController::lowLevelWriteRead(int axisNo, const char *command, ch
size_t nread = 0;
int commsError = 0;
static const char *functionName = "pmacController::lowLevelWriteRead";
pmacAxis *axis = getAxis(axisNo);
debugFlow(functionName);
@@ -292,9 +286,6 @@ asynStatus pmacController::lowLevelWriteRead(int axisNo, const char *command, ch
if (status) {
asynPrint(lowLevelPortUser_, ASYN_TRACE_ERROR, "%s: Error from pasynOctetSyncIO->writeRead. command: %s\n", functionName, command);
setIntegerParam(this->motorStatusCommsError_, 1);
if(axis!= NULL){
axis->updateMsgTxtFromDriver("Lost connection to motor controller");
}
} else {
setIntegerParam(this->motorStatusCommsError_, 0);
}
@@ -348,6 +339,8 @@ asynStatus pmacController::writeFloat64(asynUser *pasynUser, epicsFloat64 value)
pmacAxis *pAxis = NULL;
char command[64] = {0};
char response[64] = {0};
double encRatio = 1.0;
epicsInt32 encposition = 0;
char message[132];
static const char *functionName = "pmacController::writeFloat64";
@@ -415,7 +408,6 @@ asynStatus pmacController::writeFloat64(asynUser *pasynUser, epicsFloat64 value)
// bool moving = true;
// pAxis->getAxisStatus(&moving);
// } else
/*
if (function == motorLowLimit_) {
sprintf(command, "I%d14=%d", pAxis->axisNo_, (int)(value/pAxis->scale_/MULT));
asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
@@ -430,9 +422,8 @@ asynStatus pmacController::writeFloat64(asynUser *pasynUser, epicsFloat64 value)
//Execute the command.
if (command[0] != 0 && status == asynSuccess) {
status = lowLevelWriteRead(pAxis->axisNo_,command, response);
status = lowLevelWriteRead(command, response);
}
*/
//Call base class method
//This will handle callCallbacks even if the function was handled here.
@@ -470,6 +461,7 @@ asynStatus pmacController::writeInt32(asynUser *pasynUser, epicsInt32 value)
}
/** Returns a pointer to an pmacAxis object.
* Returns NULL if the axis number encoded in pasynUser is invalid.
* \param[in] pasynUser asynUser structure that encodes the axis index number. */
@@ -535,92 +527,18 @@ asynStatus pmacCreateController(const char *portName, const char *lowLevelPortNa
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 pmacHRPTAxis constructor.
* See pmacHRPTAxis::pmacHRPTAxis.
* C wrapper for the pmacAxis constructor.
* See pmacAxis::pmacAxis.
*
*/
asynStatus pmacCreateHRPTAxis(const char *pmacName, /* specify which controller by port name */
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 = "pmacCreateHRPTAxis";
static const char *functionName = "pmacCreateAxis";
pC = (pmacController*) findAsynPortDriver(pmacName);
if (!pC) {
@@ -630,97 +548,14 @@ asynStatus pmacCreateHRPTAxis(const char *pmacName, /* specify which con
}
pC->lock();
pAxis = new pmacHRPTAxis(pC, axis);
pAxis = new pmacAxis(pC, axis);
pAxis = NULL;
pC->unlock();
return asynSuccess;
}
/**
* 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.
* C Wrapper function for pmacAxis constructor.
* See pmacAxis::pmacAxis.
* This function allows creation of multiple pmacAxis objects with axis numbers 1 to numAxes.
* @param pmacName Asyn port name for the controller (const char *)
@@ -751,137 +586,6 @@ asynStatus pmacCreateAxes(const char *pmacName,
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 */
#ifdef vxWorks
@@ -906,18 +610,6 @@ 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);
}
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 */
static const iocshArg pmacCreateAxisArg0 = {"Controller port name", iocshArgString};
@@ -931,58 +623,6 @@ static void configpmacAxisCallFunc(const iocshArgBuf *args)
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 */
static const iocshArg pmacCreateAxesArg0 = {"Controller port name", iocshArgString};
static const iocshArg pmacCreateAxesArg1 = {"Num Axes", iocshArgInt};
@@ -1000,13 +640,7 @@ static void configpmacAxesCallFunc(const iocshArgBuf *args)
static void pmacControllerRegister(void)
{
iocshRegister(&configpmacCreateController, configpmacCreateControllerCallFunc);
iocshRegister(&configSeleneCreateController, configSeleneCreateControllerCallFunc);
iocshRegister(&configpmacV3CreateController, configpmacV3CreateControllerCallFunc);
iocshRegister(&configpmacAxis, configpmacAxisCallFunc);
iocshRegister(&configpmacHRPTAxis, configpmacHRPTAxisCallFunc);
iocshRegister(&configSeleneCreateAxis, configSeleneCreateAxisCallFunc);
iocshRegister(&configLiftAxis, configLiftAxisCallFunc);
iocshRegister(&configpmacV3Axis, configpmacV3AxisCallFunc);
iocshRegister(&configpmacAxes, configpmacAxesCallFunc);
}
epicsExportRegistrar(pmacControllerRegister);
@@ -1015,4 +649,3 @@ epicsExportRegistrar(pmacControllerRegister);
} // extern "C"

View File

@@ -7,27 +7,23 @@
* Matthew Pearson
* 23 May 2012
*
*
* Modified to use the MsgTxt field for SINQ
*
* Mark Koennecke, January 2019
********************************************/
#ifndef pmacController_H
#define pmacController_H
#include "SINQController.h"
#include "asynMotorController.h"
#include "asynMotorAxis.h"
#include "pmacAxis.h"
#define PMAC_C_GlobalStatusString "PMAC_C_GLOBALSTATUS"
#define PMAC_C_CommsErrorString "PMAC_C_COMMSERROR"
class pmacController : public SINQController {
class pmacController : public asynMotorController {
public:
pmacController(const char *portName, const char *lowLevelPortName, int lowLevelPortAddress, int numAxes, double movingPollPeriod,
double idlePollPeriod, const int& extraParams=2);
pmacController(const char *portName, const char *lowLevelPortName, int lowLevelPortAddress, int numAxes, double movingPollPeriod,
double idlePollPeriod);
virtual ~pmacController();
@@ -49,13 +45,13 @@ class pmacController : public SINQController {
int PMAC_C_GlobalStatus_;
int PMAC_C_CommsError_;
#define LAST_PMAC_PARAM PMAC_C_CommsError__
void debugFlow(const char *message);
asynStatus lowLevelWriteRead(int axisNo, const char *command, char *response);
private:
asynUser* lowLevelPortUser_;
epicsUInt32 debugFlag_;
asynStatus lowLevelWriteRead(const char *command, char *response);
int lowLevelPortConnect(const char *port, int addr, asynUser **ppasynUser, char *inputEos, char *outputEos);
void debugFlow(const char *message);
//static class data members
@@ -136,57 +132,9 @@ class pmacController : public SINQController {
static const epicsUInt32 PMAX_AXIS_GENERAL_PROB2;
friend class pmacAxis;
friend class pmacHRPTAxis;
friend class SeleneAxis;
friend class LiftAxis;
friend class pmacV3Axis;
};
#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 */

View File

@@ -2,23 +2,21 @@
# SINQ specific DB definitions
#---------------------------------------------
registrar(EL734Register)
registrar(PhytronRegister)
registrar(EuroMoveRegister)
registrar(NanotecRegister)
registrar(pmacControllerRegister)
registrar(pmacAsynIPPortRegister)
#--------------------------------------------------------
# With the PSI module build system, including these items actually
# hurts. It causes missing symbols when loading the shared lib.
#------------------------------------------------------------------
#include "/ioc/modules/asyn/427.0.1/R3.14.12/dbd/asyn.dbd"
#include "/ioc/modules/motorBase/6.9.12/R3.14.12/dbd/motorBase.dbd"
#include "/ioc/modules/SynApps/1.13.0/R3.14.12/dbd/SynApps.dbd"
#include "/ioc/modules/scaler/koennecke/R3.14.12/dbd/scaler.dbd"
addpath "/opt/epics/modules/asyn/4.27.0/3.14.12.5/dbd"
addpath "/opt/epics/bases/base-3.14.12.5/dbd"
addpath "/opt/epics/modules/motor/6.10.0/3.14.12.5/dbd"
#addpath "/usr/local/epics/support/std-3-1/dbd"
addpath "/opt/epics/modules/synAppsStd/3.4.1/3.14.12.5/dbd"
include "asyn.dbd"
include "motor.dbd"
#include "motorSupport.dbd"
include "synAppsStd.dbd"
device(scaler,INST_IO,devScalerEL737,"asynScalerEL737")
#--------- For lakeshore and magnets
#include "/ioc/modules/stream/2.7.9/R3.14.12/dbd/stream.dbd"
#include "busy.dbd"
#--------- For lakeshore
addpath "/opt/epics/modules/streamdevice/2.6.0/3.14.12.5/dbd"
include "streamdevice.dbd"
addpath "/opt/epics/modules/busy/1.6.0/3.14.12.5/dbd"
include "busy.dbd"

View File

@@ -1,88 +0,0 @@
#!/usr/bin/env python3
# -*- coding: iso-8859-1 -*-
"""
Created on Thur Feb 06 10:22:42 2020
@author: gaston emmanuel exil
"""
#pip install pyusb
#sudo cp 10-llbDevices.rules /etc/udev/rules.d/
#sudo udevadm control --reload-rules && udevadm trigger
#reboot
import sys
import usb.core
import usb.util
from time import sleep
# 1. Device
llbVendorID=0x04B4
llbProductID=0x1002
# 2. Configuration
CONFIGURATION_EV3 = 1 # 1-based
# 3. Interface
INTERFACE_EV3 = 0 # 0-based
# 4. Alternate setting
SETTING_EV3 = 0 # 0-based
# 5. Endpoint
ENDPOINT_EV3 = 1 # 0-based
# find our device
device = usb.core.find(idVendor=llbVendorID, idProduct=llbProductID)
# was it found?
if device is None:
raise ValueError('Device not found')
sys.exit(1)
else:
if device._manufacturer is None:
device._manufacturer = usb.util.get_string(device, device.iManufacturer)
print("manufacturer: ", str(device._manufacturer))
if device._product is None:
device._product = usb.util.get_string(device, device.iProduct)
print("product: ", str(device._product))
# By default, the kernel will claim the device and make it available via
# /dev/usb/hiddevN and /dev/hidrawN which also prevents us
# from communicating otherwise. This removes these kernel devices.
# Yes, it is weird to specify an interface before we get to a configuration.
if device.is_kernel_driver_active(INTERFACE_EV3):
print("Detaching kernel driver")
device.detach_kernel_driver(INTERFACE_EV3)
# claim the device
usb.util.claim_interface(device, INTERFACE_EV3)
# write endpoint
endpoint_BulkOut = device[0][(0,0)][0]
# Read endpoint
endpoint_BulkIn = device[0][(0,0)][2]
try:
command = "L"+chr(13)
assert device.write(endpoint_BulkOut, command.encode('utf-8'), 100) == len(command)
ret = device.read(endpoint_BulkIn, endpoint_BulkIn.wMaxPacketSize, timeout=30000)
print(ret)
#byte_str = "".join(chr(n) for n in ret)
print(ret.tostring())
command = "A1,4"+chr(13)
assert device.write(endpoint_BulkOut, command.encode('utf-8'), 100) == len(command)
ret = device.read(endpoint_BulkIn, endpoint_BulkIn.wMaxPacketSize, timeout=30000)
print(ret)
byte_str = "".join(chr(n) for n in ret)
print(ret.tostring())
except Exception as e:
print(e)
# release the device
usb.util.release_interface(device, INTERFACE_EV3)
# reattach the device to the OS kernel
#device.attach_kernel_driver(INTERFACE_EV3)