Start with motion plugin as base (just minor cleanup and renaming made) WIP

This commit is contained in:
2024-01-29 10:37:22 +01:00
commit 0dd0161ffb
37 changed files with 2945 additions and 0 deletions

18
.gitignore vendored Normal file
View File

@@ -0,0 +1,18 @@
*~
*-dev
modules.order
Module.symvers
Mkfile.old
core.*
#*
.#*
\#*
*.local
\#*
.cvsignore
*_old/
*PVs.list
*-loc/*.Makefile
ecmc_plugin_motion/*.Makefile
*__*
O*

7
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,7 @@
{
"files.associations": {
"string_view": "cpp",
"stdexcept": "cpp",
"iosfwd": "cpp"
}
}

0
Db/.keep Normal file
View File

View File

@@ -0,0 +1,258 @@
# Act pos
record(waveform,"$(P)Plg-Mtn${INDEX}-PosAct-Arr"){
info(asyn:FIFO, "1000")
field(DESC, "Pos Act")
field(PINI, "1")
field(DTYP, "asynFloat64ArrayIn")
field(INP, "@asyn(PLUGIN.MOTION_${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.motion_${INDEX}.actpos_arr")
field(FTVL, "DOUBLE")
field(NELM, "$(NELM)")
field(SCAN, "I/O Intr")
field(TSE, "0")
field(EGU, "${RAW_EGU= }")
}
# Set pos
record(waveform,"$(P)Plg-Mtn${INDEX}-PosSet-Arr"){
info(asyn:FIFO, "1000")
field(DESC, "Pos Set")
field(PINI, "1")
field(DTYP, "asynFloat64ArrayIn")
field(INP, "@asyn(PLUGIN.MOTION_${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.motion_${INDEX}.setpos_arr")
field(FTVL, "DOUBLE")
field(NELM, "$(NELM)")
field(SCAN, "I/O Intr")
field(TSE, "0")
field(EGU, "${RAW_EGU= }")
}
# Position Error
record(waveform,"$(P)Plg-Mtn${INDEX}-PosErr-Arr"){
info(asyn:FIFO, "1000")
field(DESC, "Pos Error (diff)")
field(PINI, "1")
field(DTYP, "asynFloat64ArrayIn")
field(INP, "@asyn(PLUGIN.MOTION_${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.motion_${INDEX}.diffpos_arr")
field(FTVL, "DOUBLE")
field(NELM, "$(NELM)")
field(SCAN, "I/O Intr")
field(TSE, "0")
field(EGU, "${RAW_EGU= }")
}
# X axis time (reltive within buffer)
record(waveform,"$(P)Plg-Mtn${INDEX}-Time-Arr"){
info(asyn:FIFO, "1000")
field(DESC, "Rel. time within buffer")
field(PINI, "1")
field(DTYP, "asynFloat64ArrayIn")
field(INP, "@asyn(PLUGIN.MOTION_${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.motion_${INDEX}.x_arr")
field(FTVL, "DOUBLE")
field(NELM, "$(NELM)")
field(SCAN, "I/O Intr")
field(TSE, "0")
}
# Axis Enable
record(waveform,"$(P)Plg-Mtn${INDEX}-Ena-Arr"){
info(asyn:FIFO, "1000")
field(DESC, "Enable")
field(PINI, "1")
field(DTYP, "asynInt8ArrayIn")
field(INP, "@asyn(PLUGIN.MOTION_${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.motion_${INDEX}.enable_arr")
field(FTVL, "CHAR")
field(NELM, "$(NELM)")
field(SCAN, "I/O Intr")
field(TSE, "0")
}
# Axis Enabled
record(waveform,"$(P)Plg-Mtn${INDEX}-EnaAct-Arr"){
info(asyn:FIFO, "1000")
field(DESC, "Enabled")
field(PINI, "1")
field(DTYP, "asynInt8ArrayIn")
field(INP, "@asyn(PLUGIN.MOTION_${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.motion_${INDEX}.enabled_arr")
field(FTVL, "CHAR")
field(NELM, "$(NELM)")
field(SCAN, "I/O Intr")
field(TSE, "0")
}
# Axis Busy
record(waveform,"$(P)Plg-Mtn${INDEX}-Bsy-Arr"){
info(asyn:FIFO, "1000")
field(DESC, "Busy")
field(PINI, "1")
field(DTYP, "asynInt8ArrayIn")
field(INP, "@asyn(PLUGIN.MOTION_${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.motion_${INDEX}.busy_arr")
field(FTVL, "CHAR")
field(NELM, "$(NELM)")
field(SCAN, "I/O Intr")
field(TSE, "0")
}
# Axis Execute
record(waveform,"$(P)Plg-Mtn${INDEX}-Exe-Arr"){
info(asyn:FIFO, "1000")
field(DESC, "Execute")
field(PINI, "1")
field(DTYP, "asynInt8ArrayIn")
field(INP, "@asyn(PLUGIN.MOTION_${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.motion_${INDEX}.execute_arr")
field(FTVL, "CHAR")
field(NELM, "$(NELM)")
field(SCAN, "I/O Intr")
field(TSE, "0")
}
# Axis Traj source
record(waveform,"$(P)Plg-Mtn${INDEX}-TrjSrc-Arr"){
info(asyn:FIFO, "1000")
field(DESC, "Traj source")
field(PINI, "1")
field(DTYP, "asynInt8ArrayIn")
field(INP, "@asyn(PLUGIN.MOTION_${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.motion_${INDEX}.trajsrc_arr")
field(FTVL, "CHAR")
field(NELM, "$(NELM)")
field(SCAN, "I/O Intr")
field(TSE, "0")
}
# Axis Enc source
record(waveform,"$(P)Plg-Mtn${INDEX}-EncSrc-Arr"){
info(asyn:FIFO, "1000")
field(DESC, "Enc source")
field(PINI, "1")
field(DTYP, "asynInt8ArrayIn")
field(INP, "@asyn(PLUGIN.MOTION_${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.motion_${INDEX}.encsrc_arr")
field(FTVL, "CHAR")
field(NELM, "$(NELM)")
field(SCAN, "I/O Intr")
field(TSE, "0")
}
# Axis At target
record(waveform,"$(P)Plg-Mtn${INDEX}-AtTrg-Arr"){
info(asyn:FIFO, "1000")
field(DESC, "At target")
field(PINI, "1")
field(DTYP, "asynInt8ArrayIn")
field(INP, "@asyn(PLUGIN.MOTION_${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.motion_${INDEX}.attarget_arr")
field(FTVL, "CHAR")
field(NELM, "$(NELM)")
field(SCAN, "I/O Intr")
field(TSE, "0")
}
# Axis Error Id
record(waveform,"$(P)Plg-Mtn${INDEX}-ErrId-Arr"){
info(asyn:FIFO, "1000")
field(DESC, "Error Id")
field(PINI, "1")
field(DTYP, "asynInt32ArrayIn")
field(INP, "@asyn(PLUGIN.MOTION_${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.motion_${INDEX}.error_arr")
field(FTVL, "LONG")
field(NELM, "$(NELM)")
field(SCAN, "I/O Intr")
field(TSE, "0")
}
# Axis Error Id
record(waveform,"$(P)Plg-Mtn${INDEX}-Stat-Arr"){
info(asyn:FIFO, "1000")
field(DESC, "Status wd")
field(PINI, "1")
field(DTYP, "asynInt32ArrayIn")
field(INP, "@asyn(PLUGIN.MOTION_${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.motion_${INDEX}.statuswd_arr")
field(FTVL, "LONG")
field(NELM, "$(NELM)")
field(SCAN, "I/O Intr")
field(TSE, "0")
}
record(bo,"$(P)Plg-Mtn${INDEX}-EnaCmd-RB"){
info(asyn:READBACK,"1")
field(DESC, "Plg Enable")
field(DTYP,"asynInt32")
field(OUT, "@asyn(PLUGIN.MOTION_${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.motion_${INDEX}.enable")
field(ZNAM,"FALSE")
field(ONAM,"TRUE")
field(DOL, "0")
field(VAL, "0")
}
record(ao,"$(P)Plg-Mtn${INDEX}-AxCmd-RB"){
info(asyn:READBACK,"1")
field(DESC, "Axis")
field(DTYP,"asynInt32")
field(OUT, "@asyn(PLUGIN.MOTION_${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.motion_${INDEX}.axis_id")
field(DOL, "0")
field(VAL, "1")
}
record(ai,"$(P)Plg-Mtn${INDEX}-SmpHz-RB"){
info(asyn:READBACK,"1")
field(DESC, "Sample rate")
field(DTYP,"asynFloat64")
field(INP, "@asyn(PLUGIN.MOTION_${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.motion_${INDEX}.samplerate")
field(VAL, "1")
field(EGU, "Hz")
field(SCAN, "I/O Intr")
}
record(ai,"$(P)Plg-Mtn${INDEX}-BuffSze"){
info(asyn:READBACK,"1")
field(DESC, "Buffer Size")
field(DTYP,"asynInt32")
field(INP, "@asyn(PLUGIN.MOTION_${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.motion_${INDEX}.buff_size")
field(VAL, "1")
}
record(ai,"$(P)Plg-Mtn${INDEX}-ElmCnt"){
info(asyn:READBACK,"1")
field(DESC, "Elements in buffer count")
field(DTYP,"asynInt32")
field(INP, "@asyn(PLUGIN.MOTION_${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.motion_${INDEX}.elem_count")
field(VAL, "1")
}
record(bo,"$(P)Plg-Mtn${INDEX}-TrgCmd-RB"){
info(asyn:READBACK,"1")
field(DESC, "Trigg command")
field(DTYP,"asynInt32")
field(OUT, "@asyn(PLUGIN.MOTION_${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.motion_${INDEX}.trigg")
field(ZNAM,"IDLE")
field(ONAM,"TRIGG")
field(VAL, "0")
field(HIGH, 0.001)
}
record(longout,"$(P)Plg-Mtn${INDEX}-Mde-RB"){
info(asyn:READBACK,"1")
field(DESC, "Mode selection")
field(PINI, "1")
field(TSE, "0")
field(DTYP, "asynInt32")
field(OUT, "@asyn(PLUGIN.MOTION_${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.motion_${INDEX}.mode")
field(SCAN, "Passive")
}
record(longout,"$(P)Plg-Mtn${INDEX}-Cmd-RB"){
info(asyn:READBACK,"1")
field(DESC, "Command")
field(PINI, "1")
field(TSE, "0")
field(DTYP, "asynInt32")
field(OUT, "@asyn(PLUGIN.MOTION_${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.motion_${INDEX}.cmd")
field(SCAN, "Passive")
}
record(longin,"$(P)Plg-Mtn${INDEX}-Stat"){
info(asyn:READBACK,"1")
field(DESC, "Status")
field(PINI, "1")
field(TSE, "0")
field(DTYP, "asynInt32")
field(INP, "@asyn(PLUGIN.MOTION_${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.motion_${INDEX}.status")
field(SCAN, "I/O Intr")
}

46
GNUmakefile Normal file
View File

@@ -0,0 +1,46 @@
include /ioc/tools/driver.makefile
MODULE = ecmc_plugin_safety
BUILDCLASSES = Linux
ARCH_FILTER = deb10%
# Run 7.0.6 for now
EXCLUDE_VERSIONS+=3 7.0.5 7.0.6
IGNORE_MODULES += asynMotor
IGNORE_MODULES += motorBase
USR_CXXFLAGS += -std=c++17
OPT_CXXFLAGS_YES = -O3
# dependencies
# ECmasterECMC_VERSION = v1.1.0
# motorECMC_VERSION = 7.0.7-ESS
ecmc_VERSION = v9.0.1_RC4
################################################################################
# THIS RELATES TO THE EtherCAT MASTER LIBRARY
# IT IS OF PARAMOUNT IMPORTANCE TO LOAD THE PROPER KERNEL MODULE
# ################################################################################
USR_LDFLAGS += -lethercat
EC_MASTER_LIB = ${EPICS_MODULES}/ECmasterECMC/${ECmasterECMC_VERSION}/R${EPICSVERSION}/lib/${T_A}
USR_LDFLAGS += -Wl,-rpath=${EC_MASTER_LIB}
USR_LDFLAGS += -L ${EC_MASTER_LIB}
BASE_DIR = .
SRC_DIR = $(BASE_DIR)/src
DB_DIR = $(BASE_DIR)/Db
SOURCES += $(SRC_DIR)/ecmcPluginSafety.c
SOURCES += $(SRC_DIR)/ecmcSafetyPlgWrap.cpp
SOURCES += $(SRC_DIR)/ecmcSafetyPlg.cpp
#SOURCES += $(foreach d,${SRC_DIR}, $(wildcard $d/*.c) $(wildcard $d/*.cpp))
HEADERS += $(foreach d,${SRC_DIR}, $(wildcard $d/*.h))
DBDS += $(foreach d,${SRC_DIR}, $(wildcard $d/*.dbd))
SCRIPTS += $(BASE_DIR)/startup.cmd
SCRIPTS += $(BASE_DIR)/addMotionObj.cmd
TEMPLATES += $(wildcard $(DB_DIR)/*.template)

11
README.md Normal file
View File

@@ -0,0 +1,11 @@
ecmc_plugin_safety
======
Plugin designed for interfacing safety plc:s
IMPORTANT: this plugin does not offer any safety functionality. Its just a standard interface to an external safety systtem.

0
cmds/.keep Normal file
View File

11
configure/CONFIG Normal file
View File

@@ -0,0 +1,11 @@
#
VARS_EXCLUDES := $(.VARIABLES)
include $(TOP)/configure/RELEASE
include $(TOP)/configure/CONFIG_MODULE
E3_REQUIRE_LOCATION := $(EPICS_BASE)/$(E3_REQUIRE_NAME)/$(E3_REQUIRE_VERSION)
REQUIRE_CONFIG := $(E3_REQUIRE_LOCATION)/configure
include $(REQUIRE_CONFIG)/CONFIG

40
configure/CONFIG_MODULE Normal file
View File

@@ -0,0 +1,40 @@
#
EPICS_MODULE_NAME:=ecmc_plugin_motion
EPICS_MODULE_TAG:=master
#
E3_MODULE_VERSION:=master
# DEPENDENT MODULE VERSION
# For Example,
ECMC_DEP_VERSION:=v9.0.1_RC1
ASYN_DEP_VERSION:=4.41.0
EXPRTK_DEP_VERSION:=addCompFunc
MOTOR_DEP_VERSION:=7.0.6
RUCKIG_DEP_VERSION:=1.0.0
#DEVLIB2_DEP_VERSION:=2.9.0
#PCRE_DEP_VERSION:=8.41.0
#ADCORE_DEP_VERSION:=3.7.0
#ADSUPPORT_DEP_VERSION:=1.9.0
#LOKI_DEP_VERSION=1.0.0
#NDS_DEP_VERSION=2.3.3
#SIS8300DRV_DEP_VERSION=4.3.1
#SEQUENCER_DEP_VERSION=2.2.7
#
#
#E3_KMOD_SRC_PATH:=$(E3_MODULE_SRC_PATH)
#
# In most case, we don't need to touch the following variables.
#
E3_MODULE_NAME:=$(EPICS_MODULE_NAME)
E3_MODULE_SRC_PATH:=ecmc_plugin_motion
E3_MODULE_MAKEFILE:=$(EPICS_MODULE_NAME).Makefile
-include $(TOP)/configure/CONFIG_OPTIONS
# The definitions shown below can also be placed in an untracked CONFIG_MODULE.local
-include $(TOP)/configure/CONFIG_MODULE.local

6
configure/CONFIG_OPTIONS Normal file
View File

@@ -0,0 +1,6 @@
#
# WITH_PVA:=NO
#
# The definitions shown below can also be placed in an untracked CONFIG_OPTIONS.local
-include $(TOP)/configure/CONFIG_OPTIONS.local

11
configure/RELEASE Normal file
View File

@@ -0,0 +1,11 @@
#
EPICS_BASE:=${HOME}/epics/base-7.0.5
E3_REQUIRE_NAME:=require
E3_REQUIRE_VERSION:=3.4.0
# The definitions shown below can also be placed in an untracked RELEASE.local
-include $(TOP)/../../RELEASE.local
-include $(TOP)/../RELEASE.local
-include $(TOP)/configure/RELEASE.local

12
configure/RULES Normal file
View File

@@ -0,0 +1,12 @@
include $(REQUIRE_CONFIG)/RULES_E3
include $(REQUIRE_CONFIG)/DEFINES_FT
include $(REQUIRE_CONFIG)/RULES_PATCH
include $(REQUIRE_CONFIG)/RULES_E3_SITELIBS
include $(REQUIRE_CONFIG)/RULES_VLIBS
include $(REQUIRE_CONFIG)/RULES_VARS
include $(TOP)/configure/module/RULES_MODULE
-include $(TOP)/configure/module/RULES_DKMS_L

View File

@@ -0,0 +1,38 @@
# KMOD_NAME := mrf
# .PHONY: dkms_add
# dkms_add: conf
# $(MSI) -M name="$(E3_MODULE_NAME)" -M version="$(E3_MODULE_VERSION)" -M kmod_name="$(KMOD_NAME)" $(TOP)/dkms/dkms_with_msi.conf.in > $(TOP)/dkms/dkms_with_msi.conf
# $(QUIET) cat $(TOP)/dkms/dkms_with_msi.conf $(TOP)/dkms/dkms_without_msi.conf > $(TOP)/dkms/dkms.conf
# $(QUIET) install -m 644 $(TOP)/dkms/dkms.conf $(E3_KMOD_SRC_PATH)/
# $(SUDO) install -d /usr/src/$(E3_MODULE_NAME)-$(E3_MODULE_VERSION)
# $(SUDO) cp -r $(TOP)/$(E3_KMOD_SRC_PATH)/* /usr/src/$(E3_MODULE_NAME)-$(E3_MODULE_VERSION)/
# $(SUDO) $(DKMS) add $(DKMS_ARGS)
# setup:
# $(QUIET) $(SUDO2) 'echo KERNEL==\"uio*\", ATTR{name}==\"mrf-pci\", MODE=\"0666\" | tee /etc/udev/rules.d/99-$(KMOD_NAME).rules'
# $(QUIET) $(SUDO) /bin/udevadm control --reload-rules
# $(QUIET) $(SUDO) /bin/udevadm trigger
# $(QUIET) $(SUDO2) 'echo $(KMOD_NAME) | tee /etc/modules-load.d/$(KMOD_NAME).conf'
# $(QUIET) $(SUDO) depmod --quick
# $(QUIET) $(SUDO) modprobe -rv $(KMOD_NAME)
# $(QUIET) $(SUDO) modprobe -v $(KMOD_NAME)
# $(QUIET) echo ""
# $(QUIET) echo ""
# $(QUIET) echo "It is OK to see \"E3/RULES_DKMS:37: recipe for target 'setup' failed\""
# $(QUIET) echo "---------------------------------------------------------------------"
# $(QUIET) -ls -l /dev/uio* 2>/dev/null
# $(QUIET) echo "---------------------------------------------------------------------"
# setup_clean:
# $(QUIET) $(SUDO) modprobe -rv $(KMOD_NAME)
# $(SUDO) rm -f /etc/modules-load.d/$(KMOD_NAME).conf
# $(SUDO) rm -f /etc/udev/rules.d/99-$(KMOD_NAME).rules
# .PHONY: setup setup_clean

View File

@@ -0,0 +1,20 @@
#
.PHONY: db hdrs
db: conf
$(QUIET) $(E3_MODULE_MAKE_CMDS) db
hdrs:
# $(SUDO) install -m 755 -d $(E3_MODULES_INSTALL_LOCATION_INC)/pv
# cd $(E3_MODULES_INSTALL_LOCATION_INC) && $(SUDO) mv *.h pv/
#.PHONY: epics
#epics:
# $(QUIET)echo "EPICS_BASE:=$(EPICS_BASE)" > $(TOP)/$(E3_MODULE_SRC_PATH)/configure/RELEASE
# $(QUIET)echo "ASYN:=$(M_ASYN)" > $(TOP)/$(E3_MODULE_SRC_PATH)/configure/RELEASE
# $(QUIET)echo "SSCAN:=$(M_SSCAN)" >> $(TOP)/$(E3_MODULE_SRC_PATH)/configure/RELEASE
# $(QUIET)echo "SNCSEQ:=$(M_SNCSEQ)" >> $(TOP)/$(E3_MODULE_SRC_PATH)/configure/RELEASE
# $(QUIET)echo "CHECK_RELEASE:=YES" > $(TOP)/$(E3_MODULE_SRC_PATH)/configure/CONFIG_SITE
# $(QUIET)echo "INSTALL_LOCATION:=$(M_DEVLIB2)" >> $(TOP)/$(E3_MODULE_SRC_PATH)/configure/CONFIG_SITE
# $(SUDOBASH) "$(MAKE) -C $(E3_MODULE_SRC_PATH)"

28
docs/.MODULE_LOG Normal file
View File

@@ -0,0 +1,28 @@
>>
Script is used : e3TemplateGenerator.bash
Script Path : /home/anderssandstrom/plugin_ecmc/e3-tools/e3TemplateGenerator
Script Version : 1.0.8
Script Run Time : 2020Mar22-1607-33CET
User : anderssandstrom
e3-tools Hash : bf03d40
>>
>> git diff
>>
>> git diff --cached
>>
>> git diff HEAD
>>
>> Your sources are located in e3-ecmcPlugin_Simple.
>>
EPICS_MODULE_NAME : ecmcPlugin_Simple
E3_MODULE_SRC_PATH : ecmcPlugin_Simple
E3_TARGET_URL : https://github.com/anderssandstrom
>>
e3 module name : e3-ecmcPlugin_Simple
e3 target url full : https://github.com/anderssandstrom/e3-ecmcPlugin_Simple.git
>>
e3 module is located in siteMods

BIN
docs/ecmcPLC5HzFFT.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
docs/ecmcPLC5HzRAW.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

BIN
docs/gui/ecmcArrayGui.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
docs/gui/ecmcFFTGui.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
docs/gui/ecmcFFTMainGui.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

0
iocsh/.keep Normal file
View File

40
iocsh/addSafetyAxis.cmd Normal file
View File

@@ -0,0 +1,40 @@
#==============================================================================
# addMotionObj.cmd
#-------------- Information:
#- Description: ecmc_plugin_motion startup.cmd
#-
#- by Anders Sandström, Paul Scherrer Institute, 2023
#- email: anders.sandstroem@psi.ch
#-
#-###############################################################################
#-
#- Arguments
#- [mandatory]
#- PLUGIN_ID = Plugin instansiation index, must be unique for each call
#-
#- [optional]
#- AX = Axis id, default 1
#- BUFF_SIZE = Buffer size, default 1000
#- DBG = Debug mode, default 1
#- ENA = Enable operation, default 1
#- REPORT = Printout plugin details, default 1
#################################################################################
#- Load plugin: MOTION
#- Note: ECMC_PLG_MOTION_OBJ_INDEX is the index of motion object in motion plugin and not PLUGIN_ID.
#- First loaded object will therefore have index
epicsEnvSet(ECMC_PLG_MOTION_OBJ_INDEX,${ECMC_PLG_MOTION_OBJ_INDEX=0})
# Might need differet paths for PSI and ESS.. must check
epicsEnvSet(ECMC_PLUGIN_FILNAME,"$(ecmc_plugin_motion_DIR)/lib/${EPICS_HOST_ARCH=linux-x86_64}/libecmc_plugin_motion.so")
epicsEnvSet(ECMC_PLUGIN_CONFIG,"AXIS=${AX};BUFFER_SIZE=${BUFF_SIZE};DBG_PRINT=${DBG=1};ENABLE=${ENA=1};")
${SCRIPTEXEC} ${ecmccfg_DIR}loadPlugin.cmd, "PLUGIN_ID=${PLUGIN_ID},FILE=${ECMC_PLUGIN_FILNAME},CONFIG='${ECMC_PLUGIN_CONFIG}', REPORT=${REPORT=1}"
dbLoadRecords(${ecmc_plugin_motion_TEMPLATES}ecmcPluginMotion.template,"P=$(IOC):,INDEX=${ECMC_PLG_MOTION_OBJ_INDEX=0},NELM=${BUFF_SIZE=1000}")
#- Increase of index (need to keep track in order to load correct db)
ecmcEpicsEnvSetCalc("ECMC_PLG_MOTION_OBJ_INDEX" ,${ECMC_PLG_MOTION_OBJ_INDEX=0}+1)

93
iocsh/cfg/el7031.ax Normal file
View File

@@ -0,0 +1,93 @@
#General
epicsEnvSet("ECMC_MOTOR_NAME", "Axis1")
epicsEnvSet("ECMC_R", "Axis1-")
epicsEnvSet("ECMC_AXIS_NO", "1")
epicsEnvSet("ECMC_DESC", "Test EL7037")
epicsEnvSet("ECMC_EGU", "deg") # Motor Record Unit
epicsEnvSet("ECMC_PREC", "3") # Motor Record Precision
epicsEnvSet("ECMC_AXISCONFIG", "") # Extra parameters to driver
epicsEnvSet("ECMC_EC_AXIS_HEALTH", "") # Entry for axis health output (example: ec0.s1.binaryOutput01.0)
epicsEnvSet("ECMC_MOD_RANGE" , "0") # Modulo range (traj setpoints and encoder values will be in range 0..ECMC_MOD_RANGE)
epicsEnvSet("ECMC_MOD_TYPE", "0") # For positioning and MOD_RANGE is larger than 0: 0 = Normal, 1 = Always Fwd, 2 = Always Bwd, 3 = Closest Distance
#Encoder
epicsEnvSet("ECMC_ENC_SCALE_NUM" "360")
epicsEnvSet("ECMC_ENC_SCALE_DENOM" "12800")
epicsEnvSet("ECMC_ENC_TYPE" "0") # Type: 0=Incremental, 1=Absolute
epicsEnvSet("ECMC_ENC_BITS" "16") # Total bit count of encoder raw data
epicsEnvSet("ECMC_ENC_ABS_BITS", "0") # Absolute bit count (for absolute encoders) always least significant part of ECMC_ENC_BITS
epicsEnvSet("ECMC_ENC_ABS_OFFSET" "0") # Encoder offset in eng units (for absolute encoders)
epicsEnvSet("ECMC_EC_ENC_ACTPOS", "ec0.s$(DRV_ID).positionActual01") # Ethercat entry for actual position input (encoder)
epicsEnvSet("ECMC_EC_ENC_RESET", "") # Reset (if no encoder reset bit then leave empty)
epicsEnvSet("ECMC_EC_ENC_ALARM_0", "") # Error 0 (if no encoder error bit then leave empty)
epicsEnvSet("ECMC_EC_ENC_ALARM_1", "") # Error 1 (if no encoder error bit then leave empty)
epicsEnvSet("ECMC_EC_ENC_ALARM_2", "") # Error 2 (if no encoder error bit then leave empty)
epicsEnvSet("ECMC_EC_ENC_WARNING", "") # Warning (if no encoder warning bit then leave empty)
#Drive
epicsEnvSet("ECMC_DRV_TYPE" "0") # Stepper: 0. DS402: 1 (DS402 = servos and advanced stepper drives)
epicsEnvSet("ECMC_DRV_SCALE_NUM" "3600") # Fastest speed in engineering units
epicsEnvSet("ECMC_DRV_SCALE_DENOM" "32768") # I/O range for ECMC_EC_ALIAS_DRV_VELO_SET
epicsEnvSet("ECMC_EC_DRV_CONTROL", "ec0.s$(DRV_ID).driveControl01.0") # Ethercat entry for control word or bit output
epicsEnvSet("ECMC_EC_DRV_STATUS", "ec0.s$(DRV_ID).driveStatus01.1") # Ethercat entry for status word or bit input
epicsEnvSet("ECMC_EC_DRV_VELOCITY", "ec0.s$(DRV_ID).velocitySetpoint01") # Ethercat entry for velocity setpoint output
epicsEnvSet("ECMC_EC_DRV_REDUCE_TORQUE", "ec0.s$(DRV_ID).driveControl01.2") # Ethercat entry for reduce torque output
epicsEnvSet("ECMC_EC_DRV_BRAKE", "ec0.s$(DO_ID).binaryOutput01.0") # Ethercat entry for brake output
epicsEnvSet("ECMC_DRV_BRAKE_OPEN_DLY_TIME", "1000") # Brake timing parameter in cycles (default 1kHz)
epicsEnvSet("ECMC_DRV_BRAKE_CLOSE_AHEAD_TIME", "2000") # Brake timing parameter in cycles (default 1kHz)
epicsEnvSet("ECMC_EC_DRV_RESET", "ec0.s$(DRV_ID).driveControl01.1") # Reset
epicsEnvSet("ECMC_EC_DRV_ALARM_0", "ec0.s$(DRV_ID).driveStatus01.3") # Error
epicsEnvSet("ECMC_EC_DRV_ALARM_1", "ec0.s$(DRV_ID).driveStatus01.7") # Stall
epicsEnvSet("ECMC_EC_DRV_ALARM_2", "ec0.s$(DRV_ID).driveStatus01.14") # Sync error
epicsEnvSet("ECMC_EC_DRV_WARNING", "ec0.s$(DRV_ID).driveStatus01.2") # Warning
#Trajectory
epicsEnvSet("ECMC_VELO", "360.0")
epicsEnvSet("ECMC_JOG_VEL", "360.0")
epicsEnvSet("ECMC_JAR", "0.0") # JAR defaults to VELO/ACCL
epicsEnvSet("ECMC_ACCS_EGU_PER_S2", "360")
epicsEnvSet("ECMC_EMERG_DECEL", "1000") # Emergency deceleration
#Homing
epicsEnvSet("ECMC_HOME_PROC", "1")
epicsEnvSet("ECMC_HOME_POS", "0.0")
epicsEnvSet("ECMC_HOME_VEL_TO", "5")
epicsEnvSet("ECMC_HOME_VEL_FRM", "4")
epicsEnvSet("ECMC_HOME_ACC", "21")
epicsEnvSet("ECMC_HOME_DEC", "100")
epicsEnvSet("ECMC_HOME_POS_MOVE_ENA", "0") # Enable move to position after successfull homing
epicsEnvSet("ECMC_HOME_POS_MOVE_TARG_POS","0") # Target position to go to after successfull homing
#Controller
epicsEnvSet("ECMC_CNTRL_KP", "5.0")
epicsEnvSet("ECMC_CNTRL_KI", "0.02")
epicsEnvSet("ECMC_CNTRL_KD", "0.0")
epicsEnvSet("ECMC_CNTRL_KFF", "1.0")
#Monitoring
# Switches
epicsEnvSet("ECMC_EC_MON_LOWLIM", "ec0.s$(DRV_ID).ONE.0") # Ethercat entry for low limit switch input
epicsEnvSet("ECMC_EC_MON_HIGHLIM", "ec0.s$(DRV_ID).ONE.0") # Ethercat entry for high limit switch inpuit
epicsEnvSet("ECMC_EC_MON_HOME_SWITCH", "ec0.s$(DRV_ID).ONE.0") # Ethercat entry for home switch input
epicsEnvSet("ECMC_EC_MON_EXT_INTERLOCK", "ec0.s$(DRV_ID).ONE.0") # Ethercat entry for external interlock input
# Softlimits (disable with 0,0,0)
epicsEnvSet("ECMC_SOFT_LOW_LIM", "$(SM_DLLM=0)")
epicsEnvSet("ECMC_SOFT_HIGH_LIM", "$(SM_DHLM=0)")
epicsEnvSet("ECMC_DXLM_ENABLE", "0")
# Position lag
epicsEnvSet("ECMC_MON_LAG_MON_TOL", "5")
epicsEnvSet("ECMC_MON_LAG_MON_TIME", "100")
epicsEnvSet("ECMC_MON_LAG_MON_ENA", "0")
# At target
epicsEnvSet("ECMC_MON_AT_TARGET_TOL", "0.1")
epicsEnvSet("ECMC_MON_AT_TARGET_TIME", "100")
epicsEnvSet("ECMC_MON_AT_TARGET_ENA", "1")
# Velocity
epicsEnvSet("ECMC_MON_VELO_MAX", "21000.0")
epicsEnvSet("ECMC_MON_VELO_MAX_TRAJ_TIME","100")
epicsEnvSet("ECMC_MON_VELO_MAX_DRV_TIME", "200")
epicsEnvSet("ECMC_MON_VELO_MAX_ENA", "0")

View File

@@ -0,0 +1,9 @@
###############################################################################################
# For help on syntax, variables and functions, please read the file: "plcSyntaxHelp.plc"
#
# PLC Functionality Demo:
# No hardware related variables
#
static.time:=ec_get_time()/1E9;
static.sineval:=sin(2*pi*${FREQ=10}*static.time);

345
iocsh/pvs.log Normal file
View File

@@ -0,0 +1,345 @@
IOC_TEST:m0s001-Drv01-Cmd-RB
IOC_TEST:m0s001-Drv01-Spd-RB
IOC_TEST:m0s001-Enc01-PosAct
IOC_TEST:m0s001-Enc01-LtchPosAct
IOC_TEST:m0s001-Enc01-Cmd-RB
IOC_TEST:m0s001-Enc01-PosCmd-RB
IOC_TEST:Axis1-Vel-RB
IOC_TEST:Axis1-Acc-RB
IOC_TEST:Axis1-EncAct
IOC_TEST:Axis1-CfgSREV-RB
IOC_TEST:Axis1-CfgUREV-RB
IOC_TEST:Axis1-CfgPMIN-RB
IOC_TEST:Axis1-CfgPMAX-RB
IOC_TEST:Axis1-CfgSPDB-RB
IOC_TEST:Axis1-CfgRDBD-RB
IOC_TEST:Axis1-CfgRDBD-Tim-RB
IOC_TEST:Axis1-CfgPOSLAG-RB
IOC_TEST:Axis1-CfgPOSLAG-Tim-RB
IOC_TEST:Axis1-CfgDHLM-RB
IOC_TEST:Axis1-CfgDLLM-RB
IOC_TEST:Axis1-CfgVELO-RB
IOC_TEST:Axis1-CfgVMAX-RB
IOC_TEST:Axis1-CfgJVEL-RB
IOC_TEST:Axis1-CfgACCS-RB
IOC_TEST:Axis1-HomPos-RB
IOC_TEST:Axis1-PosAct
IOC_TEST:Axis1-VelAct
IOC_TEST:Axis1-PosSet
IOC_TEST:Axis1-PosErr
IOC_TEST:Axis1-PLC-Err
IOC_TEST:Plg-Mtn0-SmpHz-RB
IOC_TEST:Plg-Mtn0-BuffSze
IOC_TEST:Plg-Mtn0-ElmCnt
IOC_TEST:MCU-AppMode
IOC_TEST:MCU-ErrId
IOC_TEST:MCU-ThdLatMin
IOC_TEST:MCU-ThdLatMax
IOC_TEST:MCU-ThdPrdMin
IOC_TEST:MCU-ThdPrdMax
IOC_TEST:MCU-ThdExeMin
IOC_TEST:MCU-ThdExeMax
IOC_TEST:MCU-ThdSndMin
IOC_TEST:MCU-ThdSndMax
IOC_TEST:m0s001-Drv01-WrnAlrm
IOC_TEST:m0s001-Drv01-ErrAlrm
IOC_TEST:m0s001-Drv01-StlAlrm
IOC_TEST:m0s001-Drv01-SyncErrAlrm
IOC_TEST:m0s001-Enc01-ExtLtchOK
IOC_TEST:m0s001-Enc01-OpnCrctAlrm
IOC_TEST:m0s001-Enc01-WrnAlrm
IOC_TEST:m0s001-Enc01-SyncErrAlrm
IOC_TEST:m0s001-Online
IOC_TEST:m0s001-Operational
IOC_TEST:m0s001-Alstate-Init
IOC_TEST:m0s001-Alstate-Preop
IOC_TEST:m0s001-Alstate-Safeop
IOC_TEST:m0s001-Alstate-Op
IOC_TEST:m0s002-BO01-RB
IOC_TEST:m0s002-BO02-RB
IOC_TEST:m0s002-BO03-RB
IOC_TEST:m0s002-BO04-RB
IOC_TEST:m0s002-BO05-RB
IOC_TEST:m0s002-BO06-RB
IOC_TEST:m0s002-BO07-RB
IOC_TEST:m0s002-BO08-RB
IOC_TEST:m0s002-BO09-RB
IOC_TEST:m0s002-BO10-RB
IOC_TEST:m0s002-BO11-RB
IOC_TEST:m0s002-BO12-RB
IOC_TEST:m0s002-BO13-RB
IOC_TEST:m0s002-BO14-RB
IOC_TEST:m0s002-BO15-RB
IOC_TEST:m0s002-BO16-RB
IOC_TEST:m0s002-BO01-OvrTmpAlrm
IOC_TEST:m0s002-BO01-OpnLdAlrm
IOC_TEST:m0s002-BO01-OvrCurrAlrm
IOC_TEST:m0s002-BO01-ShrtCircAlrm
IOC_TEST:m0s002-BO02-OvrTmpAlrm
IOC_TEST:m0s002-BO02-OpnLdAlrm
IOC_TEST:m0s002-BO02-OvrCurrAlrm
IOC_TEST:m0s002-BO02-ShrtCircAlrm
IOC_TEST:m0s002-BO03-OvrTmpAlrm
IOC_TEST:m0s002-BO03-OpnLdAlrm
IOC_TEST:m0s002-BO03-OvrCurrAlrm
IOC_TEST:m0s002-BO03-ShrtCircAlrm
IOC_TEST:m0s002-BO04-OvrTmpAlrm
IOC_TEST:m0s002-BO04-OpnLdAlrm
IOC_TEST:m0s002-BO04-OvrCurrAlrm
IOC_TEST:m0s002-BO04-ShrtCircAlrm
IOC_TEST:m0s002-BO05-OvrTmpAlrm
IOC_TEST:m0s002-BO05-OpnLdAlrm
IOC_TEST:m0s002-BO05-OvrCurrAlrm
IOC_TEST:m0s002-BO05-ShrtCircAlrm
IOC_TEST:m0s002-BO06-OvrTmpAlrm
IOC_TEST:m0s002-BO06-OpnLdAlrm
IOC_TEST:m0s002-BO06-OvrCurrAlrm
IOC_TEST:m0s002-BO06-ShrtCircAlrm
IOC_TEST:m0s002-BO07-OvrTmpAlrm
IOC_TEST:m0s002-BO07-OpnLdAlrm
IOC_TEST:m0s002-BO07-OvrCurrAlrm
IOC_TEST:m0s002-BO07-ShrtCircAlrm
IOC_TEST:m0s002-BO08-OvrTmpAlrm
IOC_TEST:m0s002-BO08-OpnLdAlrm
IOC_TEST:m0s002-BO08-OvrCurrAlrm
IOC_TEST:m0s002-BO08-ShrtCircAlrm
IOC_TEST:m0s002-BO09-OvrTmpAlrm
IOC_TEST:m0s002-BO09-OpnLdAlrm
IOC_TEST:m0s002-BO09-OvrCurrAlrm
IOC_TEST:m0s002-BO09-ShrtCircAlrm
IOC_TEST:m0s002-BO10-OvrTmpAlrm
IOC_TEST:m0s002-BO10-OpnLdAlrm
IOC_TEST:m0s002-BO10-OvrCurrAlrm
IOC_TEST:m0s002-BO10-ShrtCircAlrm
IOC_TEST:m0s002-BO11-OvrTmpAlrm
IOC_TEST:m0s002-BO11-OpnLdAlrm
IOC_TEST:m0s002-BO11-OvrCurrAlrm
IOC_TEST:m0s002-BO11-ShrtCircAlrm
IOC_TEST:m0s002-BO12-OvrTmpAlrm
IOC_TEST:m0s002-BO12-OpnLdAlrm
IOC_TEST:m0s002-BO12-OvrCurrAlrm
IOC_TEST:m0s002-BO12-ShrtCircAlrm
IOC_TEST:m0s002-BO13-OvrTmpAlrm
IOC_TEST:m0s002-BO13-OpnLdAlrm
IOC_TEST:m0s002-BO13-OvrCurrAlrm
IOC_TEST:m0s002-BO13-ShrtCircAlrm
IOC_TEST:m0s002-BO14-OvrTmpAlrm
IOC_TEST:m0s002-BO14-OpnLdAlrm
IOC_TEST:m0s002-BO14-OvrCurrAlrm
IOC_TEST:m0s002-BO14-ShrtCircAlrm
IOC_TEST:m0s002-BO15-OvrTmpAlrm
IOC_TEST:m0s002-BO15-OpnLdAlrm
IOC_TEST:m0s002-BO15-OvrCurrAlrm
IOC_TEST:m0s002-BO15-ShrtCircAlrm
IOC_TEST:m0s002-BO16-OvrTmpAlrm
IOC_TEST:m0s002-BO16-OpnLdAlrm
IOC_TEST:m0s002-BO16-OvrCurrAlrm
IOC_TEST:m0s002-BO16-ShrtCircAlrm
IOC_TEST:m0s002-Online
IOC_TEST:m0s002-Operational
IOC_TEST:m0s002-Alstate-Init
IOC_TEST:m0s002-Alstate-Preop
IOC_TEST:m0s002-Alstate-Safeop
IOC_TEST:m0s002-Alstate-Op
IOC_TEST:Axis1-EnaCmd-RB
IOC_TEST:Axis1-EnaAct
IOC_TEST:Axis1-ExeCmd-RB
IOC_TEST:Axis1-Busy
IOC_TEST:Axis1-AtTarget
IOC_TEST:Axis1-Moving
IOC_TEST:Axis1-LimFwd
IOC_TEST:Axis1-LimBwd
IOC_TEST:Axis1-HomeSwitch
IOC_TEST:Axis1-Homed
IOC_TEST:Axis1-InRT
IOC_TEST:Axis1-TrjSrcTyp-RB
IOC_TEST:Axis1-EncSrcTyp-RB
IOC_TEST:Axis1-CmdFrmPLCCmd-RB
IOC_TEST:Axis1-SftLimFwdEna-RB
IOC_TEST:Axis1-SftLimBwdEna-RB
IOC_TEST:Axis1-PLC-EnaCmd-RB
IOC_TEST:Axis1-PLC-FirstScan
IOC_TEST:Axis1-Err
IOC_TEST:Axis1-Wrn
IOC_TEST:MCU-ThdRTPrioOK
IOC_TEST:MCU-ThdMemLocked
IOC_TEST:m0-LinkUp
IOC_TEST:m0-AlStates-Init
IOC_TEST:m0-AlStates-Preop
IOC_TEST:m0-AlStates-Safeop
IOC_TEST:m0-AlStates-Op
IOC_TEST:m0-Dom-RedunActive
IOC_TEST:m0-Dom-WC-Zero
IOC_TEST:m0-Dom-WC-Incomplete
IOC_TEST:m0-Dom-WC-Complete
IOC_TEST:m0-Stat-OK
REQMOD:raspberrypi-10406:exit
REQMOD:raspberrypi-10406:MODULES
REQMOD:raspberrypi-10406:VERSIONS
REQMOD:raspberrypi-10406:MOD_VER
IOC_TEST:Axis1-Arr-Stat
IOC_TEST:Axis1-PLC-Expr-RB
IOC_TEST:Plg-Mtn0-PosAct-Arr
IOC_TEST:Plg-Mtn0-PosSet-Arr
IOC_TEST:Plg-Mtn0-PosErr-Arr
IOC_TEST:Plg-Mtn0-Time-Arr
IOC_TEST:Plg-Mtn0-Ena-Arr
IOC_TEST:Plg-Mtn0-EnaAct-Arr
IOC_TEST:Plg-Mtn0-Bsy-Arr
IOC_TEST:Plg-Mtn0-Exe-Arr
IOC_TEST:Plg-Mtn0-TrjSrc-Arr
IOC_TEST:Plg-Mtn0-EncSrc-Arr
IOC_TEST:Plg-Mtn0-AtTrg-Arr
IOC_TEST:Plg-Mtn0-ErrId-Arr
IOC_TEST:MCU-ErrMsg
IOC_TEST:MCU-Updated
IOC_TEST:m0s001-Enc01-LtchCmd
IOC_TEST:Axis1-MtnCmd
IOC_TEST:Axis1-movVelCmd
IOC_TEST:Axis1-movRelCmd
IOC_TEST:Axis1-movAbsCmd
IOC_TEST:Axis1-movHomCmd
IOC_TEST:Axis1-HomProc-RB
IOC_TEST:Axis1-Type
IOC_TEST:Axis1-DrvType
IOC_TEST:Axis1-TrajType
IOC_TEST:m0s001-One
IOC_TEST:m0s001-Zero
IOC_TEST:m0s002-One
IOC_TEST:m0s002-Zero
IOC_TEST:Axis1-DIR_
IOC_TEST:Axis1-ErrRst
IOC_TEST:Axis1-HomProc
IOC_TEST:Axis1-MtnCmdData
IOC_TEST:Plg-Mtn0-Mde-RB
IOC_TEST:Plg-Mtn0-Cmd-RB
IOC_TEST:m0s001-Stat
IOC_TEST:m0s002-Stat
IOC_TEST:Axis1-MR-ErrId
IOC_TEST:Axis1-CfgRDBD-En-RB
IOC_TEST:Axis1-CfgPOSLAG-En-RB
IOC_TEST:Axis1-CfgDHLM-En-RB
IOC_TEST:Axis1-CfgDLLM-En-RB
IOC_TEST:Axis1-Stat
IOC_TEST:Axis1-ErrId
IOC_TEST:Axis1-WrnId
IOC_TEST:Plg-Mtn0-Stat
IOC_TEST:m0-Stat
IOC_TEST:m0-SlvCntr
IOC_TEST:m0-MemmapCntr
IOC_TEST:m0-DomFailCntrTot
IOC_TEST:m0-EntryCntr
IOC_TEST:m0-Dom-Stat
IOC_TEST:MCU-Cfg-Info
IOC_TEST:MCU-Cfg-Naming
IOC_TEST:MCU-Cfg-Mode
IOC_TEST:MCU-Cfg-PVA
IOC_TEST:Axis1-DbgStrToLOG
IOC_TEST:MCU-Cfg-AX1-Pfx
IOC_TEST:MCU-Cfg-AX1-Nam
IOC_TEST:MCU-Cfg-AX1-PfxNam
IOC_TEST:m0s001-EntryCntr
IOC_TEST:m0s002-EntryCntr
IOC_TEST:Axis1-SeqState
IOC_TEST:Axis1-LastIlock
IOC_TEST:m0-SlvRsp
IOC_TEST:m0-Dom-WC
IOC_TEST:m0s001-Enc01-LtchRst
IOC_TEST:Axis1-Cmd_
REQMOD:raspberrypi-10406:BaseVersion
REQMOD:raspberrypi-10406:require_VER
REQMOD:raspberrypi-10406:ecmccfg_VER
REQMOD:raspberrypi-10406:asyn_VER
REQMOD:raspberrypi-10406:exprtk_VER
REQMOD:raspberrypi-10406:motor_VER
REQMOD:raspberrypi-10406:ruckig_VER
REQMOD:raspberrypi-10406:ecmc_VER
IOC_TEST:m0s001-HWType
IOC_TEST:m0s002-HWType
IOC_TEST:Axis1-MsgTxt
REQMOD:raspberrypi-10406:ecmc_plugin_motion_VER
IOC_TEST:m0s001-Drv01-Stat
IOC_TEST:m0s001-Enc01-Stat
IOC_TEST:m0s001-Stat_
IOC_TEST:m0s002-BO01-Stat
IOC_TEST:m0s002-BO02-Stat
IOC_TEST:m0s002-BO03-Stat
IOC_TEST:m0s002-BO04-Stat
IOC_TEST:m0s002-BO05-Stat
IOC_TEST:m0s002-BO06-Stat
IOC_TEST:m0s002-BO07-Stat
IOC_TEST:m0s002-BO08-Stat
IOC_TEST:m0s002-BO09-Stat
IOC_TEST:m0s002-BO10-Stat
IOC_TEST:m0s002-BO11-Stat
IOC_TEST:m0s002-BO12-Stat
IOC_TEST:m0s002-BO13-Stat
IOC_TEST:m0s002-BO14-Stat
IOC_TEST:m0s002-BO15-Stat
IOC_TEST:m0s002-BO16-Stat
IOC_TEST:m0s002-Stat_
IOC_TEST:Axis1-Stat_
IOC_TEST:ThdRTStat_
IOC_TEST:m0-Stat_
IOC_TEST:m0-Dom-Stat_
IOC_TEST:m0s001-Enc01-LtchAutRst
IOC_TEST:Axis1-MtnCmd_
IOC_TEST:MCU-Cfg-EC-Mst
IOC_TEST:MCU-Cfg-Rate
IOC_TEST:MCU-Cfg-Time
IOC_TEST:MCU-Cfg-PV-Time
IOC_TEST:m0s001-Drv01-Cmd
IOC_TEST:m0s001-Drv01-Spd
IOC_TEST:m0s001-Enc01-Cmd
IOC_TEST:m0s001-Enc01-PosCmd
IOC_TEST:m0s001-NxtObjId
IOC_TEST:MCU-Cfg-EC-FrstObjId
IOC_TEST:m0s002-NxtObjId
IOC_TEST:Axis1-OFF_
IOC_TEST:Axis1-MRES_
IOC_TEST:Axis1-HomPos
IOC_TEST:Axis1-VelToHom
IOC_TEST:Axis1-VelFrmHom
IOC_TEST:Axis1-AccHom
IOC_TEST:Axis1-TgtPosCmd
IOC_TEST:Axis1-TgtVelCmd
IOC_TEST:Axis1-Id
IOC_TEST:MCU-Cfg-AX1-NxtObjId
IOC_TEST:MCU-Cfg-AX-FrstObjId
IOC_TEST:MCU-Cfg-PLG{Index}-NxtObjId
IOC_TEST:MCU-Cfg-PLG-FrstObjId
IOC_TEST:Plg-Mtn0-AxCmd-RB
IOC_TEST:MCU-Cfg-Eng-Mode
IOC_TEST:m0s001-Enc01-LchAutRstSp
IOC_TEST:m0s002-BO01
IOC_TEST:m0s002-BO02
IOC_TEST:m0s002-BO03
IOC_TEST:m0s002-BO04
IOC_TEST:m0s002-BO05
IOC_TEST:m0s002-BO06
IOC_TEST:m0s002-BO07
IOC_TEST:m0s002-BO08
IOC_TEST:m0s002-BO09
IOC_TEST:m0s002-BO10
IOC_TEST:m0s002-BO11
IOC_TEST:m0s002-BO12
IOC_TEST:m0s002-BO13
IOC_TEST:m0s002-BO14
IOC_TEST:m0s002-BO15
IOC_TEST:m0s002-BO16
IOC_TEST:Axis1-EnaCmd
IOC_TEST:Axis1-ExeCmd
IOC_TEST:Axis1-StpCmd
IOC_TEST:Axis1-RstCmd
IOC_TEST:Axis1-EncSrcTyp-Cmd
IOC_TEST:Axis1-TrjSrcTyp-Cmd
IOC_TEST:Axis1-PLC-EnaCmd
IOC_TEST:Axis1-CmdFrmPLCCmd
IOC_TEST:Axis1-SftLimBwdEna
IOC_TEST:Axis1-SftLimFwdEna
IOC_TEST:Plg-Mtn0-EnaCmd-RB
IOC_TEST:Plg-Mtn0-TrgCmd-RB
IOC_TEST:MCU-ErrRst
IOC_TEST:Axis1-MCU1-asyn
IOC_TEST:MCU-Cmd
IOC_TEST:Axis1

View File

@@ -0,0 +1,62 @@
##############################################################################
## Example: Configuraftion for running ecmc motion plugin
##############################################################################
## Initiation:
epicsEnvSet("IOC" ,"$(IOC="IOC_TEST")")
epicsEnvSet("SCRIPTEXEC" ,"$(SCRIPTEXEC="iocshLoad")")
require ecmccfg "9.0.1_RC1"
# run module startup.cmd (only needed at ESS PSI auto call at require)
$(ECMCCFG_INIT="")$(SCRIPTEXEC) ${ecmccfg_DIR}startup.cmd, "IOC=$(IOC),ECMC_VER=v9.0.1_RC1, EC_RATE=500"
##############################################################################
## Configure hardware
epicsEnvSet("ECMC_EC_SLAVE_NUM", "1")
${SCRIPTEXEC} ${ecmccfg_DIR}configureSlave.cmd, "SLAVE_ID=$(ECMC_EC_SLAVE_NUM), HW_DESC=EL7031, CONFIG=-Motor-Trinamic-QMot-QSH4218-41-10-035"
epicsEnvSet("DRV_ID", "${ECMC_EC_SLAVE_NUM}")
${SCRIPTEXEC} ${ecmccfg_DIR}addSlave.cmd, "HW_DESC=EL2819"
epicsEnvSet("DO_ID", "${ECMC_EC_SLAVE_NUM}")
# Configure drv input 1 as drv enable
ecmcConfigOrDie "Cfg.EcAddSdo(${DRV_ID},0x8012,0x32,1,1)"
OK
# Control external drv enable
ecmcConfigOrDie "Cfg.WriteEcEntryIDString(${DO_ID},binaryOutput02,1)"
#Apply hardware configuration
ecmcConfigOrDie "Cfg.EcApplyConfig(1)"
##############################################################################
## AXIS 1
#
epicsEnvSet("DEV", "$(IOC)")
$(SCRIPTEXEC) ($(ecmccfg_DIR)configureAxis.cmd, CONFIG=./cfg/el7031.ax)
##############################################################################
## Load plugin: MOTION
#
epicsEnvSet(ECMC_PLUGIN_CONFIG,"PLUGIN_ID=1,AX=1,BUFF_SIZE=200,DBG=0,ENA=1")
require ecmc_plugin_motion master ${ECMC_PLUGIN_CONFIG}
# below needed at ESS but not PSI:
${SCRIPTEXEC} ${ecmc_plugin_motion_DIR}startup.cmd "${ECMC_PLUGIN_CONFIG}"
##############################################################################
############# Configure diagnostics:
ecmcConfigOrDie "Cfg.EcSetDiagnostics(1)"
ecmcConfigOrDie "Cfg.EcEnablePrintouts(0)"
ecmcConfigOrDie "Cfg.EcSetDomainFailedCyclesLimit(100)"
ecmcConfigOrDie "Cfg.SetDiagAxisIndex(1)"
ecmcConfigOrDie "Cfg.SetDiagAxisFreq(2)"
ecmcConfigOrDie "Cfg.SetDiagAxisEnable(0)"
##############################################################################
############# go active:
$(SCRIPTEXEC) ($(ecmccfg_DIR)setAppMode.cmd)
iocInit
dbl > pvs.log

View File

@@ -0,0 +1,54 @@
##############################################################################
## Example: Configuraftion for running ecmc motion plugin
##############################################################################
## Initiation:
epicsEnvSet("IOC" ,"$(IOC="IOC_TEST")")
epicsEnvSet("ECMCCFG_INIT" ,"") #Only run startup once (auto at PSI, need call at ESS), variable set to "#" in startup.cmd
epicsEnvSet("SCRIPTEXEC" ,"$(SCRIPTEXEC="iocshLoad")")
require ecmccfg "sandst_a_v9.0.1_RC1" "ECMC_VER=v9.0.1_RC1"
##############################################################################
## Configure hardware
epicsEnvSet("ECMC_EC_SLAVE_NUM", "4")
${SCRIPTEXEC} ${ecmccfg_DIR}configureSlave.cmd, "SLAVE_ID=$(ECMC_EC_SLAVE_NUM), HW_DESC=EL7031, CONFIG=-Motor-Trinamic-QMot-QSH4218-41-10-035"
epicsEnvSet("DRV_ID", "${ECMC_EC_SLAVE_NUM}")
${SCRIPTEXEC} ${ecmccfg_DIR}addSlave.cmd, "SLAVE_ID=6,HW_DESC=EL2008"
epicsEnvSet(DO_ID,${ECMC_EC_SLAVE_NUM})
#Apply hardware configuration
ecmcConfigOrDie "Cfg.EcApplyConfig(1)"
##############################################################################
## AXIS 1
#
epicsEnvSet("DEV", "$(IOC)")
$(SCRIPTEXEC) ($(ecmccfg_DIR)configureAxis.cmd, CONFIG=./cfg/el7031.ax)
##############################################################################
## Load plugin: MOTION
#
epicsEnvSet(ECMC_PLUGIN_CONFIG,"PLUGIN_ID=1,AX=1,BUFF_SIZE=200,DBG=0,ENA=1")
require ecmc_plugin_motion sandst_a "${ECMC_PLUGIN_CONFIG}"
# below needed at ESS but not PSI:
#${SCRIPTEXEC} ${ecmc_plugin_motion_DIR}startup.cmd "${ECMC_PLUGIN_CONFIG}"
##############################################################################
############# Configure diagnostics:
ecmcConfigOrDie "Cfg.EcSetDiagnostics(1)"
ecmcConfigOrDie "Cfg.EcEnablePrintouts(0)"
ecmcConfigOrDie "Cfg.EcSetDomainFailedCyclesLimit(100)"
ecmcConfigOrDie "Cfg.SetDiagAxisIndex(1)"
ecmcConfigOrDie "Cfg.SetDiagAxisFreq(2)"
ecmcConfigOrDie "Cfg.SetDiagAxisEnable(0)"
##############################################################################
############# go active:
$(SCRIPTEXEC) ($(ecmccfg_DIR)setAppMode.cmd)
iocInit
dbl > pvs.log

0
qt/.keep Normal file
View File

0
src/.keep Normal file
View File

298
src/ecmcPluginSafety.c Normal file
View File

@@ -0,0 +1,298 @@
/*************************************************************************\
* Copyright (c) 2023 Paul Scherrer Institute
* ecmc is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*
* ecmcPluginExample.cpp
*
* Created on: july 10, 2023
* Author: anderssandstrom
*
\*************************************************************************/
// Needed to get headers in ecmc right...
#define ECMC_IS_PLUGIN
#define ECMC_EXAMPLE_PLUGIN_VERSION 2
#ifdef __cplusplus
extern "C" {
#endif // ifdef __cplusplus
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ecmcPluginDefs.h"
#include "ecmcMotionPlgDefs.h"
#include "ecmcMotionPlgWrap.h"
static int lastEcmcError = 0;
static char* lastConfStr = NULL;
/** Optional.
* Will be called once after successfull load into ecmc.
* Return value other than 0 will be considered error.
* configStr can be used for configuration parameters.
**/
int motionConstruct(char *configStr)
{
//This module is allowed to load several times so no need to check if loaded
// create FFT object and register data callback
lastConfStr = strdup(configStr);
return createMotionObj(configStr);
}
/** Optional function.
* Will be called once at unload.
**/
void motionDestruct(void)
{
deleteAllMotionObjs();
if(lastConfStr){
free(lastConfStr);
}
}
/** Optional function.
* Will be called each realtime cycle if definded
* ecmcError: Error code of ecmc. Makes it posible for
* this plugin to react on ecmc errors
* Return value other than 0 will be considered to be an error code in ecmc.
**/
int motionRealtime(int ecmcError)
{
executeMotionObjs();
lastEcmcError = ecmcError;
return 0;
}
/** Link to data source here since all sources should be availabe at this stage
* (for example ecmc PLC variables are defined only at enter of realtime)
**/
int motionEnterRT(){
return linkDataTomotionObjs();
}
/** Optional function.
* Will be called once just before leaving realtime mode
* Return value other than 0 will be considered error.
**/
int motionExitRT(void){
return 0;
}
//// Plc function for clear of buffers
//double fft_clear(double index) {
// return (double)clearFFT((int)index);
//}
//
//// Plc function for enable
//double fft_enable(double index, double enable) {
// return (double)enableFFT((int)index, (int)enable);
//}
//
//// Plc function for trigg new measurement (will clear buffers)
//double fft_trigg(double index) {
// return (double)triggFFT((int)index);
//}
//
//// Plc function for enable
//double fft_mode(double index, double mode) {
// return (double)modeFFT((int)index, (FFT_MODE)((int)mode));
//}
//
//// Plc function for enable
//double fft_stat(double index) {
// return (double)statFFT((int)index);
//}
// Register data for plugin so ecmc know what to use
struct ecmcPluginData pluginDataDef = {
// Allways use ECMC_PLUG_VERSION_MAGIC
.ifVersion = ECMC_PLUG_VERSION_MAGIC,
// Name
.name = "ecmcPlugin_Motion",
// Description
.desc = "Motion plugin for commissioning of ecmc motion axes.",
// Option description
.optionDesc = "\n "ECMC_PLUGIN_DBG_PRINT_OPTION_CMD"<1/0> : Enables/disables printouts from plugin, default = disabled.\n"
" "ECMC_PLUGIN_AXIS_OPTION_CMD"<axis id> : Sets default source axis id.\n"
" "ECMC_PLUGIN_BUFFER_SIZE_OPTION_CMD"<size> : Data points to collect, default = 4096.\n"
" "ECMC_PLUGIN_RATE_OPTION_CMD"<rate hz> : Sampling rate in Hz"
" "ECMC_PLUGIN_MODE_OPTION_CMD"<TRIGG/CONT> : Sampling rate in Hz"
,
// Plugin version
.version = ECMC_EXAMPLE_PLUGIN_VERSION,
// Optional construct func, called once at load. NULL if not definded.
.constructFnc = motionConstruct,
// Optional destruct func, called once at unload. NULL if not definded.
.destructFnc = motionDestruct,
// Optional func that will be called each rt cycle. NULL if not definded.
.realtimeFnc = motionRealtime,
// Optional func that will be called once just before enter realtime mode
.realtimeEnterFnc = motionEnterRT,
// Optional func that will be called once just before exit realtime mode
.realtimeExitFnc = motionExitRT,
// PLC funcs
// .funcs[0] =
// { /*----fft_clear----*/
// // Function name (this is the name you use in ecmc plc-code)
// .funcName = "fft_clear",
// // Function description
// .funcDesc = "double fft_clear(index) : Clear/reset fft[index].",
// /**
// * 7 different prototypes allowed (only doubles since reg in plc).
// * Only funcArg${argCount} func shall be assigned the rest set to NULL.
// **/
// .funcArg0 = NULL,
// .funcArg1 = fft_clear,
// .funcArg2 = NULL,
// .funcArg3 = NULL,
// .funcArg4 = NULL,
// .funcArg5 = NULL,
// .funcArg6 = NULL,
// .funcArg7 = NULL,
// .funcArg8 = NULL,
// .funcArg9 = NULL,
// .funcArg10 = NULL,
// .funcGenericObj = NULL,
// },
// .funcs[1] =
// { /*----fft_enable----*/
// // Function name (this is the name you use in ecmc plc-code)
// .funcName = "fft_enable",
// // Function description
// .funcDesc = "double fft_enable(index, enable) : Set enable for fft[index].",
// /**
// * 7 different prototypes allowed (only doubles since reg in plc).
// * Only funcArg${argCount} func shall be assigned the rest set to NULL.
// **/
// .funcArg0 = NULL,
// .funcArg1 = NULL,
// .funcArg2 = fft_enable,
// .funcArg3 = NULL,
// .funcArg4 = NULL,
// .funcArg5 = NULL,
// .funcArg6 = NULL,
// .funcArg7 = NULL,
// .funcArg8 = NULL,
// .funcArg9 = NULL,
// .funcArg10 = NULL,
// .funcGenericObj = NULL,
// },
// .funcs[2] =
// { /*----fft_trigg----*/
// // Function name (this is the name you use in ecmc plc-code)
// .funcName = "fft_trigg",
// // Function description
// .funcDesc = "double fft_trigg(index) : Trigg new measurement for fft[index]. Will clear buffers.",
// /**
// * 7 different prototypes allowed (only doubles since reg in plc).
// * Only funcArg${argCount} func shall be assigned the rest set to NULL.
// **/
// .funcArg0 = NULL,
// .funcArg1 = fft_trigg,
// .funcArg2 = NULL,
// .funcArg3 = NULL,
// .funcArg4 = NULL,
// .funcArg5 = NULL,
// .funcArg6 = NULL,
// .funcArg7 = NULL,
// .funcArg8 = NULL,
// .funcArg9 = NULL,
// .funcArg10 = NULL,
// .funcGenericObj = NULL,
// },
// .funcs[3] =
// { /*----fft_mode----*/
// // Function name (this is the name you use in ecmc plc-code)
// .funcName = "fft_mode",
// // Function description
// .funcDesc = "double fft_mode(index, mode) : Set mode Cont(1)/Trigg(2) for fft[index].",
// /**
// * 7 different prototypes allowed (only doubles since reg in plc).
// * Only funcArg${argCount} func shall be assigned the rest set to NULL.
// **/
// .funcArg0 = NULL,
// .funcArg1 = NULL,
// .funcArg2 = fft_mode,
// .funcArg3 = NULL,
// .funcArg4 = NULL,
// .funcArg5 = NULL,
// .funcArg6 = NULL,
// .funcArg7 = NULL,
// .funcArg8 = NULL,
// .funcArg9 = NULL,
// .funcArg10 = NULL,
// .funcGenericObj = NULL,
// },
// .funcs[4] =
// { /*----fft_stat----*/
// // Function name (this is the name you use in ecmc plc-code)
// .funcName = "fft_stat",
// // Function description
// .funcDesc = "double fft_stat(index) : Get status of fft (NO_STAT, IDLE, ACQ, CALC) for fft[index].",
// /**
// * 7 different prototypes allowed (only doubles since reg in plc).
// * Only funcArg${argCount} func shall be assigned the rest set to NULL.
// **/
// .funcArg0 = NULL,
// .funcArg1 = fft_stat,
// .funcArg2 = NULL,
// .funcArg3 = NULL,
// .funcArg4 = NULL,
// .funcArg5 = NULL,
// .funcArg6 = NULL,
// .funcArg7 = NULL,
// .funcArg8 = NULL,
// .funcArg9 = NULL,
// .funcArg10 = NULL,
// .funcGenericObj = NULL,
// },
.funcs[0] = {0}, // last element set all to zero..
// PLC consts
/* CONTINIOUS MODE = 1 */
// .consts[0] = {
// .constName = "fft_CONT",
// .constDesc = "FFT Mode: Continious",
// .constValue = CONT
// },
// /* TRIGGERED MODE = 2 */
// .consts[1] = {
// .constName = "fft_TRIGG",
// .constDesc = "FFT Mode :Triggered",
// .constValue = TRIGG
// },
// /* TRIGGERED MODE = 2 */
// .consts[2] = {
// .constName = "fft_NO_STAT",
// .constDesc = "FFT Status: Invalid state",
// .constValue = NO_STAT,
// },
// /* TRIGGERED MODE = 2 */
// .consts[3] = {
// .constName = "fft_IDLE",
// .constDesc = "FFT Status: Idle state (waiting for trigger)",
// .constValue = IDLE
// },
// /* TRIGGERED MODE = 2 */
// .consts[4] = {
// .constName = "fft_ACQ",
// .constDesc = "FFT Status: Acquiring data",
// .constValue = ACQ
// },
// /* TRIGGERED MODE = 2 */
// .consts[5] = {
// .constName = "fft_CALC",
// .constDesc = "FFT Status: Calculating result",
// .constValue = CALC
// },
.consts[0] = {0}, // last element set all to zero..
};
ecmc_plugin_register(pluginDataDef);
# ifdef __cplusplus
}
# endif // ifdef __cplusplus

