Anders Sandström 5658be384f Rename files
2020-04-02 09:54:46 +02:00
2020-04-02 09:51:49 +02:00
2020-04-02 09:51:49 +02:00
2020-04-02 09:51:49 +02:00
2020-04-02 09:51:49 +02:00
2020-04-02 09:51:49 +02:00
2020-04-02 09:51:49 +02:00
2020-04-02 09:51:49 +02:00
2020-04-02 09:51:49 +02:00
2020-04-02 09:51:49 +02:00
2020-04-02 09:51:49 +02:00
2020-04-02 09:51:49 +02:00

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  
Description
No description provided
Readme 581 KiB
Languages
C 55.5%
C++ 38.8%
Makefile 3.8%
Python 1.9%