try to recover corrupted git

This commit is contained in:
Anders Sandstrom
2023-08-03 10:30:17 +02:00
commit 2c66f05238
42 changed files with 3778 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"
}
}

28
Makefile Normal file
View File

@@ -0,0 +1,28 @@
#
# Copyright (c) 2018 - 2019 European Spallation Source ERIC
#
# The program is free software: you can redistribute
# it and/or modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation, either version 2 of the
# License, or any newer version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see https://www.gnu.org/licenses/gpl-2.0.txt
#
#
# Author : Jeong Han Lee
# email : han.lee@esss.se
# Date : 2020Mar22-1607-33CET
# version : 1.0.0
TOP:=$(CURDIR)
include $(TOP)/configure/CONFIG
include $(TOP)/configure/RULES

453
README.md Normal file
View File

@@ -0,0 +1,453 @@
e3-ecmc_plugin_fft
======
ESS Site-specific EPICS module : ecmcPlugin_FFT
A shared library with FFT functionalities loadable into ecmc:
https://github.com/epics-modules/ecmc (or local ess fork https://github.com/icshwi/ecmc).
Configuration is made through ecmccfg:
https://github.com/paulscherrerinstitute/ecmccfg (ot local ess fork https://github.com/icshwi/ecmccfg)
FFT:s are calculated with the kissfft lib:
https://github.com/mborgerding/kissfft
# Introduction
The main functionality of this plugin is to make FFT analysis of ecmc data. Most data in ecmc is accessible:
1. EtherCAT data ("ec0.s1.AI_1" or "ec0.s2.mm.CH1_ARRAY")
2. Motion data ("ax1.actpos")
3. PLC data ("plcs.plc0.static.testvalue")
Precautions have been taken in order to disturb ecmc real time thread as little as possible:
1. All CPU intensive calculations are handled in a low prio work thread (not ecmc thread).
2. Communication to epics is made via a dedicated asynPortDriver (not the same that ecmc uses).
See below for configuration options and the different modes supported by this ecmc plugin.
## Loading of FFT plugin in ecmc:
A plugin is loaded by the ecmccfg command loadPlugin:
https://github.com/icshwi/ecmccfg/blob/master/scripts/loadPlugin.cmd
Example:
```
${SCRIPTEXEC} ${ecmccfg_DIR}loadPlugin.cmd, "PLUGIN_ID=0,FILE=libecmcPlugin_FFT.so,CONFIG='DBG_PRINT=1;SOURCE=ax1.actpos;RM_LIN=1;', REPORT=1
dbLoadRecords(ecmcPluginFFT.template,"P=$(IOC):,INDEX=0, NELM=${FFT_NELM}")
```
This plugin supports multiple loading. For each load of the plugin a new FFT object will be created. In order to access these plugins, from plc:s or EPICS records, they can be accessed by an index. The first FFT plugin will have index 0. The next loaded FFT plugin will have index 1...
Note: If another plugin is loaded in between the loading of FFT plugins, it will have no affect on these FFT indexes (so the FFT index is _not_ the same as plugin index).
## Configuration
The different available configuration settings:
* SOURCE= source variable : Sets source variable for FFT (example: ec0.s1.AI_1). This config is mandatory.
* DBG_PRINT=1/0 : Enables/disables printouts from plugin, default = disabled.
* NFFT= nfft : Data points to collect, default = 4096.
* SCALE=scale : Apply scale to input data, default = 1.0.
* RM_DC=1/0 : Remove DC offset of input data (SOURCE), default = disabled.
* RM_LIN=1/0 : Remove linear component input data (SOURCE), default = disabled.
* ENABLE=1/0 : Enable data acq. and calcs (can be controlled over asyn), default = disabled.
* MODE=CONT/TRIGG : Continious or triggered mode, defaults to TRIGG
* RATE=rate in hz : fft data sample rate in hz (must be lower than ecmc rate and (ecmc_rate/fft_rate)=integer), default = ecmc rate.
* BREAKTABLE= EPICS breaktable : Apply breaktable to raw value.
Example configuration string:
```
"SOURCE=ax1.poserr;MODE=TRIGG;DBG_PRINT=1;ENABLE=1;"
```
#### SOURCE (mandatory)
The data source is defined by setting the SOURCE option in the plugin configuration string.
This configuration is mandatory.
Example: Axis 1 actpos (See RM_LIN config below)
```
"DBG_PRINT=1;SOURCE=ax1.actpos;RM_LIN=1;"
```
Example: Ethercat slave 1 analog input ch1
```
"DBG_PRINT=1;SOURCE=ec0.s1.AI_1;"
```
#### DBG_PRINT (default: disabled)
Enable/disable printouts from plugin can be made bu setting the "DBG_PRINT" option.
Example: Disable
```
"DBG_PRINT=0;SOURCE=ax1.poserr;"
```
#### NFFT (default: 4096)
Defines number of samples for each measurement.
Note: Must be a n² number..
Example: 1024
```
"NFFT=1024;DBG_PRINT=0;SOURCE=ax1.poserr;"
```
#### SCALE (default 1.0)
Apply custom scale to input data.
Example: 5.0
```
"SCALE=5.0;NFFT=1024;DBG_PRINT=0;SOURCE=ax1.poserr;"
```
### RM_DC
Remove DC of input signal. Default is disabled.
Example: Remove DC offset
```
"RM_DC=1;SCALE=1;NFFT=1024;DBG_PRINT=0;SOURCE=ax1.poserr;"
```
### RM_LIN
Remove linear component of input signal. Default is disabled.
The linear component is calculated by least square method.
Could be usefull for values that increase, like actual position.
Example: Remove linear component
```
"RM_LIN=1;SCALE=1;NFFT=1024;DBG_PRINT=0;SOURCE=ax1.poserr;"
```
#### ENABLE (default: disabled)
Enable data acq. and FFT calcs. The default settings is disabled so needs to be enabled from plc or over asyn in order to start calculations.
Example: Enable at startup by config
```
"ENABLE=1;RM_DC=1;SCALE=1;NFFT=1024;DBG_PRINT=0;SOURCE=ax1.poserr;"
```
Example: Enable FFT index 0 from EPICS:
```
caput IOC_TEST:Plugin-FFT0-Enable 1
```
Example: Enable FFT index 0 from ecmc PLC code:
```
fft_enable(0,1)
```
#### MODE (default: TRIGG)
The FFT module can operate in two different modes:
* CONTINIOUS (CONT)
* TRIGGERED (TRIGG)
Continious mode:
1. Clear data buffers
2. Wait for enable (from plc or asyn/epics record or configuration(see above))
3. Data acqusition starts
4. When buffers are full a worker thread will be triggered to calculate the FFT.
5. FTT results are sent by callback over asyn to epics records
6. goto 1.
Note: data will be "lost" during calculation time.
Triggered mode:
1. Clear data buffers
2. Wait for enable (from plc or asyn/epics record or configuration(see above))
3. Wait for trigger (from plc or asyn/epics record)
3. Data acqusition starts
4. When buffers are full a worker thread will be triggered to calculate the FFT.
5. FTT results are sent by callback over asyn to epics records
6. goto 1.
Example: Mode triggered
```
"MODE=TRIGG;ENABLE=1;RM_DC=1;SCALE=1;NFFT=1024;DBG_PRINT=0;SOURCE=ax1.poserr;"
```
Example: Mode from EPICS record
```
# CONT
caput IOC_TEST:Plugin-FFT0-Mode-RB 1
# TRIGG
caput IOC_TEST:Plugin-FFT0-Mode-RB 2
```
Note: The record is a output record with readback so can both be read and written to.
#### RATE (default: the ecmc rate of the selected data source)
Sets the sample rate of the raw input data (from data source). The default value is the ecmc rate for that data source.
Note: only a lower and "integer" division of sample rate can be defined.
Example: Rate = 100Hz
```
"RATE=100;MODE=TRIGG;ENABLE=1;RM_DC=1;SCALE=1;NFFT=1024;DBG_PRINT=0;SOURCE=ax1.poserr;"
```
#### BREAKTABLE (default: no break table)
Note: The break table must be added in EPICS
Example: Apply BREAKTABLE=typeTelemess33020_21877 to raw value
```
"...;BREAKTABLE=typeTelemess33020_21877;"
```
Example: Load custom breaktable in EPICS
```
dbLoadRecords ./bptBreakTable.dbd
```
Example: breaktable (in a bptBreakTable.dbd)
```
# <raw> <eng>
breaktable(typeTelemess33020_21877) {
2502.48 0
4058.89 1.5
6164.64 3
8880.74 4.5
11993.57 6
15259.00 7.5
18371.84 9
21271.05 10.5
24658.54 12
27344.13 13.5
29297.28 15
}
```
## EPICS records
Each FFT plugin object will create a new asynportdriver-port named "PLUGIN.FFT<index>" (index is explaine above).
The reason for a dedicated asynport is to disturb ecmc as little as possible.
The plugin contains a template file, "ecmcPluginFFT.template", that will make most information availbe from records:
* Rawdata array (ro)
* FFT amplitude array (result) (ro)
* FFT x axis (frequencies) (ro)
* Status (ro)
* Mode (rw)
* Sample rate (ro)
* Enable cmd (rw)
* Trigger cmd (rw)
* NFFT (ro)
The available records from this template file can be listed by the cmd (here two FFT plugins loaded):
```
dbgrep *FFT*
IOC_TEST:Plugin-FFT0-SampleRate-Act
IOC_TEST:Plugin-FFT1-SampleRate-Act
IOC_TEST:Plugin-FFT0-Mode-RB
IOC_TEST:Plugin-FFT1-Mode-RB
IOC_TEST:Plugin-FFT0-Source
IOC_TEST:Plugin-FFT0-Raw-Data-Act
IOC_TEST:Plugin-FFT0-Spectrum-Amp-Act
IOC_TEST:Plugin-FFT0-Spectrum-X-Axis-Act
IOC_TEST:Plugin-FFT1-Source
IOC_TEST:Plugin-FFT1-Raw-Data-Act
IOC_TEST:Plugin-FFT1-Spectrum-Amp-Act
IOC_TEST:Plugin-FFT1-Spectrum-X-Axis-Act
IOC_TEST:Plugin-FFT0-Enable
IOC_TEST:Plugin-FFT0-Trigg
IOC_TEST:Plugin-FFT1-Enable
IOC_TEST:Plugin-FFT1-Trigg
IOC_TEST:Plugin-FFT0-stat
IOC_TEST:Plugin-FFT0-NFFT
IOC_TEST:Plugin-FFT1-stat
IOC_TEST:Plugin-FFT1-NFFT
```
Note: The FFT asynparameters will not be visible by the ecmcReport iocsh command since the FFT records belong to another port.
## PLC interface
### PLC Functions
1. "fft_clear(arg0);" double fft_clear(index) : Clear/resets all buffers fft[index].
2. "fft_enable(arg0, arg1);" double fft_enable(index, enable) : Set enable for fft[index].
3. "fft_trigg(arg0);" double fft_trigg(index) : Trigg new measurement for fft[index]. Will clear buffers.
4. "fft_mode(arg0, arg1);" double fft_mode(index, mode) : Set mode Cont(1)/Trigg(2) for fft[index].
5. "fft_stat(arg0);" double fft_stat(index) : Get status of fft (NO_STAT, IDLE, ACQ, CALC) for fft[index].
### PLC Constants:
These constants are for use togheter with the above listed PLC functions:
1. "fft_CONT" = 1: FFT Mode: Continious
2. "fft_TRIGG" = 2: FFT Mode :Triggered
3. "fft_NO_STAT" = 0: FFT Status: Invalid state
4. "fft_IDLE" = 1: FFT Status: Idle state (waiting for trigger)
5. "fft_ACQ" = 2: FFT Status: Acquiring data
6. "fft_CALC" = 3: FFT Status: Calculating result
## Example script
An example script can be found in the iocsh directory of this repo.
This example load 2 FFT plugin objects:
1. SOURCE="plcs.plc0.static.sineval" which is a plc variable updated as a sinus with default freq 5 Hz.
2. SOURCE="ecmc.thread.latency.max". This is the execution latency of ecmc (in nanoseconds).
Start one FFT calc over EPICS records:
```
# Enable
caput IOC_TEST:Plugin-FFT0-Enable 1
# Trigg a new calc
caput IOC_TEST:Plugin-FFT1-Trigg 1
```
#### Example input signal
Epics record: IOC_TEST:Plugin-FFT0-Raw-Data-Act
|![ecmc dep](docs/ecmcPLC5HzRAW.png)|
| :---: |
|**Figure 1** Raw data. |
#### Example FFT result
Epics records:
* X = IOC_TEST:Plugin-FFT0-Spectrum-X-Axis-Act
* Y = IOC_TEST:Plugin-FFT0-Spectrum-Amp-Act
|![ecmc dep](docs/ecmcPLC5HzFFT.png)|
| :---: |
|**Figure 2** Resulting FFT amplitude. |
#### ecmc PLC code for example:
```
static.time:=ec_get_time()/1E9;
static.sineval:=sin(2*pi*${FREQ=5}*static.time);
```
## FFT GUI
### FFT GUI (FFT and rawdata plots + controls)
A simple tool, [ecmcFFTMainGui.py](tools/ecmcFFTMainGui.py), to visualize the calculated spectrum, rawdata and also plugin controls can be found in the tools directory. The GUI connects to the plugin records over pypics framwork.
The gui are included in the ecmccomgui repo:
https://github.com/anderssandstrom/ecmccomgui
Example: ecmcFFTMainGui.py help printout
```
python ecmcFFTMainGui.py
ecmcFFTMainGui: Plots waveforms of FFT data (updates on Y data callback).
python ecmcFFTMainGui.py <prefix> <fftId>
<prefix>: Ioc prefix ('IOC_TEST:')
<fftId> : Id of fft plugin ('0')
example : python ecmcFFTMainGui.py 'IOC_TEST:' '0'
Will connect to Pvs: <prefix>Plugin-FFT<fftId>-*
```
Example: Start ecmcFFMainTGui.py for:
* predix="IOC_TEST:"
* fftPluginId=0 (the first loaded FFT plugin in the ioc)
```
python ecmcFFTMainGui.py IOC_TEST: 0
```
![ecmcFFTMainGui.py](docs/gui/ecmcFFTMainGui.png)
### FFT GUI (only FFT plot)
A simple tool, [ecmcFFTGui.py](tools/ecmcFFTGui.py), to visualize the calculated spectrum can be found in the tools directory.
The GUI connects to the plugin records over pypics framwork.
Example: ecmcFFTGui.py help printout
```
python ecmcFFTGui.py
ecmcFFTGui: Plots waveforms of FFT data (updates on Y data callback).
python ecmcFFTGui.py <x.pv> <y.pv>
example: python ecmcFFTGui.py IOC_TEST:Plugin-FFT1-Spectrum-X-Axis-Act IOC_TEST:Plugin-FFT1-Spectrum-Amp-Act
```
Example: Start ecmcFFTGui.py for spectrum amplitude and freq. waveform pvs
```
python ecmcFFTGui.py IOC_TEST:Plugin-FFT1-Spectrum-X-Axis-Act IOC_TEST:Plugin-FFT1-Spectrum-Amp-Act
```
![ecmcFFTMainGui.py](docs/gui/ecmcFFTGui.png)
### Array GUI (generic waveform plt)
A simple generic tool, [ecmcFFTGui.py](tools/ecmcFFTGui.py), to visualize wavforms.
The GUI connects to the plugin records over pypics framwork.
Example: ecmcArrayGui.py help printout
```
python ecmcArrayGui.py
ecmcArrayGui: Plots waveforms data (updates on data callback).
python ecmcArrayGui.py <y.pv>
example: python ecmcArrayGui.py IOC_TEST:Plugin-FFT0-Raw-Data-Act
```
Example: Start ecmcArrayGui.py for raw data wavform
```
python ecmcArrayGui.py IOC_TEST:Plugin-FFT0-Raw-Data-Act
```
![ecmcFFTMainGui.py](docs/gui/ecmcArrayGui.png)
### Needed packages:
* python 3.5
* epics
* PyQt5
* numpy
* matplotlib
## Plugin info
```
Plugin info:
Index = 1
Name = ecmcPlugin_FFT
Description = FFT plugin for use with ecmc.
Option description =
DBG_PRINT=<1/0> : Enables/disables printouts from plugin, default = disabled.
SOURCE=<source> : Sets source variable for FFT (example: ec0.s1.AI_1).
NFFT=<nfft> : Data points to collect, default = 4096.
SCALE=<1/0> : Apply scale, default = disabled.
RM_DC=<1/0> : Remove DC offset of input data (SOURCE), default = disabled.
ENABLE=<1/0> : Enable data acq. and calcs (can be controlled over asyn), default = disabled.
MODE=<CONT/TRIGG> : Continious or triggered mode, defaults to TRIGG
RATE=<rate in hz> : fft data sample rate in hz (must be lower than ecmc rate and (ecmc_rate/fft_rate)=integer), default = ecmc rate.
Filename = /epics/base-7.0.3.1/require/3.1.2/siteMods/ecmcPlugin_FFT/master/lib/linux-arm/libecmcPlugin_FFT.so
Config string = SOURCE=ecmc.thread.latency.max;DBG_PRINT=0;NFFT=1024;
Version = 1
Interface version = 512 (ecmc = 512)
max plc funcs = 64
max plc func args = 10
max plc consts = 64
Construct func = @0xb5022044
Enter realtime func = @0xb5022090
Exit realtime func = @0xb502203c
Realtime func = @0xb5022034
Destruct func = @0xb502206c
dlhandle = @0x1d9de28
Plc functions:
funcs[00]:
Name = "fft_clear(arg0);"
Desc = double fft_clear(index) : Clear/reset fft[index].
Arg count = 1
func = @0xb5022094
funcs[01]:
Name = "fft_enable(arg0, arg1);"
Desc = double fft_enable(index, enable) : Set enable for fft[index].
Arg count = 2
func = @0xb50220b0
funcs[02]:
Name = "fft_trigg(arg0);"
Desc = double fft_trigg(index) : Trigg new measurement for fft[index]. Will clear buffers.
Arg count = 1
func = @0xb50220d4
funcs[03]:
Name = "fft_mode(arg0, arg1);"
Desc = double fft_mode(index, mode) : Set mode Cont(1)/Trigg(2) for fft[index].
Arg count = 2
func = @0xb50220f0
funcs[04]:
Name = "fft_stat(arg0);"
Desc = double fft_stat(index) : Get status of fft (NO_STAT, IDLE, ACQ, CALC) for fft[index].
Arg count = 1
func = @0xb5022114
Plc constants:
consts[00]:
Name = "fft_CONT" = 1.000
Desc = FFT Mode: Continious
consts[01]:
Name = "fft_TRIGG" = 2.000
Desc = FFT Mode :Triggered
consts[02]:
Name = "fft_NO_STAT" = 0.000
Desc = FFT Status: Invalid state
consts[03]:
Name = "fft_IDLE" = 1.000
Desc = FFT Status: Idle state (waiting for trigger)
consts[04]:
Name = "fft_ACQ" = 2.000
Desc = FFT Status: Acquiring data
consts[05]:
Name = "fft_CALC" = 3.000
Desc = FFT Status: Calculating result
```

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