1064
src/ecmcSafetyPlg.cpp Normal file

File diff suppressed because it is too large Load Diff

168
src/ecmcSafetyPlg.h Normal file
View File

@@ -0,0 +1,168 @@
/*************************************************************************\
* Copyright (c) 2023 Paul Scherrer Institute
* ecmc is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*
* ecmcMotionPlg.h
*
* Created on: july 10, 2023
* Author: anderssandstrom
*
\*************************************************************************/
#ifndef ECMC_MOTION_PLG_H_
#define ECMC_MOTION_PLG_H_
#include <stdexcept>
#include "ecmcDataItem.h"
#include "ecmcAsynPortDriver.h"
#include "ecmcMotionPlgDefs.h"
#include "inttypes.h"
#include <string>
#include "dbBase.h"
#include "ecmcAxisBase.h"
#include "ecmcDataBuffer.h"
#include "epicsMutex.h"
#include "epicsEvent.h"
#define ECMC_PLUGIN_MOTION_ERROR_AXIS_OUT_OF_RANGE 1
typedef enum TRIGG_MODE{
NO_MODE = 0,
CONT = 1,
TRIGG = 2,
} TRIGG_MODE;
class ecmcMotionPlg : public asynPortDriver {
public:
/** ecmc Motion Plg class
* This object can throw:
* - bad_alloc
* - invalid_argument
* - runtime_error
* - out_of_range
*/
ecmcMotionPlg(int objIndex, // index of this object
char* configStr,
char* portName);
~ecmcMotionPlg();
// Add data to buffer (called from "external" callback)
void dataUpdatedCallback(uint8_t* data,
size_t size,
ecmcEcDataType dt);
// Call just before realtime because then all data sources should be available
void connectToDataSource();
void doWriteWorker(); // low prio worker thread
void setEnable(int enable);
void clearBuffers();
void triggMotionObject();
void executeMotionObject();
virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
virtual asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value);
virtual asynStatus readFloat64Array(asynUser *pasynUser, epicsFloat64 *value,
size_t nElements, size_t *nIn);
virtual asynStatus readFloat64(asynUser *pasynUser, epicsFloat64 *value);
private:
void parseConfigStr(char *configStr);
void addDataToBuffer(double data);
void initAsyn();
static int dataTypeSupported(ecmcEcDataType dt);
int setAxis(int axisId);
int setMode(TRIGG_MODE mode);
int setTrigg(int trigg);
void writeBuffers();
void switchBuffers();
epicsMutexId axisMutex_;
double* xAxisArray_; // FFT x axis with freqs
size_t elementsInBuffer_;
double ecmcSampleRateHz_;
int dataSourceLinked_; // To avoid link several times
int command_;
int status_;
// ecmc callback handle for use when deregister at unload
int callbackHandle_;
int destructs_;
int objectId_; // Unique object id
int triggOnce_;
int cycleCounter_;
int ignoreCycles_;
// Config options
int cfgDbgMode_; // Config: allow dbg printouts
size_t cfgArraySize_; // Config: Data set size
int cfgEnable_; // Config: Enable data acq./calc.
double cfgSampleRateHz_; // Config: Sample rate (defaults to ecmc rate)
double cfgDataSampleRateHz_;// Config: Sample for data
int cfgAxisIndex_; // Config: Enable data acq./calc.
TRIGG_MODE cfgMode_; // Config: Mode continous or triggered.
// Asyn
int asynEnableId_; // Enable/disable acq./calcs
int asynYActPosArrayId_;
int asynYSetPosArrayId_;
int asynYDiffPosArrayId_;
int asynXAxisArrayId_;
int asynTriggId_; // Trigg new measurement
int asynAxisId_; // motion axis id
int asynSRateId_; // Sample rate
int asynElementsInBufferId_; // Current buffer index
int asynBufferSizeId_; // Current buffer index
int asynCommandId_;
int asynStatusId_;
int asynModeId_;
ecmcAxisBase *axis_;
// Thread related
//epicsEvent doCalcEvent_;
// Some generic utility functions
static uint8_t getUint8(uint8_t* data);
static int8_t getInt8(uint8_t* data);
static uint16_t getUint16(uint8_t* data);
static int16_t getInt16(uint8_t* data);
static uint32_t getUint32(uint8_t* data);
static int32_t getInt32(uint8_t* data);
static uint64_t getUint64(uint8_t* data);
static int64_t getInt64(uint8_t* data);
static float getFloat32(uint8_t* data);
static double getFloat64(uint8_t* data);
static size_t getEcDataTypeByteSize(ecmcEcDataType dt);
static void printEcDataArray(uint8_t* data,
size_t size,
ecmcEcDataType dt,
int objId);
static void printComplexArray(std::complex<double>* fftBuff,
size_t elements,
int objId);
static std::string to_string(int value);
ecmcDataBuffer<epicsFloat64> *actPosBuffer_;
ecmcDataBuffer<epicsFloat64> *setPosBuffer_;
ecmcDataBuffer<epicsFloat64> *diffPosBuffer_;
ecmcDataBuffer<epicsFloat64> *xPosBuffer_;
ecmcDataBuffer<epicsInt8> *enableBuffer_;
ecmcDataBuffer<epicsInt8> *enabledBuffer_;
ecmcDataBuffer<epicsInt8> *busyBuffer_;
ecmcDataBuffer<epicsInt8> *executeBuffer_;
ecmcDataBuffer<epicsInt8> *trajSourceBuffer_;
ecmcDataBuffer<epicsInt8> *encSourceBuffer_;
ecmcDataBuffer<epicsInt8> *atTargetBuffer_;
ecmcDataBuffer<epicsInt32> *errorIdBuffer_;
ecmcDataBuffer<epicsInt32> *statusWdBuffer_;
bool bTriggInProgress_;
double xdt_;
double xTime_;
epicsEvent doWriteEvent_;
int writeBusy_;
timespec writePauseTime_;
};
#endif /* ECMC_MOTION_PLG_H_ */

