Start from new plugin
This commit is contained in:
16
.gitignore
vendored
Normal file
16
.gitignore
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
*~
|
||||
*-dev
|
||||
modules.order
|
||||
Module.symvers
|
||||
Mkfile.old
|
||||
core.*
|
||||
#*
|
||||
.#*
|
||||
\#*
|
||||
*.local
|
||||
\#*
|
||||
.cvsignore
|
||||
*_old/
|
||||
*PVs.list
|
||||
*-loc/*.Makefile
|
||||
ecmcPlugin_Simple-loc/*.Makefile
|
||||
28
Makefile
Normal file
28
Makefile
Normal 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
|
||||
|
||||
259
README.md
Normal file
259
README.md
Normal file
@@ -0,0 +1,259 @@
|
||||
e3-ecmcPlugin_Advanced
|
||||
======
|
||||
ESS Site-specific EPICS module : ecmcPlugin_Advanced
|
||||
|
||||
Example illustrating how to implement plugins for use with ecmc (https://github.com/icshwi/ecmc).
|
||||
|
||||
Shows how to implement:
|
||||
* callbacks
|
||||
* custom ecmc plc-functions
|
||||
* custom ecmc plc-constants
|
||||
* access to ecmcAsynPort object to add plugin specific asyn parameter.
|
||||
|
||||
# Interface
|
||||
The interface is defined in the structure ecmcPluginData in ecmcPluginDefs.h:
|
||||
```
|
||||
struct ecmcPluginData {
|
||||
// Name
|
||||
const char *name;
|
||||
// Description
|
||||
const char *desc;
|
||||
// Plugin version
|
||||
int version;
|
||||
// ECMC_PLUG_VERSION_MAGIC
|
||||
int ifVersion;
|
||||
// Optional construct func, called once at load
|
||||
int (*constructFnc)(void);
|
||||
// Optional destruct func, called once at unload
|
||||
void (*destructFnc)(void);
|
||||
// Optional func that will be called once just before enter realtime mode
|
||||
int (*realtimeEnterFnc)(void*);
|
||||
// Optional func that will be called once just before exit realtime mode
|
||||
int (*realtimeExitFnc)(void);
|
||||
// Optional func that will be called each realtime cycle
|
||||
int (*realtimeFnc)(int);
|
||||
// Allow max ECMC_PLUGIN_MAX_PLC_FUNC_COUNT custom plc functions
|
||||
struct ecmcOnePlcFunc funcs[ECMC_PLUGIN_MAX_PLC_FUNC_COUNT];
|
||||
// Allow max ECMC_PLUGIN_MAX_PLC_CONST_COUNT custom plc constants
|
||||
struct ecmcOnePlcConst consts[ECMC_PLUGIN_MAX_PLC_CONST_COUNT];
|
||||
};
|
||||
```
|
||||
## Callbacks:
|
||||
All callbacks are optional. If the callbacks are not used then set the func pointer to NULL
|
||||
("ecmcPluginData.*Fnc=NULL").
|
||||
|
||||
Example:
|
||||
```
|
||||
ecmcPluginData.destructFnc=NULL
|
||||
ecmcPluginData.constructFnc=NULL
|
||||
...
|
||||
```
|
||||
|
||||
### int constructFnc(), optional
|
||||
This callback is called once when the plugin is loaded into ecmc. This is a good place to put code for any initialization needed in the plugin module.
|
||||
|
||||
Return value: 0 for success or error code.
|
||||
|
||||
In this example plugin only a printout is made in this callback.
|
||||
|
||||
### void destructFnc(), optional
|
||||
This callback is called once when the plugin is unloaded. This is a good place to put cleanup code needed by the plugin module.
|
||||
|
||||
In this example plugin only a printout is made in this callback.
|
||||
|
||||
### int realtimeFnc(int ecmcErrorId), optional
|
||||
This callback is called once in each realtime loop (sync to ecmc). This is a good place to put any cyclic processing needed by the plugin module.
|
||||
|
||||
NOTE: This callback is executed by ecmc realtime thread. Take measures to stay as short time as possible in this function. If lots of processing is needed a separate worker thread might be a solution.
|
||||
|
||||
Parameters: ecmcErrorId: reflects the current errorstate of ecmc.
|
||||
|
||||
Return value: 0 for success or error code.
|
||||
|
||||
In this example a counter value is increased for each call and the coresponding asyn parameter is updated.
|
||||
|
||||
### int realtimeEnterFnc(void* ecmcRefs), optional
|
||||
This callback is called once just before ecmc enters realtime mode (starts rt-thread). This is a good place to make any prepartions needed before cyclic processing starts.
|
||||
|
||||
Parameters: ecmcRefs: ref to ecmcdata that can be cast to ecmcPluginDataRefs
|
||||
```
|
||||
struct ecmcPluginDataRefs {
|
||||
double sampleTimeMS;
|
||||
ecmcAsynPortDriver *ecmcAsynPort;
|
||||
};
|
||||
```
|
||||
Return value: 0 for success or error code.
|
||||
|
||||
In this example a asyn parameter called "plugin.adv.counter" is registered. The ecmc realtime samplerate is also determined from the ecmcRefs
|
||||
|
||||
### int realtimeExitFnc(), optional
|
||||
This callback is called once just before ecmc exits realtime mode (exits rt-thread).
|
||||
|
||||
Return value: 0 for success or error code.
|
||||
|
||||
In this example plugin only a printout is made in this callback.
|
||||
|
||||
### Example:
|
||||
```
|
||||
// Compile data for lib so ecmc now what to use
|
||||
struct ecmcPluginData pluginDataDef = {
|
||||
// Name
|
||||
.name = "ecmcExamplePlugin",
|
||||
// Description
|
||||
.desc = "Advanced example with use of asynport obj.",
|
||||
// Plugin version
|
||||
.version = ECMC_EXAMPLE_PLUGIN_VERSION,
|
||||
// ECMC_PLUG_VERSION_MAGIC
|
||||
.ifVersion = ECMC_PLUG_VERSION_MAGIC,
|
||||
// Optional construct func, called once at load. NULL if not definded.
|
||||
.constructFnc = adv_exampleConstruct,
|
||||
// Optional destruct func, called once at unload. NULL if not definded.
|
||||
.destructFnc = adv_exampleDestruct,
|
||||
// Optional func that will be called each rt cycle. NULL if not definded.
|
||||
.realtimeFnc = adv_exampleRealtime,
|
||||
// Optional func that will be called once just before enter realtime mode
|
||||
.realtimeEnterFnc = adv_exampleEnterRT,
|
||||
// Optional func that will be called once just before exit realtime mode
|
||||
.realtimeExitFnc = adv_exampleExitRT,
|
||||
...
|
||||
...
|
||||
|
||||
```
|
||||
## PLC functions:
|
||||
Custom ecmc PLC-functions can be implemented in plugins. Currentlly the interface supports implementation of up to 64 plc functions. Each plc function needs to be defined by the struct "ecmcOnePlcFunc":
|
||||
```
|
||||
struct ecmcOnePlcFunc {
|
||||
// Function name (this is the name you use in ecmc plc-code)
|
||||
const char *funcName;
|
||||
// Function description
|
||||
const char *funcDesc;
|
||||
/**
|
||||
* 7 different prototypes allowed (only doubles since reg in plc).
|
||||
* Only one funcArg<argCount> func shall be assigned the rest set to NULL
|
||||
**/
|
||||
double (*funcArg0)();
|
||||
double (*funcArg1)(double);
|
||||
double (*funcArg2)(double,double);
|
||||
double (*funcArg3)(double,double,double);
|
||||
double (*funcArg4)(double,double,double,double);
|
||||
double (*funcArg5)(double,double,double,double,double);
|
||||
double (*funcArg6)(double,double,double,double,double,double);
|
||||
};
|
||||
|
||||
```
|
||||
Example:
|
||||
```
|
||||
.funcs[0] =
|
||||
{ /*----customPlcFunc1----*/
|
||||
// Function name (this is the name you use in ecmc plc-code)
|
||||
.funcName = "adv_plugin_func_1",
|
||||
// Function description
|
||||
.funcDesc = "Multiply arg0 with arg1.",
|
||||
/**
|
||||
* 7 different prototypes allowed (only doubles since reg in plc).
|
||||
* Only funcArg<argCount> one func shall be assigned the rest set to NULL.
|
||||
**/
|
||||
.funcArg0 = NULL,
|
||||
.funcArg1 = NULL,
|
||||
.funcArg2 = adv_customPlcFunc1, // Func 1 has 2 args
|
||||
.funcArg3 = NULL,
|
||||
.funcArg4 = NULL,
|
||||
.funcArg5 = NULL,
|
||||
.funcArg6 = NULL
|
||||
},
|
||||
```
|
||||
Note: Only the first non NULL function will be used (starting from funcArg0...)
|
||||
|
||||
## PLC constants
|
||||
Custom ecmc PLC-constants can be implemented in plugins. Currentlly the interface supports implementation of up to 64 plc constants. Each plc constant needs to be defined by the struct "ecmcOnePlcConst":
|
||||
```
|
||||
struct ecmcOnePlcConst{
|
||||
const char *constName;
|
||||
const char *constDesc;
|
||||
double constValue;
|
||||
};
|
||||
|
||||
```
|
||||
Example:
|
||||
```
|
||||
.consts[0] = {
|
||||
.constName = "adv_CONST_1",
|
||||
.constDesc = "Test constant \"adv_CONST_1\" = 1.234567890",
|
||||
.constValue = 1.234567890,
|
||||
},
|
||||
```
|
||||
## Dependencies:
|
||||
|
||||
All needed headers are available in ecmc (https://github.com/icshwi/ecmc)
|
||||
### Simple plugins
|
||||
|
||||
Only the "ecmcPluginDefs.h" header is needed.
|
||||
|
||||
### Advanced plugins
|
||||
When using the "void* ecmcRefs" param (cast to ecmcPluginDataRefs)in the "realtimeEnterFnc()" these additional headers are needed:
|
||||
* from ecmc:
|
||||
* ecmcAsynPortDriver.h
|
||||
* ecmcAsynDataItem.h
|
||||
* ecmcAsynPortDriverUtils.h
|
||||
* ecmcDefinitions.h
|
||||
* ecmcErrorsList.h
|
||||
* ecmcPluginDataRefs.h
|
||||
* from asyn:
|
||||
* asynPortDriver.h
|
||||
|
||||
Note: This define is needed in the plugin sources:
|
||||
```
|
||||
#define ECMC_IS_PLUGIN
|
||||
```
|
||||
## Plugin info for ecmcPlugin_Advanced
|
||||
```
|
||||
Plugin info:
|
||||
Name = ecmcExamplePlugin
|
||||
Description = Advanced example with use of asynport obj.
|
||||
Version = 1
|
||||
Interface version = 512 (ecmc = 512)
|
||||
max plc funcs = 64
|
||||
max plc consts = 64
|
||||
Construct func = @0x7fac4353d190
|
||||
Enter realtime func = @0x7fac4353d200
|
||||
Exit realtime func = @0x7fac4353d1c0
|
||||
Realtime func = @0x7fac4353d1e0
|
||||
Destruct func = @0x7fac4353d1b0
|
||||
dlhandle = @0x182e580
|
||||
Plc functions:
|
||||
funcs[00]:
|
||||
Name = "adv_plugin_func_1(arg0, arg1);"
|
||||
Desc = Multiply arg0 with arg1.
|
||||
Arg count = 2
|
||||
func = @0x7fac4353d170
|
||||
funcs[01]:
|
||||
Name = "adv_plugin_func_2(arg0, arg1, arg2);"
|
||||
Desc = Multiply arg0, arg1 and arg2.
|
||||
Arg count = 3
|
||||
func = @0x7fac4353d180
|
||||
Plc constants:
|
||||
consts[00]:
|
||||
Name = "adv_CONST_1" = 1.235
|
||||
Desc = Test constant "adv_CONST_1" = 1.234567890
|
||||
consts[01]:
|
||||
Name = "adv_CONST_2" = 9.877
|
||||
Desc = Test constant "adv_CONST_2" = 9.876543210
|
||||
```
|
||||
|
||||
## Access to asyn parameter (linked to record IOC_TEST:Plugin-Adv-Counter)
|
||||
```
|
||||
camonitor IOC_TEST:Plugin-Adv-Counter
|
||||
IOC_TEST:Plugin-Adv-Counter 2020-03-26 15:45:21.535547 23
|
||||
IOC_TEST:Plugin-Adv-Counter 2020-03-26 15:45:21.630954 24
|
||||
IOC_TEST:Plugin-Adv-Counter 2020-03-26 15:45:21.740799 25
|
||||
IOC_TEST:Plugin-Adv-Counter 2020-03-26 15:45:21.838110 26
|
||||
IOC_TEST:Plugin-Adv-Counter 2020-03-26 15:45:21.930354 27
|
||||
IOC_TEST:Plugin-Adv-Counter 2020-03-26 15:45:22.034919 28
|
||||
IOC_TEST:Plugin-Adv-Counter 2020-03-26 15:45:22.130358 29
|
||||
IOC_TEST:Plugin-Adv-Counter 2020-03-26 15:45:22.234041 30
|
||||
IOC_TEST:Plugin-Adv-Counter 2020-03-26 15:45:22.334133 31
|
||||
IOC_TEST:Plugin-Adv-Counter 2020-03-26 15:45:22.434937 32
|
||||
IOC_TEST:Plugin-Adv-Counter 2020-03-26 15:45:22.530212 33
|
||||
IOC_TEST:Plugin-Adv-Counter 2020-03-26 15:45:22.634437 34
|
||||
IOC_TEST:Plugin-Adv-Counter 2020-03-26 15:45:22.734606 35
|
||||
```
|
||||
0
cmds/.keep
Normal file
0
cmds/.keep
Normal file
11
configure/CONFIG
Normal file
11
configure/CONFIG
Normal 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
|
||||
|
||||
37
configure/CONFIG_MODULE
Normal file
37
configure/CONFIG_MODULE
Normal file
@@ -0,0 +1,37 @@
|
||||
#
|
||||
EPICS_MODULE_NAME:=ecmcPlugin_FFT
|
||||
|
||||
EPICS_MODULE_TAG:=master
|
||||
#
|
||||
E3_MODULE_VERSION:=master
|
||||
|
||||
# DEPENDENT MODULE VERSION
|
||||
# For Example,
|
||||
|
||||
ECMC_DEP_VERSION:=master
|
||||
ASYN_DEP_VERSION:=4.36.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:=ecmcPlugin_Advanced-loc
|
||||
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
6
configure/CONFIG_OPTIONS
Normal 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
11
configure/RELEASE
Normal file
@@ -0,0 +1,11 @@
|
||||
#
|
||||
EPICS_BASE:=/epics/base-7.0.3.1
|
||||
|
||||
E3_REQUIRE_NAME:=require
|
||||
E3_REQUIRE_VERSION:=3.1.2
|
||||
|
||||
# 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
12
configure/RULES
Normal 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
|
||||
|
||||
38
configure/module/RULES_DKMS_L
Normal file
38
configure/module/RULES_DKMS_L
Normal 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
|
||||
|
||||
20
configure/module/RULES_MODULE
Normal file
20
configure/module/RULES_MODULE
Normal 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
28
docs/.MODULE_LOG
Normal 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
|
||||
4
docs/ecmcPlugin_Simple.conf
Normal file
4
docs/ecmcPlugin_Simple.conf
Normal file
@@ -0,0 +1,4 @@
|
||||
EPICS_MODULE_NAME:=ecmcPlugin_Simple
|
||||
E3_TARGET_URL:=https://github.com/anderssandstrom
|
||||
E3_MODULE_SRC_PATH:=ecmcPlugin_Simple
|
||||
#
|
||||
0
ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/Db/.keep
Normal file
0
ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/Db/.keep
Normal file
0
ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/.keep
Normal file
0
ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/.keep
Normal file
75
ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/ecmcAdvanced.cpp
Normal file
75
ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/ecmcAdvanced.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
/*************************************************************************\
|
||||
* 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.
|
||||
*
|
||||
* ecmcAdvanced.cpp
|
||||
*
|
||||
* Created on: Mar 22, 2020
|
||||
* Author: anderssandstrom
|
||||
* Credits to https://github.com/sgreg/dynamic-loading
|
||||
*
|
||||
\*************************************************************************/
|
||||
|
||||
// Needed to get headers in ecmc right...
|
||||
#define ECMC_IS_PLUGIN
|
||||
|
||||
// Error Codes
|
||||
#define ECMC_ERROR_ASYNPORT_NULL 1
|
||||
#define ECMC_ERROR_ASYN_PARAM_FAIL 2
|
||||
|
||||
#include "ecmcAdvanced.h"
|
||||
#include "ecmcPluginClient.h"
|
||||
#include "ecmcAsynPortDriver.h"
|
||||
|
||||
// Vars
|
||||
static int counter = 0;
|
||||
static ecmcAsynDataItem *paramCount = NULL;
|
||||
|
||||
// Use ecmcPluginClient.h interface
|
||||
double getSampleRate() {
|
||||
|
||||
return getEcmcSampleRate();
|
||||
}
|
||||
|
||||
// Use ecmcPluginClient.h interface
|
||||
void* getAsynPort() {
|
||||
return getEcmcAsynPortDriver();
|
||||
}
|
||||
|
||||
// register a dummy asyn parameter "plugin.adv.counter"
|
||||
int initAsyn() {
|
||||
|
||||
ecmcAsynPortDriver *ecmcAsynPort = (ecmcAsynPortDriver *)getEcmcAsynPortDriver();
|
||||
if(!ecmcAsynPort) {
|
||||
printf("Error: ecmcPlugin_Advanced: ecmcAsynPortDriver NULL.");
|
||||
return ECMC_ERROR_ASYNPORT_NULL;
|
||||
}
|
||||
|
||||
// Add a dummy counter that incraeses one for each rt cycle
|
||||
paramCount = ecmcAsynPort->addNewAvailParam(
|
||||
"plugin.adv.counter", // name
|
||||
asynParamInt32, // asyn type
|
||||
(uint8_t *)&(counter),// pointer to data
|
||||
sizeof(counter), // size of data
|
||||
ECMC_EC_S32, // ecmc data type
|
||||
0); // die if fail
|
||||
if(!paramCount) {
|
||||
printf("Error: ecmcPlugin_Advanced: Failed to create asyn param \"plugin.adv.counter\".");
|
||||
return ECMC_ERROR_ASYN_PARAM_FAIL;
|
||||
}
|
||||
paramCount->addSupportedAsynType(asynParamInt32); // Only allw records of this type
|
||||
paramCount->setAllowWriteToEcmc(false); // read only
|
||||
paramCount->refreshParam(1); // read once into asyn param lib
|
||||
ecmcAsynPort->callParamCallbacks(ECMC_ASYN_DEFAULT_LIST, ECMC_ASYN_DEFAULT_ADDR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// increase value of counter and refresh asyn param
|
||||
void increaseCounter(){
|
||||
counter++;
|
||||
if(paramCount){
|
||||
paramCount->refreshParamRT(0);
|
||||
// "callParamCallbacks" are handled in ecmc rt thread so don't call
|
||||
}
|
||||
}
|
||||
32
ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/ecmcAdvanced.h
Normal file
32
ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/ecmcAdvanced.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*************************************************************************\
|
||||
* 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.
|
||||
*
|
||||
* ecmcAdvanced.h
|
||||
*
|
||||
* Created on: Mar 22, 2020
|
||||
* Author: anderssandstrom
|
||||
*
|
||||
\*************************************************************************/
|
||||
#ifndef ECMC_ADVANCED_H_
|
||||
#define ECMC_ADVANCED_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // ifdef __cplusplus
|
||||
|
||||
// get ecmc rt sample rate from ecmcPluginClient.h funcs
|
||||
double getSampleRate();
|
||||
// get ecmcAsynPort from ecmcPluginClient.h funcs
|
||||
void* getAsynPort();
|
||||
// register a dummy asyn parameter "plugin.adv.counter"
|
||||
int initAsyn();
|
||||
// increase value of counter and refresh asyn param
|
||||
void increaseCounter();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // ifdef __cplusplus
|
||||
|
||||
#endif /* ECMC_ADVANCED_H_ */
|
||||
225
ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/ecmcPluginExample.c
Normal file
225
ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/ecmcPluginExample.c
Normal file
@@ -0,0 +1,225 @@
|
||||
/*************************************************************************\
|
||||
* 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.
|
||||
*
|
||||
* ecmcPluginExample.cpp
|
||||
*
|
||||
* Created on: Mar 21, 2020
|
||||
* Author: anderssandstrom
|
||||
*
|
||||
\*************************************************************************/
|
||||
|
||||
// Needed to get headers in ecmc right...
|
||||
#define ECMC_IS_PLUGIN
|
||||
#define ECMC_EXAMPLE_PLUGIN_VERSION 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // ifdef __cplusplus
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ecmcPluginDefs.h"
|
||||
#include "ecmcAdvanced.h"
|
||||
#include "ecmcPLC.h"
|
||||
|
||||
#define ECMC_PLUGIN_DBG_OPTION_CMD "DBG_PRINT"
|
||||
|
||||
#define PRINT_IF_DBG_MODE(fmt, ...) \
|
||||
{ \
|
||||
if(dbgModeOption){ \
|
||||
printf(fmt, ## __VA_ARGS__); \
|
||||
} \
|
||||
} \
|
||||
|
||||
static int lastEcmcError = 0;
|
||||
static double ecmcSampleRate = 0;
|
||||
static void* ecmcAsynPort = NULL;
|
||||
static char* confStr = NULL;
|
||||
static int dbgModeOption = 0;
|
||||
|
||||
/** 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 adv_exampleConstruct(char * configStr)
|
||||
{
|
||||
confStr = strdup(configStr);
|
||||
//Only one option defined "DBG_PRINT=" (no need for loop)
|
||||
int tempValue=0;
|
||||
int nvals = sscanf(confStr, ECMC_PLUGIN_DBG_OPTION_CMD"=%d",&tempValue);
|
||||
if (nvals == 1) {
|
||||
dbgModeOption = tempValue;
|
||||
}
|
||||
|
||||
PRINT_IF_DBG_MODE("%s/%s:%d: ConfigStr=\"%s\"...\n",__FILE__, __FUNCTION__, __LINE__,configStr);
|
||||
// Determine ecmc sample rate (just for demo)
|
||||
ecmcSampleRate = getSampleRate();
|
||||
PRINT_IF_DBG_MODE("%s/%s:%d Ecmc sample rate is: %lf ms\n",__FILE__, __FUNCTION__, __LINE__,ecmcSampleRate);
|
||||
|
||||
// Use ecmcAsynPort (just for demo)
|
||||
ecmcAsynPort = getAsynPort();
|
||||
|
||||
// init asyn param counter
|
||||
initAsyn(ecmcAsynPort);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Optional function.
|
||||
* Will be called once at unload.
|
||||
**/
|
||||
void adv_exampleDestruct(void)
|
||||
{
|
||||
PRINT_IF_DBG_MODE("%s/%s:%d...\n",__FILE__, __FUNCTION__, __LINE__);
|
||||
|
||||
if(confStr){
|
||||
free(confStr);
|
||||
}
|
||||
}
|
||||
|
||||
/** 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 adv_exampleRealtime(int ecmcError)
|
||||
{
|
||||
// Check if plc 0 is enabled.. Just to show something with the ecmc headers
|
||||
int plcEnabled = 0;
|
||||
getPLCEnable(0,&plcEnabled);
|
||||
|
||||
PRINT_IF_DBG_MODE("%s/%s:%d: plc0.enabled=%d\n",__FILE__, __FUNCTION__, __LINE__,plcEnabled);
|
||||
|
||||
//Update asynparam counter
|
||||
increaseCounter();
|
||||
lastEcmcError = ecmcError;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Optional function.
|
||||
* Will be called once just before going to realtime mode
|
||||
* Return value other than 0 will be considered error.
|
||||
**/
|
||||
int adv_exampleEnterRT(){
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Optional function.
|
||||
* Will be called once just before leaving realtime mode
|
||||
* Return value other than 0 will be considered error.
|
||||
**/
|
||||
int adv_exampleExitRT(void){
|
||||
PRINT_IF_DBG_MODE("%s/%s:%d...\n",__FILE__, __FUNCTION__, __LINE__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Optional plc function 1*/
|
||||
double adv_customPlcFunc1(double arg1, double arg2)
|
||||
{
|
||||
PRINT_IF_DBG_MODE("%s/%s:%d...\n",__FILE__, __FUNCTION__, __LINE__);
|
||||
return arg1 * arg2;
|
||||
}
|
||||
|
||||
/** Optional plc function 2*/
|
||||
double adv_customPlcFunc2(double arg1, double arg2, double arg3)
|
||||
{
|
||||
PRINT_IF_DBG_MODE("%s/%s:%d...\n",__FILE__, __FUNCTION__, __LINE__);
|
||||
return arg1 * arg2 * arg3;
|
||||
}
|
||||
|
||||
// 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 = "ecmcExamplePlugin",
|
||||
// Description
|
||||
.desc = "Advanced example with use of asynport obj.",
|
||||
// Option description
|
||||
.optionDesc = ECMC_PLUGIN_DBG_OPTION_CMD"=1/0 : Enables/disables printouts from plugin.",
|
||||
// Plugin version
|
||||
.version = ECMC_EXAMPLE_PLUGIN_VERSION,
|
||||
// Optional construct func, called once at load. NULL if not definded.
|
||||
.constructFnc = adv_exampleConstruct,
|
||||
// Optional destruct func, called once at unload. NULL if not definded.
|
||||
.destructFnc = adv_exampleDestruct,
|
||||
// Optional func that will be called each rt cycle. NULL if not definded.
|
||||
.realtimeFnc = adv_exampleRealtime,
|
||||
// Optional func that will be called once just before enter realtime mode
|
||||
.realtimeEnterFnc = adv_exampleEnterRT,
|
||||
// Optional func that will be called once just before exit realtime mode
|
||||
.realtimeExitFnc = adv_exampleExitRT,
|
||||
|
||||
// Allow max s custom plc funcs
|
||||
.funcs[0] =
|
||||
{ /*----customPlcFunc1----*/
|
||||
// Function name (this is the name you use in ecmc plc-code)
|
||||
.funcName = "adv_plugin_func_1",
|
||||
// Function description
|
||||
.funcDesc = "Multiply arg0 with arg1.",
|
||||
/**
|
||||
* 11 different prototypes allowed (only doubles since reg in plc).
|
||||
* Only one funcArg<argCount> func shall be assigned the rest set to NULL.
|
||||
**/
|
||||
.funcArg0 = NULL,
|
||||
.funcArg1 = NULL,
|
||||
.funcArg2 = adv_customPlcFunc1, // Func 1 has 2 args
|
||||
.funcArg3 = NULL,
|
||||
.funcArg4 = NULL,
|
||||
.funcArg5 = NULL,
|
||||
.funcArg6 = NULL,
|
||||
.funcArg7 = NULL,
|
||||
.funcArg8 = NULL,
|
||||
.funcArg9 = NULL,
|
||||
.funcArg10 = NULL
|
||||
},
|
||||
.funcs[1] =
|
||||
{ /*----customPlcFunc2----*/
|
||||
// Function name (this is the name you use in ecmc plc-code)
|
||||
.funcName = "adv_plugin_func_2",
|
||||
// Function description
|
||||
.funcDesc = "Multiply arg0, arg1 and arg2.",
|
||||
/**
|
||||
* 11 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 = NULL,
|
||||
.funcArg3 = adv_customPlcFunc2, // Func 2 has 3 args
|
||||
.funcArg4 = NULL,
|
||||
.funcArg5 = NULL,
|
||||
.funcArg6 = NULL,
|
||||
.funcArg7 = NULL,
|
||||
.funcArg8 = NULL,
|
||||
.funcArg9 = NULL,
|
||||
.funcArg10 = NULL
|
||||
},
|
||||
.funcs[2] = {0}, // last element set all to zero..
|
||||
|
||||
/** Plugin specific constants (add prefix to not risc collide with
|
||||
* names from other modules) */
|
||||
.consts[0] = {
|
||||
.constName = "adv_CONST_1",
|
||||
.constDesc = "Test constant \"adv_CONST_1\" = 1.234567890",
|
||||
.constValue = 1.234567890,
|
||||
},
|
||||
.consts[1] = {
|
||||
.constName = "adv_CONST_2",
|
||||
.constDesc = "Test constant \"adv_CONST_2\" = 9.876543210",
|
||||
.constValue = 9.876543210,
|
||||
},
|
||||
.consts[2] = {0}, // last element set all to zero..
|
||||
};
|
||||
|
||||
ecmc_plugin_register(pluginDataDef);
|
||||
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif // ifdef __cplusplus
|
||||
63
ecmcPlugin_FFT.Makefile
Normal file
63
ecmcPlugin_FFT.Makefile
Normal file
@@ -0,0 +1,63 @@
|
||||
#
|
||||
# Copyright (c) 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 : anderssandstrom
|
||||
# email : anderssandstrom@esss.se
|
||||
# Date : 2020Mar22-1607-33CET
|
||||
# version : 0.0.0
|
||||
#
|
||||
# template file is generated by ./e3TemplateGenerator.bash with bf03d40
|
||||
# Please look at many other _module_.Makefile in e3-* repository
|
||||
#
|
||||
|
||||
|
||||
|
||||
|
||||
## 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
|
||||
|
||||
APP:=ecmcPlugin_AdvancedApp
|
||||
APPDB:=$(APP)/Db
|
||||
APPSRC:=$(APP)/src
|
||||
|
||||
USR_CFLAGS += -shared -fPIC -Wall -Wextra
|
||||
USR_LDFLAGS += -lstdc++
|
||||
USR_INCLUDES += -I$(where_am_I)$(APPSRC)
|
||||
|
||||
TEMPLATES += $(wildcard $(APPDB)/*.db)
|
||||
SOURCES += $(APPSRC)/ecmcPluginExample.c
|
||||
SOURCES += $(APPSRC)/ecmcAdvanced.cpp
|
||||
|
||||
db:
|
||||
|
||||
.PHONY: db
|
||||
|
||||
vlibs:
|
||||
|
||||
.PHONY: vlibs
|
||||
|
||||
###
|
||||
0
iocsh/.keep
Normal file
0
iocsh/.keep
Normal file
7
patch/Site/HISTORY.md
Normal file
7
patch/Site/HISTORY.md
Normal 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
22
patch/Site/README.md
Normal 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
|
||||
```
|
||||
|
||||
0
template/.keep
Normal file
0
template/.keep
Normal file
Reference in New Issue
Block a user