Update README.md
This commit is contained in:
@@ -1,259 +1,31 @@
|
||||
e3-ecmcPlugin_Advanced
|
||||
e3-ecmcPlugin_FFT
|
||||
======
|
||||
ESS Site-specific EPICS module : ecmcPlugin_Advanced
|
||||
ESS Site-specific EPICS module : ecmcPlugin_FFT
|
||||
|
||||
Example illustrating how to implement plugins for use with ecmc (https://github.com/icshwi/ecmc).
|
||||
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)
|
||||
|
||||
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:
|
||||
## Load FFT module in ecmc:
|
||||
```
|
||||
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];
|
||||
};
|
||||
epicsEnvSet(ECMC_PLUGIN_FILNAME,"/epics/base-7.0.3.1/require/3.1.2/siteMods/ecmcPlugin_FFT/master/lib/linux-arm/libecmcPlugin_FFT.so")
|
||||
epicsEnvSet(ECMC_PLUGIN_CONFIG,"DBG_PRINT=1;SOURCE=ax1.actpos;")
|
||||
") # Enable printouts from plugin
|
||||
${SCRIPTEXEC} ${ecmccfg_DIR}loadPlugin.cmd, "PLUGIN_ID=0,FILE=${ECMC_PLUGIN_FILNAME},CONFIG='${ECMC_PLUGIN_CONFIG}', REPORT=1"
|
||||
epicsEnvUnset(ECMC_PLUGIN_FILNAME)
|
||||
epicsEnvUnset(ECMC_PLUGIN_CONFIG)
|
||||
```
|
||||
## Callbacks:
|
||||
All callbacks are optional. If the callbacks are not used then set the func pointer to NULL
|
||||
("ecmcPluginData.*Fnc=NULL").
|
||||
|
||||
Example:
|
||||
### Define SOURCE
|
||||
The data source is defined by setting the SOURCE option in the plugin configuration string.
|
||||
Example: Axis 1 actpos
|
||||
```
|
||||
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,
|
||||
...
|
||||
...
|
||||
epicsEnvSet(ECMC_PLUGIN_CONFIG,"DBG_PRINT=1;SOURCE=ax1.actpos;")
|
||||
|
||||
```
|
||||
## 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":
|
||||
Example: Ethercat slave 1 analog input ch1
|
||||
```
|
||||
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);
|
||||
};
|
||||
epicsEnvSet(ECMC_PLUGIN_CONFIG,"DBG_PRINT=1;SOURCE=ec0.s1.AI_1;")
|
||||
|
||||
```
|
||||
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
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user