39
src/ecmcSafetyPlgDefs.h Normal file
View File

@@ -0,0 +1,39 @@
/*************************************************************************\
* Copyright (c) 2023 Paul Scherrer Institute
* ecmc is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*
* ecmcMotionPlgDefs.h
*
* Created on: july 10, 2023
* Author: anderssandstrom
* Credits to https://github.com/sgreg/dynamic-loading
*
\*************************************************************************/
#ifndef ECMC_MOTION_PLG_DEFS_H_
#define ECMC_MOTION_PLG_DEFS_H_
#define ECMC_PLUGIN_ASYN_PREFIX "plugin.motion"
// Options
#define ECMC_PLUGIN_DBG_PRINT_OPTION_CMD "DBG_PRINT="
#define ECMC_PLUGIN_AXIS_OPTION_CMD "AXIS="
#define ECMC_PLUGIN_BUFFER_SIZE_OPTION_CMD "BUFFER_SIZE="
#define ECMC_PLUGIN_RATE_OPTION_CMD "RATE="
#define ECMC_PLUGIN_ENABLE_OPTION_CMD "ENABLE="
#define ECMC_PLUGIN_MODE_OPTION_CMD "MODE="
// CONT, TRIGG
#define ECMC_PLUGIN_MODE_CONT_OPTION "CONT"
#define ECMC_PLUGIN_MODE_TRIGG_OPTION "TRIGG"
/** Just one error code in "c" part of plugin
(error handled with exceptions i c++ part) */
#define ECMC_PLUGIN_MOTION_ERROR_CODE 1
// Default size (must be n²)
#define ECMC_PLUGIN_DEFAULT_ARRAY_SIZE 4096
#endif /* ECMC_MOTION_PLG_DEFS_H_ */