View File

@@ -0,0 +1,99 @@
#
# Copyright (c) 2023 Paul Scherrer Institute
#
# The program is free software: you can redistribute
# it and/or modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation, either version 2 of the
# License, or any newer version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see https://www.gnu.org/licenses/gpl-2.0.txt
#
#
# Author : anderssandstrom
# email : anders.sandstroem@psi.ch
# Date : 2023 July 10
# version : 0.0.0
#
## The following lines are mandatory, please don't change them.
where_am_I := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
include $(E3_REQUIRE_TOOLS)/driver.makefile
include $(E3_REQUIRE_CONFIG)/DECOUPLE_FLAGS
ifneq ($(strip $(ASYN_DEP_VERSION)),)
asyn_VERSION=$(ASYN_DEP_VERSION)
endif
ifneq ($(strip $(ECMC_DEP_VERSION)),)
ecmc_VERSION=$(ECMC_DEP_VERSION)
endif
ifneq ($(strip $(RUCKIG_DEP_VERSION)),)
ruckig_VERSION=$(RUCKIG_DEP_VERSION)
endif
ifeq ($(T_A),linux-x86_64)
# Assume that the etherlab user library is done via
# https://github.com/icshwi/etherlabmaster
USR_INCLUDES += -I/opt/etherlab/include
USR_CFLAGS += -fPIC
USR_LDFLAGS += -L /opt/etherlab/lib
USR_LDFLAGS += -lethercat
USR_LDFLAGS += -Wl,-rpath=/opt/etherlab/lib
else
ifeq ($(T_A),linux-arm)
# Assume that the etherlab user library is done via
# https://github.com/icshwi/etherlabmaster
USR_INCLUDES += -I/opt/etherlab/include
USR_CFLAGS += -fPIC
USR_LDFLAGS += -L /opt/etherlab/lib
USR_LDFLAGS += -lethercat
USR_LDFLAGS += -Wl,-rpath=/opt/etherlab/lib
else
# Assume that the etherlab user library is done via
# Yocto ESS Linux bb recipe
USR_INCLUDES += -I$(SDKTARGETSYSROOT)/usr/include/etherlab
USR_CFLAGS += -fPIC
USR_LDFLAGS += -L $(SDKTARGETSYSROOT)/usr/lib/etherlab
USR_LDFLAGS += -lethercat
USR_LDFLAGS += -Wl,-rpath=$(SDKTARGETSYSROOT)/usr/lib/etherlab
USR_LDFLAGS += -lstdc++
endif
endif
APP:="."
#APPDB:=$(APP)/Db
#APPSRC:=$(APP)/src
APPSRC:=src
APPDB:=Db
USR_CFLAGS += -shared -fPIC -Wall -Wextra
USR_LDFLAGS += -lstdc++
USR_INCLUDES += -I$(where_am_I)$(APPSRC)
TEMPLATES += $(wildcard $(APPDB)/*.db)
TEMPLATES += $(wildcard $(APPDB)/*.template)
SOURCES += $(APPSRC)/ecmcPluginMotion.c
SOURCES += $(APPSRC)/ecmcMotionPlgWrap.cpp
SOURCES += $(APPSRC)/ecmcMotionPlg.cpp
#SOURCES += $(APPSRC)/ecmcDataBuffer.cpp
SCRIPTS += startup.cmd
SCRIPTS += addMotionObj.cmd
db:
.PHONY: db
vlibs:
.PHONY: vlibs
###

View File

View File

@@ -0,0 +1,272 @@
# Parameter 0 type=asynFloat64Array, name=plugin.motion_0.actpos_arr, value is undefined DONE
# Parameter 1 type=asynFloat64Array, name=plugin.motion_0.setpos_arr, value is undefined DONE
# Parameter 2 type=asynFloat64Array, name=plugin.motion_0.diffpos_arr, value is undefined DONE
# Parameter 3 type=asynFloat64Array, name=plugin.motion_0.x_arr, value is undefined DONE
# Parameter 4 type=asynInt32, name=plugin.motion_0.enable, value=1, status=0 DONE
# Parameter 5 type=asynInt32, name=plugin.motion_0.cmd, value=0, status=0
# Parameter 6 type=asynInt32, name=plugin.motion_0.status, value=0, status=0
# Parameter 7 type=asynInt32, name=plugin.motion_0.trigg, value=0, status=0
# Parameter 8 type=asynInt32, name=plugin.motion_0.buff_size, value=25, status=0
# Parameter 9 type=asynFloat64, name=plugin.motion_0.samplerate, value=1000, status=0
# Parameter 10 type=asynInt32, name=plugin.motion_0.elem_count, value=0, status=0
# Parameter 11 type=asynInt32, name=plugin.motion_0.axis_id, value=1, status=0
# Parameter 12 type=asynInt32, name=plugin.motion_0.mode, value=0, status=0
# 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")
field(EGU, "s")
}
# 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")
field(EGU, "s")
}
# 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")
field(EGU, "s")
}
# 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")
field(EGU, "s")
}
# 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")
field(EGU, "s")
}
# 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")
field(EGU, "s")
}
# 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")
field(EGU, "s")
}
# 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")
field(EGU, "s")
}
# Axis Error Id
record(waveform,"$(P)Plg-Mtn${INDEX}-ErrId-Arr"){
info(asyn:FIFO, "1000")
field(DESC, "Error Id")
field(PINI, "1")
field(DTYP, "asynInt8ArrayIn")
field(INP, "@asyn(PLUGIN.MOTION_${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.motion_${INDEX}.error_arr")
field(FTVL, "CHAR")
field(NELM, "$(NELM)")
field(SCAN, "I/O Intr")
field(TSE, "0")
field(EGU, "s")
}
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(ao,"$(P)Plg-Mtn${INDEX}-SmpHz-RB"){
info(asyn:READBACK,"1")
field(DESC, "Sample rate")
field(DTYP,"asynInt32")
field(OUT, "@asyn(PLUGIN.MOTION_${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.motion_${INDEX}.samplerate")
field(DOL, "0")
field(VAL, "1")
field(EGU, "Hz")
}
record(ai,"$(P)Plg-Mtn${INDEX}-BuffSze"){
info(asyn:READBACK,"1")
field(DESC, "Buffer Size")
field(DTYP,"asynInt32")
field(OUT, "@asyn(PLUGIN.MOTION_${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.motion_${INDEX}.buff_size")
field(DOL, "0")
field(VAL, "1")
}
record(ai,"$(P)Plg-Mtn${INDEX}-ElmCnt"){
info(asyn:READBACK,"1")
field(DESC, "Elements in buffer count")
field(DTYP,"asynInt32")
field(OUT, "@asyn(PLUGIN.MOTION_${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.motion_${INDEX}.elem_count")
field(DOL, "0")
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(OUT, "@asyn(PLUGIN.MOTION_${INDEX},$(ADDR=0),$(TIMEOUT=1000))plugin.motion_${INDEX}.status")
field(SCAN, "Passive")
}

View File

@@ -0,0 +1,39 @@
#==============================================================================
# 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(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)

View File

View File

@@ -0,0 +1,300 @@
/*************************************************************************\
* Copyright (c) 2019 European Spallation Source ERIC
* ecmc is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*
* ecmcDataBuffer.h
*
* Created on: Mar 22, 2020
* Author: anderssandstrom
*
\*************************************************************************/
#ifndef ECMC_DATA_BUFFER_WRITE_H_
#define ECMC_DATA_BUFFER_WRITE_H_
#include "ecmcAsynPortDriver.h"
#include <stdexcept>
#include "inttypes.h"
#include <string>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "asynPortDriver.h"
#include "epicsMutex.h"
#include "ecmcMotionPlgDefs.h"
template <typename T>
struct dataBuffer {
T *data;
int dataCounter;
int id;
};
/*
Implements a data buffer with asyn callbacks.
The buffer uses two memory areas. When one mem area is full,
writes are redirected to the other buffer. The full buffer then
can be transferred to epics.
*/
template <typename T>
class ecmcDataBuffer {
public:
/** ecmc ecmcDataBuffer class
* This object can throw:
* - bad_alloc
* - invalid_argument
* - runtime_error
* - out_of_range
*/
ecmcDataBuffer(int objIndex,
int bufferIndex,
int bufferSize,
int dbgMode,
const char* asynSuffix,
asynPortDriver *asynPort) {
// prepare data buffers
bufferSize_ = bufferSize;
buffer1_.data = new T[bufferSize_];
buffer2_.data = new T[bufferSize_];
memset(&buffer1_.data[0],0,sizeof(T)*bufferSize_);
memset(&buffer2_.data[0],0,sizeof(T)*bufferSize_);
buffer1_.dataCounter = 0;
buffer1_.id = 1;
buffer2_.dataCounter = 0;
buffer2_.id = 2;
// add data to buffer
bufferAdd_ = &buffer1_;
// Buffer ready for writing to epics
bufferWrite_ = &buffer2_;
cfgDbgMode_ = dbgMode;
destructs_ = 0;
bufferSwitchMutex_ = epicsMutexCreate();
bufferIndex_ = bufferIndex;
objIndex_ = objIndex;
asynPort_ = asynPort;
asynSuffix_ = strdup(asynSuffix);
asynParamId_ = -1;
enable_ = true;
initAsyn();
}
~ecmcDataBuffer() {
delete[] buffer1_.data;
delete[] buffer2_.data;
free(asynSuffix_);
destructs_ = 1; // maybe need todo in other way..
}
void addData(T data) {
// Switch buffer if needed
if(bufferAdd_->dataCounter >= bufferSize_) {
switchBuffer();
}
epicsMutexLock(bufferSwitchMutex_);
bufferAdd_->data[bufferAdd_->dataCounter] = data;
bufferAdd_->dataCounter++;
epicsMutexUnlock(bufferSwitchMutex_);
}
void clear() {
//Fill data buffer
memset(&buffer1_.data[0],0,sizeof(T)*bufferSize_);
memset(&buffer2_.data[0],0,sizeof(T)*bufferSize_);
buffer1_.dataCounter = 0;
buffer2_.dataCounter = 0;
}
void setEnable(bool enable) {
enable_ = enable;
}
bool getBufferFull() {
return bufferAdd_->dataCounter == bufferSize_;
}
void switchBuffer(){
// ensure safe buffer switch
epicsMutexLock(bufferSwitchMutex_);
dataBuffer<T> *temp = bufferWrite_;
bufferWrite_ = bufferAdd_;
bufferAdd_ = temp;
// start from 0 in new buffer
bufferAdd_->dataCounter = 0;
epicsMutexUnlock(bufferSwitchMutex_);
}
void writeBuffer();
void initAsyn();
private:
static std::string to_string(int value){
std::ostringstream os;
os << value;
return os.str();
}
int destructs_;
int cfgDbgMode_;
int bufferSize_;
int bufferIndex_;
int objIndex_;
epicsMutexId bufferSwitchMutex_;
dataBuffer<T> buffer1_;
dataBuffer<T> buffer2_;
dataBuffer<T> *bufferAdd_;
dataBuffer<T> *bufferWrite_;
asynPortDriver *asynPort_;
char *asynSuffix_;
int asynParamId_;
bool enable_;
};
// specialized for epicsInt8
template<> inline void ecmcDataBuffer<epicsInt8>::writeBuffer() {
epicsMutexLock(bufferSwitchMutex_);
// Write asyn
asynPort_->lock();
/*asynStatus stat=*/ asynPort_->doCallbacksInt8Array(&bufferWrite_->data[0], bufferSize_, asynParamId_,0);
asynPort_->unlock();
epicsMutexUnlock(bufferSwitchMutex_);
}
// specialized for epicsInt16
template<> inline void ecmcDataBuffer<epicsInt16>::writeBuffer() {
epicsMutexLock(bufferSwitchMutex_);
// Write asyn
asynPort_->lock();
/*asynStatus stat=*/ asynPort_->doCallbacksInt16Array(&bufferWrite_->data[0], bufferSize_, asynParamId_,0);
asynPort_->unlock();
epicsMutexUnlock(bufferSwitchMutex_);
}
// specialized for epicsInt32
template<> inline void ecmcDataBuffer<int32_t>::writeBuffer() {
epicsMutexLock(bufferSwitchMutex_);
// Write asyn
asynPort_->lock();
/*asynStatus stat=*/ asynPort_->doCallbacksInt32Array(&bufferWrite_->data[0], bufferSize_, asynParamId_,0);
asynPort_->unlock();
epicsMutexUnlock(bufferSwitchMutex_);
}
// specialized for epicsInt64
template<> inline void ecmcDataBuffer<int64_t>::writeBuffer() {
epicsMutexLock(bufferSwitchMutex_);
// Write asyn
asynPort_->lock();
/*asynStatus stat=*/ asynPort_->doCallbacksInt64Array(&bufferWrite_->data[0], bufferSize_, asynParamId_,0);
asynPort_->unlock();
epicsMutexUnlock(bufferSwitchMutex_);
}
// specialized for epicsFloat32
template<> inline void ecmcDataBuffer<epicsFloat32>::writeBuffer() {
epicsMutexLock(bufferSwitchMutex_);
// Write asyn
asynPort_->lock();
/*asynStatus stat=*/ asynPort_->doCallbacksFloat32Array(&bufferWrite_->data[0], bufferSize_, asynParamId_,0);
asynPort_->unlock();
epicsMutexUnlock(bufferSwitchMutex_);
}
// specialized for epicsFloat64
template<> inline void ecmcDataBuffer<epicsFloat64>::writeBuffer() {
epicsMutexLock(bufferSwitchMutex_);
// Write asyn
asynPort_->lock();
/*asynStatus stat=*/ asynPort_->doCallbacksFloat64Array(&bufferWrite_->data[0], bufferSize_, asynParamId_,0);
asynPort_->unlock();
epicsMutexUnlock(bufferSwitchMutex_);
}
template<> inline void ecmcDataBuffer<epicsInt8>::initAsyn() {
std::string paramName = ECMC_PLUGIN_ASYN_PREFIX "_" + to_string(objIndex_) +
"." + std::string(asynSuffix_);
if( asynPort_->createParam(0, paramName.c_str(), asynParamInt8Array, &asynParamId_ ) != asynSuccess ) {
throw std::runtime_error("Failed create asyn parameter rawdata");
}
// use buffer 1 for first callback
writeBuffer();
}
template<> inline void ecmcDataBuffer<epicsInt16>::initAsyn() {
std::string paramName = ECMC_PLUGIN_ASYN_PREFIX "_" + to_string(objIndex_) +
"." + std::string(asynSuffix_);
if( asynPort_->createParam(0, paramName.c_str(), asynParamInt16Array, &asynParamId_ ) != asynSuccess ) {
throw std::runtime_error("Failed create asyn parameter rawdata");
}
// use buffer 1 for first callback
writeBuffer();
}
template<> inline void ecmcDataBuffer<epicsInt32>::initAsyn() {
std::string paramName = ECMC_PLUGIN_ASYN_PREFIX "_" + to_string(objIndex_) +
"." + std::string(asynSuffix_);
if( asynPort_->createParam(0, paramName.c_str(), asynParamInt32Array, &asynParamId_ ) != asynSuccess ) {
throw std::runtime_error("Failed create asyn parameter rawdata");
}
// use buffer 1 for first callback
writeBuffer();
}
template<> inline void ecmcDataBuffer<epicsInt64>::initAsyn() {
std::string paramName = ECMC_PLUGIN_ASYN_PREFIX "_" + to_string(objIndex_) +
"." + std::string(asynSuffix_);
if( asynPort_->createParam(0, paramName.c_str(), asynParamInt64Array, &asynParamId_ ) != asynSuccess ) {
throw std::runtime_error("Failed create asyn parameter rawdata");
}
// use buffer 1 for first callback
writeBuffer();
}
template<> inline void ecmcDataBuffer<epicsFloat32>::initAsyn() {
std::string paramName = ECMC_PLUGIN_ASYN_PREFIX "_" + to_string(objIndex_) +
"." + std::string(asynSuffix_);
if( asynPort_->createParam(0, paramName.c_str(), asynParamFloat32Array, &asynParamId_ ) != asynSuccess ) {
throw std::runtime_error("Failed create asyn parameter rawdata");
}
// use buffer 1 for first callback
writeBuffer();
}
template<> inline void ecmcDataBuffer<epicsFloat64>::initAsyn() {
std::string paramName = ECMC_PLUGIN_ASYN_PREFIX "_" + to_string(objIndex_) +
"." + std::string(asynSuffix_);
if( asynPort_->createParam(0, paramName.c_str(), asynParamFloat64Array, &asynParamId_ ) != asynSuccess ) {
throw std::runtime_error("Failed create asyn parameter rawdata");
}
// use buffer 1 for first callback
writeBuffer();
}
#endif /* ECMC_DATA_BUFFER_WRITE_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,167 @@
/*************************************************************************\
* 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_;
bool bTriggInProgress_;
double xdt_;
double xTime_;
epicsEvent doWriteEvent_;
int writeBusy_;
timespec writePauseTime_;
};
#endif /* ECMC_MOTION_PLG_H_ */

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_ */

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

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_ */

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

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
iocsh/.keep Normal file
View File

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", "90.0")
epicsEnvSet("ECMC_JOG_VEL", "90.0")
epicsEnvSet("ECMC_JAR", "0.0") # JAR defaults to VELO/ACCL
epicsEnvSet("ECMC_ACCS_EGU_PER_S2", "10")
epicsEnvSet("ECMC_EMERG_DECEL", "100") # 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);

329
iocsh/pvs.log Normal file
View File

@@ -0,0 +1,329 @@
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: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-19888:exit
REQMOD:raspberrypi-19888:MODULES
REQMOD:raspberrypi-19888:VERSIONS
REQMOD:raspberrypi-19888: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: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: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: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-19888:BaseVersion
REQMOD:raspberrypi-19888:require_VER
REQMOD:raspberrypi-19888:ecmccfg_VER
REQMOD:raspberrypi-19888:asyn_VER
REQMOD:raspberrypi-19888:exprtk_VER
REQMOD:raspberrypi-19888:motor_VER
REQMOD:raspberrypi-19888:ruckig_VER
REQMOD:raspberrypi-19888:ecmc_VER
IOC_TEST:m0s001-HWType
IOC_TEST:m0s002-HWType
IOC_TEST:Axis1-MsgTxt
REQMOD:raspberrypi-19888: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: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-FFT0-EnaCmd-RB
IOC_TEST:MCU-ErrRst
IOC_TEST:Axis1-MCU1-asyn
IOC_TEST:MCU-Cmd
IOC_TEST:Axis1

View File

@@ -0,0 +1,69 @@
##############################################################################
## 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 "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"
##############################################################################
## 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)
########################################################################s######
## Load plugin: MOTION
epicsEnvSet(ECMC_PLUGIN_CONFIG,"PLUGIN_ID=1,AX=1,BUFF_SIZE=25,DBG=0,ENA=1")
require ecmc_plugin_motion master ${ECMC_PLUGIN_CONFIG}
${SCRIPTEXEC} ${ecmc_plugin_motion_DIR}startup.cmd "${ECMC_PLUGIN_CONFIG}"
#epicsEnvSet(ECMC_PLUGIN_FILNAME,"/home/pi/epics/base-7.0.5/require/3.4.0/siteMods/ecmc_plugin_motion/master/lib/${EPICS_HOST_ARCH=linux-x86_64}/libecmc_plugin_motion.so")
#
#${SCRIPTEXEC} ${ecmccfg_DIR}loadPlugin.cmd, "PLUGIN_ID=0,FILE=${ECMC_PLUGIN_FILNAME},CONFIG='${ECMC_PLUGIN_CONFIG}', REPORT=1"
## Note: INDEX is the index of FFT object in FFT plugin and not PLUGIN_ID. In this case the same
##dbLoadRecords(ecmcPluginFFT.template,"P=$(IOC):,INDEX=0, NELM=${FFT_NELM}, AMP_DESC='Sine amplitude',AMP_EGU='',RAW_DESC='Sine',AMP_EGU='', TITLE='FFT of sinus in 5Hz'")
##############################################################################
############# 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
opi/.keep Normal file
View File

7
patch/Site/HISTORY.md Normal file
View File

@@ -0,0 +1,7 @@
# E3_MODULE_VERSION-what_ever_filename.p0.patch
Generic Description.....
* created by Jeong Han Lee, han.lee@esss.se
* related URL or reference https://github.com/icshwi
* Tuesday, February 13 13:24:57 CET 2018

22
patch/Site/README.md Normal file
View File

@@ -0,0 +1,22 @@
# Site Specific EPICS Module Patch Files
## Changes
The changes were tested in local environemnt, and commits to the forked repository and do pull request to the epics community module repository.
* Check the original HASH, and your own master
* feb8856 : The original HASH
* master : Changed
## How to create a p0 patch file between commits
* Show what the difference between commits
* Create p0 patch
```
$git diff feb8856 master --no-prefix > ../patch/Site/E3_MODULE_VERSION-what_ever_filename.p0.patch
```

49
tempGNUmakefile Normal file
View File

@@ -0,0 +1,49 @@
include /ioc/tools/driver.makefile
MODULE = ecmc_plugin_motion
BUILDCLASSES = Linux
ARCH_FILTER = deb10%
EXCLUDE_VERSIONS+=3 7.0.5
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_RC1
################################################################################
# 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}
# expression parser
#exprtk_DIR = ecmc/exprtkSupport/
#SOURCES += ${exprtk_DIR}exprtkIF.cpp
#SOURCES += ${exprtk_DIR}exprtkImp.cpp
#SOURCES += ${exprtk_DIR}exprtkWrap.cpp
#
#HEADER += ${exprtk_DIR}/exprtkWrap.h
#HEADER += ${exprtk_DIR}/exprtkIF.h
SRC_DIR = ecmc_plugin_motion/src
SOURCES += $(SRC_DIR)/ecmcPluginMotion.c
SOURCES += $(SRC_DIR)/ecmcMotionPlgWrap.cpp
SOURCES += $(SRC_DIR)/ecmcMotionPlg.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))

0
template/.keep Normal file
View File

8
tools/README.md Normal file
View File

@@ -0,0 +1,8 @@
# FFT tools
## GUI
A python gui for vizualization and control of the FFT plugin can be found in the ecmccomgui repo:
https://github.com/anderssandstrom/ecmccomgui
![ecmcFFTMainGui.py](docs/gui/ecmcFFTMainGui.png)