Estendere run time PLC LogicLab

In questo articolo abbiamo visto come programmare il modulo SlimLine Raspberry in linguaggio "C", questo permette di scrivere programmi che possono essere eseguiti autonomamente. Ma chi utilizza il modulo come PLC con la programmazione in ambiente LogicLab ha la necessità di poter integrare nuove funzioni o blocchi funzioni realizzati in linguaggio "C" rendendoli accessibili dall'IDE LogicLab.

Di seguito riprendiamo quanto riportato in questo articolo della Axel e vediamo come estendere Il run time di LogicLab con nuovi oggetti. In pratica viene creato un plug-in con una libreria dinamica che viene inglobata ed eseguita dal run-time di LogicLab.

Compilazione plug-in

Per poter compilare il plug-in occorre disporre del PluginHeaders SDK, lo zip è scaricabile dal sito della Axel nella sezione download. Creare una directory e scompattare all'interno il file PluginHeaders, al termine troveremo una cartella del tipo PluginHeaders_2.13.17. Nella cartella vi saranno i files definizione (.h) che espongono le API LLExec per l'interfaccia con il runtime.

Ogni versione di run-time LLExec ha le proprie intestazioni di plugin, quindi assicurarsi che il numero di versione del PluginHeader corrisponda alla versione di run-time installata, non è garantita alcuna compatibilità con le versioni precedenti.

All'interno di questa cartella potremo creare la cartella con il nostro progetto di plugin, nell'esempio che forniamo il progetto viene nominato LLXPlugin_Demo e contiene un workspace Codelite con relativo progetto pronto per essere compilato. Aprire il workspace LLXPlugin_Demo.workspace con Codelite, compilare il progetto generando il file di libreria dinamica LLXPlugin_Demo.so.

Aggiunta plugin al run time

Per questa operazione occorre accertarsi che il run time non sia in esecuzione, eventualmente arrestarlo con il comando:
sudo /etc/init.d/LLExecDaemon stop

Per aggiungere il plugin al run time LLExec occorre trasferire il nostro eseguibile LLXPlugin_Demo.so nella cartella dove risiede il run time LogicLab (Tipicamente /data/plc). Trasferito il file occorre aggiungerlo ai plugin che il run time LLExec carica, per fare questo editare il file di configurazione LLExecLinux.conf (Sempre in /data/plc) aggiungendolo nell'elenco dei plugin con una definizione del tipo <plugin filename="./LLXPlugin_Demo.so">.

Nell'esempio (I sorgenti si trovano nel file main.cpp) sono dichiarate una funzione MyFUN ed un blocco funzione MyFB che potranno essere eseguiti all'interno di un programma LogicLab. La funzione PluginInit viene eseguita automaticamente al caricamento del plugin da parte del run time, nell'esempio viene stampato un messaggio di debug. Se mandiamo in esecuzione il run time dalla cartella /data/plc con il comando sudo ./LLExec potremo vedere a terminale i vari messaggi di report e se tutto è corretto al caricamento del nostro plugin vedremo il messaggio definito.

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

Verificato che tutto è corretto possiamo eseguire il run time con il comando:
sudo /etc/init.d/LLExecDaemon start

Utilizzo in LogicLab

Nel nostro plugin come visto abbiamo dichiarato la funzione MyFUN ed il blocco funzione MyFB, ora nel progetto LogicLab possiamo creare la cartella Lib dove andremo ad abilitare la generazione libreria. All'interno di questa cartella possiamo dichiarare la funzione ed il blocco funzione entrambi di tipo Embedded.

Negli oggetti embedded è possibile dichiarare solo le variabili di I/O, che devono rispecchiare le dichiarazioni degli oggetti fatte nel plugin, da programma è possibile richiamare i nostri oggetti ed utilizzarli.

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?