126
src/ecmcSafetyPlgWrap.cpp Normal file
View File

@@ -0,0 +1,126 @@
/*************************************************************************\
* Copyright (c) 2023 Paul Scherrer Institute
* ecmc is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*
* ecmcMotionPlgWrap.cpp
*
* Created on: july 10, 2023
* Author: anderssandstrom
* Credits to https://github.com/sgreg/dynamic-loading
*
\*************************************************************************/
// Needed to get headers in ecmc right...
#define ECMC_IS_PLUGIN
#include <vector>
#include <stdexcept>
#include <string>
#include "ecmcMotionPlgWrap.h"
#include "ecmcMotionPlg.h"
#define ECMC_PLUGIN_MAX_PORTNAME_CHARS 64
#define ECMC_PLUGIN_PORTNAME_PREFIX "PLUGIN.MOTION"
static std::vector<ecmcMotionPlg*> motionObjs;
static int motionObjCounter = 0;
static char portNameBuffer[ECMC_PLUGIN_MAX_PORTNAME_CHARS];
int createMotionObj(char* configStr) {
// create new ecmcMotionPlg object
ecmcMotionPlg* motionObj = NULL;
// create asynport name for new object ()
memset(portNameBuffer, 0, ECMC_PLUGIN_MAX_PORTNAME_CHARS);
snprintf (portNameBuffer, ECMC_PLUGIN_MAX_PORTNAME_CHARS,
ECMC_PLUGIN_PORTNAME_PREFIX "_%d", motionObjCounter);
try {
motionObj = new ecmcMotionPlg(motionObjCounter, configStr, portNameBuffer);
}
catch(std::exception& e) {
if(motionObj) {
delete motionObj;
}
printf("Exception: %s. Plugin will unload.\n",e.what());
return ECMC_PLUGIN_MOTION_ERROR_CODE;
}
motionObjs.push_back(motionObj);
motionObjCounter++;
return 0;
}
void deleteAllMotionObjs() {
for(std::vector<ecmcMotionPlg*>::iterator pMotionObj = motionObjs.begin(); pMotionObj != motionObjs.end(); ++pMotionObj) {
if(*pMotionObj) {
delete (*pMotionObj);
}
}
}
int linkDataTomotionObjs() {
for(std::vector<ecmcMotionPlg*>::iterator pMotionObj = motionObjs.begin(); pMotionObj != motionObjs.end(); ++pMotionObj) {
if(*pMotionObj) {
try {
(*pMotionObj)->connectToDataSource();
}
catch(std::exception& e) {
printf("Exception: %s. Plugin will unload.\n",e.what());
return ECMC_PLUGIN_MOTION_ERROR_CODE;
}
}
}
return 0;
}
int enableMotionObj(int objIndex, int enable) {
try {
motionObjs.at(objIndex)->setEnable(enable);
}
catch(std::exception& e) {
printf("Exception: %s. Motion object index out of range.\n",e.what());
return ECMC_PLUGIN_MOTION_ERROR_CODE;
}
return 0;
}
int clearMotionObj(int objIndex) {
try {
motionObjs.at(objIndex)->clearBuffers();
}
catch(std::exception& e) {
printf("Exception: %s. Motion object index out of range.\n",e.what());
return ECMC_PLUGIN_MOTION_ERROR_CODE;
}
return 0;
}
int triggMotionObj(int objIndex) {
try {
motionObjs.at(objIndex)->triggMotionObject();
}
catch(std::exception& e) {
printf("Exception: %s. Motion object index out of range.\n",e.what());
return ECMC_PLUGIN_MOTION_ERROR_CODE;
}
return 0;
}
int executeMotionObjs() {
for(std::vector<ecmcMotionPlg*>::iterator pMotionObj = motionObjs.begin(); pMotionObj != motionObjs.end(); ++pMotionObj) {
if(*pMotionObj) {
try {
(*pMotionObj)->executeMotionObject();
}
catch(std::exception& e) {
printf("Exception: %s. Plugin will unload.\n",e.what());
return ECMC_PLUGIN_MOTION_ERROR_CODE;
}
}
}
return 0;
}

