Start from new plugin

This commit is contained in:
Anders Sandström
2020-04-02 09:51:49 +02:00
commit c5c1278bde
24 changed files with 894 additions and 0 deletions

16
.gitignore vendored Normal file
View 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
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

259
README.md Normal file
View 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
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

37
configure/CONFIG_MODULE Normal file
View 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
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:=/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
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

View File

@@ -0,0 +1,4 @@
EPICS_MODULE_NAME:=ecmcPlugin_Simple
E3_TARGET_URL:=https://github.com/anderssandstrom
E3_MODULE_SRC_PATH:=ecmcPlugin_Simple
#

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

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

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

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

0
template/.keep Normal file
View File