Extend run time PLC LogicLab

In this article we have seen how to program the module SlimLine Raspberry in "C" language, this allows you to write programs that can be run independently. But who uses the module as a PLC with room programming LogicLab it needs to be able to integrate new functions or function blocks realized in "C" language making them accessible from the LogicLab IDE.

The following is a summary of what is reported in this article of Axel and see how to extend the run time of LogicLab with new objects. In practice, a plug-in is created with a dynamic library that is incorporated and executed by the run-time of LogicLab.

Plug-in compilation

To be able to compile the plug-in you need to have the PluginHeaders SDK, the zip can be downloaded from the website of Axel in the download section. Create a directory and unpack the file inside PluginHeaders, at the end we will find a folder of the type PluginHeaders_2.13.17. In the folder there will be the definition files (.h) that expose the LLExec APIs for the interface with the runtime.

Every run-time version LLExec has its own plugin headers, so make sure the version number of the PluginHeader corresponds to the run-time version installed, no compatibility with previous versions is guaranteed.

Within this folder we can create the folder with our plugin project, in the example we provide the project is named LLXPlugin_Demo and contains a workspace Codelite with its project ready to be filled out. Open the workspace LLXPlugin_Demo.workspace with Codelite, compile the project generating the dynamic library file LLXPlugin_Demo.so.

Added plugin to run time

For this operation it is necessary to make sure that the run time is not running, possibly stop it with the command:
sudo /etc/init.d/LLExecDaemon stop

To add the plugin to the run time LLExec we need to transfer our executable LLXPlugin_Demo.so in the folder where the run time LogicLab (Typically /data/plc). Once the file is transferred, it must be added to the plugins that the run time LLExec upload, to do this edit the configuration file LLExecLinux.conf (Always in /data/plc) adding it to the list of plugins with a type definition <plugin filename="./LLXPlugin_Demo.so">.

In the example (The sources are in the file main.cpp) a function is declared MyFUN and a function block MyFB that can be performed within a LogicLab program. The function PluginInit it is automatically executed when the plugin is loaded by the run time, in the example a debug message is printed. If we run the run time from the folder /data/plc with the command sudo ./LLExec we will be able to see the various report messages at the terminal and if everything is correct when loading our plugin we will see the message defined.

pi@raspberrypi:/data/plc $ sudo ./LLExec
LLEXEC 2.13.17 (Build: Jul 24 2019 14:10:26 32bit)
LLEXEC Starting up...
** Loading configuration
** License key is valid
** Loading runtimes
** Loading plugins
LLXPlugin_Demo start.............................................................
** Scheduler is running

Verified that everything is correct we can execute the run time with the command:
sudo /etc/init.d/LLExecDaemon start

Use in LogicLab

In our plugin as seen we have declared the function MyFUN and the function block MyFB, now in the project LogicLab we can create the folder Lib where we are going to enable the library generation. Within this folder we can declare the function and the function block both of type Embedded.

In objects embedded it is possible to declare only the I / O variables, which must reflect the declarations of the objects made in the plugin, from the program it is possible to recall our objects and use them.

LLXPlugin_Demo (Ptp168)
// *****************************************************************************
// LLEXEC EXAMPLE PLUGIN
// *****************************************************************************
// Codelite workspace: "LLXPlugin_Demo"
// Codelite project: "LLXPlugin_Demo"
// File: "main.cpp"
// -----------------------------------------------------------------------------
// In Codelite project remember to define:
//
// LLExecCore platform   : WINDOWS_XP7_EXECCORE, WINDOWS_CE_EXECCORE, LINUXBASE_EXECCORE, LINUXXEN_EXECCORE, VXWORKS_EXECCORE, ...
// Architecture platform : ALPLC_P_X86, ALPLC_P_ARM32, ...
// Compiler platform     : ALPLC_C_MSDEVX86, ALPLC_C_GCCX86, ALPLC_C_MSDEVARM, ALPLC_C_GCCARM9, ...
// EXTERNAL_MISRA_C_TYPES if your environment already has Misra-C types
// -----------------------------------------------------------------------------

#include "../LLExecCore/PluginsInterface.h"
#include "../LLExecCore/TraceLog.h"

// -----------------------------------------------------------------------------
// Access to API functions of LLEXECCORE
// -----------------------------------------------------------------------------

LLEXEC_API m_plcApi;
LLXPLG_INITIALIZEPLUGIN
{
    m_plcApi = *api;
    return TRUE;
}

// -----------------------------------------------------------------------------
// INIT FUNCTION
// -----------------------------------------------------------------------------
// This will be called automatically in the system startup sequence.

static bool_t PluginInit()
{
    m_plcApi.LLPrintLog(ALTRACE_LEV_PLG_BASE, "LLXPlugin_Demo start............................................................");
    return TRUE;
}

// -----------------------------------------------------------------------------
// FUNCTION "MyFUN"
// -----------------------------------------------------------------------------
// This function is exposed to the PLC runtime, it can be called from PLC code.

static uint32_t MyFUN(uint32_t In)
{
    return(In*2);
}

// -----------------------------------------------------------------------------
// FUNCTION BLOCK "MyFB"
// -----------------------------------------------------------------------------
// FB data structure, all data are passed in this structure type.

typedef struct
{
    uint32_t In; //FB input
    uint32_t Out; //FB output
}MYFBDATA;

// This FB is exposed to the PLC runtime, it can be called from PLC code.

static void MyFB(MYFBDATA* S)
{
    S->Out=S->In*2;
}

// -----------------------------------------------------------------------------
// EXPOSED FUNCTIONS TABLE
// -----------------------------------------------------------------------------
// This is the table of function exposed to the runtime.

static LLEXEC_FUNDEF m_Functions[] =
{
    { LLFUNCT_INIT_L0, (void *)PluginInit, "PluginInit", }, //Init function
    { LLFUNCT_PLC, (void *)MyFUN, "MyFUN", }, //LogicLab exported function
    { LLFUNCT_PLC, (void *)MyFB, "MyFB", }, //LogicLab exported function block
};

LLXPLG_GETFUNCTIONDEFS
{
    *num = ARRDIM(m_Functions);
    *defs = m_Functions;
    return TRUE;
}

// [End of file]
Was this article helpful?