109
src/ecmcSafetyPlgWrap.h Normal file
View File

@@ -0,0 +1,109 @@
/*************************************************************************\
* Copyright (c) 2023 Paul Scherrer Institute
* ecmc is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*
* ecmcMotionPlgWrap.h
*
* Created on: july 10, 2023
* Author: anderssandstrom
*
\*************************************************************************/
#ifndef ECMC_MOTION_PLG_WRAP_H_
#define ECMC_MOTION_PLG_WRAP_H_
#include "ecmcMotionPlgDefs.h"
# ifdef __cplusplus
extern "C" {
# endif // ifdef __cplusplus
/** \brief Create new Motion object
*
* The plugin supports creation of multiple Motion objects\n
* (if loaded several times).\n
* The different fft are adressed by fftindex (in other functions below).\n
* The first loaded fft get index 0 and then increases for each load.\n
* This function call will create the custom asynparameters dedicated for this plugin.\
* The configuration string needs to define a data source by:\n
* "SOURCE=<data source>;"\n
* Example:\n
* "SOURCE=ec0.s1.AI_1";\n
* \param[in] configStr Configuration string.\n
*
* \return 0 if success or otherwise an error code.\n
*/
int createMotionObj(char *configStr);
/** \brief Enable/disable Motion object
*
* Enable/disable Motion object. If disabled no data will be acquired\n
* and no calculations will be made.\n
* \param[in] fftIndex Index of fft (first loaded fft have index 0 then increases)\n
* \param[in] enable enable/disable (1/0).\n
*
* \return 0 if success or otherwise an error code.\n
*/
int enableMotionObj(int objIndex, int enable);
/** \brief Clear FFT object\n
*
* Clears buffers. After this command the acquistion can start from scratch.\n
* \param[in] fftIndex Index of fft (first loaded fft have index 0 then increases)\n
*
* \return 0 if success or otherwise an error code.\n
*/
int clearMotionObj(int objIndex);
/** \brief Set mode of FFT object
*
* The FFT object can measure in two differnt modes:\n
* CONT(1) : Continious measurement (Acq data, calc, then Acq data ..)\n
* TRIGG(2): Measurements are triggered from plc or over asyn and is only done once (untill next trigger)\n
* \param[in] fftIndex Index of fft (first loaded fft have index 0 then increases)\n
* \param[in] mode Mode CONT(1) or TRIGG(2)\n
*
* \return 0 if success or otherwise an error code.\n
*/
//int modeMotionObj(int objIndex, FFT_MODE mode);
/** \brief Trigger FFT object\n
*
* If in triggered mode a new measurment cycle is initiated (fft will be cleared first).\n
* \param[in] fftIndex Index of fft (first loaded fft have index 0 then increases)\n
*
* \return 0 if success or otherwise an error code.\n
*/
int triggMotionObj(int objIndex);
/** \brief execute FFT object\n
*
* If in triggered mode a new measurment cycle is initiated (fft will be cleared first).\n
* \param[in] fftIndex Index of fft (first loaded fft have index 0 then increases)\n
*
* \return 0 if success or otherwise an error code.\n
*/
int executeMotionObjs();
/** \brief Link data to _all_ fft objects
*
* This tells the FFT lib to connect to ecmc to find it's data source.\n
* This function should be called just before entering realtime since then all\n
* data sources in ecmc will be definded (plc sources are compiled just before runtime\n
* so are only fist accesible now).\n
* \return 0 if success or otherwise an error code.\n
*/
int linkDataTomotionObjs();
/** \brief Deletes all created fft objects\n
*
* Should be called when destructs.\n
*/
void deleteAllMotionObjs();
# ifdef __cplusplus
}
# endif // ifdef __cplusplus
#endif /* ECMC_MOTION_PLG_WRAP_H_ */

