Implementation of IEC61499 function block calling C++ dynamic library (2)

People who use IEC61499 to develop applications will have a feeling-"the number of functional blocks will be less when they are used". Therefore, it is necessary for users to develop functional blocks. In theory, the IEC61499 standard provides a way to define the type of function block. For example, in 4DIAC, function block types can be defined. It includes basic function blocks, service interface function blocks and composite function blocks that can be defined. The internal algorithm of the function block can be written in ST language or Lua language. In fact, after the design of the function block type is completed, the function block Export should be converted into runtime C++ code, and the runtime will be recompiled together with the runtime before the runtime truly supports the defined function block (called external module in 4DIAC Forte) (External module)). This method is flawed. First of all, it is not a dynamic function block and needs to be compiled together with runtime. The way to truly realize dynamic function blocks can only use interpreted languages ​​to write algorithms (such as lua, or java, JavaScript), and the disadvantages of interpreted languages ​​are obvious, the execution efficiency is not high, and it is not suitable for real-time control requirements. In addition, if it involves the control of the underlying hardware, the interpretive language is also powerless. Under Linux OS, there is another way to achieve dynamic remote deployment, and that is container technology. However, docker is a behemoth and is not suitable for small embedded systems.

In order to find a more suitable way to implement dynamic function blocks. We made many efforts and finally chose the technology of dynamic library to realize IEC61499 dynamic function block.

General format of dynamic function blocks

We designed a CALL function block whose main function is to call a subroutine in a dynamic library.

For example: the following is a library function call function block with two parameters

Among them, param1, and param2 are the input values ​​of the function, and result is the result of the function

The name is a combination of the library name and the function name. For example, libmath.add means the add function in the dynamic library libmath.

 

More complicated considerations

How to consider the internal variables of the function

   We know that functions cannot access external variables, nor can they retain internal variables. We use classes to keep internal variables.

example:

The following example is a class defined in the dynamic library. Then use external functions to call this class.

fifo.cpp

#include<stdio.h>
#include "fifo.h"
FB::FB(){

}
FIFO::FIFO(){
    inPos=0;
    outPos=0;
    counter=0;
}
void FIFO::pushData(int value){
    printf("pushData\n");
     buffer[inPos++]=value;
     if (inPos==32) 
     inPos=0;
     counter++;
}
int FIFO::popData() {
   int value;
   printf("popData\n");
   value=buffer[outPos++];
   if (outPos==32) outPos=0;
   counter--;
   return value;
}

 
extern "C" { 
FB * init(){
   printf("init\n");
    return (new FIFO());
}

 
void pushData(FB * handle,int val){
     FIFO * h;
     h=(FIFO *)handle;
     h->pushData(val);
}
 
 int popData(FB * handle){
     FIFO * h;
     h=(FIFO *)handle;
   return h->popData();
}
}

Note: extern "C" is very important. Otherwise, running ./dlopen_test will report the error of undefined symbol dlsym, because the file compiled by C++ will rename the function (in order to realize the overload function), and after declaring it with extern "C", it will be compiled and compiled The following file is still the defined function name, you can see the name of the function in so through nm.

The extern "C" qualifier does not mean that C++ code cannot be used in the function. On the contrary, it is still a complete C++ function, which can use any C++ features and various types of parameters.

However, in another example, when I compiled it into a static library, or linked it dynamically at compile time, it seemed that adding extern "C" did not work, and an undefined reference to error occurred. Removed but it's good. It's weird. Hi

fifo.h

#include<stdio.h>
class FB {
    public:
      FB();
};
class FIFO :public FB {
    public:
       FIFO();
       void pushData(int value);
       int popData();
    private:
      int buffer[32];
      int counter;
      int inPos,outPos;

};
FB * init();
void pushData(FB * handle,int val);
int popData(FB * handle);

 

Compile

 g++ fifo.cpp  -fPIC  -shared  -o libfifo.so   

Main program

#include<stdio.h>
#include<dlfcn.h>
#include "fifo.h"
typedef FB *(*PFUNC_INIT)(); 
typedef void (*PFUNC_PUSH)(FB* handle,int);
typedef int(*PFUNC_POP)(FB* handle);        //给函数指针定义一个别名   PFUNC_SHOW = int(*)(int)
 
int main()
{
     printf("Dynamic lib test\n");
    void *handle = dlopen("./libfifo.so",RTLD_LAZY| RTLD_DEEPBIND |RTLD_GLOBAL);  //加载动态库
        if(handle==NULL)
        {
            printf("dlopen fail:%s\n",dlerror());
            return -1;
        }
    PFUNC_INIT init = (PFUNC_INIT)dlsym(handle,"init"); 
    if(init==NULL)
    {
        printf("dlsym fail:%s\n",dlerror());
        return -1;
    } 
    PFUNC_PUSH push = (PFUNC_PUSH)dlsym(handle,"pushData");  
       if(push==NULL)
    {
        printf("dlsym fail:%s\n",dlerror());
        return -1;
    }         
    PFUNC_POP pop = (PFUNC_POP)dlsym(handle,"popData");  
       if(pop==NULL)
    {
        printf("dlsym fail:%s\n",dlerror());
        return -1;
    } 
    FB * h=init();
    push(h,1);
    push(h,2);
    int val=pop(h);
    printf("result=%d\n",val);
    val=pop(h);
    printf("result=%d\n",val);
    dlclose(handle);
    return 0;
}

Compile

g++ fifoTest.cpp -ldl -o fifoTest  

operation result

yao@DESKTOP-U0S0G7O:/mnt/f/yao2020/c++2020/dynamiclib$ ./fifoTest
Dynamic lib test
init
pushData
pushData
popData
result=1
popData
result=2

Here we see that the pointer of the class (FB * h) is passed through the function parameter in main. And FB is just an empty class, FIFO uses FB as the base class. In the main program, only the FB pointer class is used to transfer the address of the instance of the FIFO class. In other words, if all classes in the dynamic library use FB as the base class, then the FB pointer can be used as the pointer of the class in the dynamic library. In C++, you can use base class pointers to access derived classes.

Similarly, in the function of the dynamic library, you can also run a thread.

The use of dynamic libraries to realize the development of dynamic function blocks is a feasible method. What do you say?

Guess you like

Origin blog.csdn.net/yaojiawan/article/details/108874766