32
startup.cmd Normal file
View File

@@ -0,0 +1,32 @@
#==============================================================================
# startup.cmd
#-------------- Information:
#- Description: ecmc_plugin_motion startup.cmd
#-
#- by Anders Sandström, Paul Scherrer Institute, 2023
#- email: anders.sandstroem@psi.ch
#-
#-###############################################################################
#-
#- Arguments
#- [mandatory]
#- PLUGIN_ID = Plugin instansiation index, must be unique for each call
#-
#- [optional]
#- AX = Axis id, default 1
#- BUFF_SIZE = Buffer size, default 1000
#- DBG = Debug mode, default 1
#- ENA = Enable operation, default 1
#- REPORT = Printout plugin details, default 1
#################################################################################
#- Load plugin: MOTION
# Only allow call startup.cmd once. if more objects are needed then use addMotionObj.cmd directlly.
#- add One motion plugin object, only run startup once
${ECMC_PLG_MOTION_INIT=""}${SCRIPTEXEC} $(ecmc_plugin_motion_DIR)addMotionObj.cmd "PLUGIN_ID=${PLUGIN_ID},AX=${AX=1},BUFF_SIZE=${BUFF_SIZE=1000},DBG=${DBG=1},ENA=${ENA=1},REPORT=${REPORT=1}"
epicsEnvSet("ECMC_PLG_MOTION_INIT" ,"#")

0
template/.keep Normal file
View File