How to install OPC UA

Revision as of 18:22, 8 November 2021 by Registered User

This stage explains how to properly install a library to use it on STM32MP1 boards.

1. Overview[edit source]

Please refer to the OPC UA overview to have details about this communication protocol.

2. Installation process[edit source]

Now, we will see how to get the open62541 library for our STM32MP1.

2.1. Install the SDK[edit source]

  • If you have not the SDK installed, please refer to Install the SDK before going further. It will be essential later to cross-compile our library.

2.2. Create a new project[edit source]

You do not have to follow this step if you want, but all the tutorial will be based on a fake project to give you an example of how to proceed.

  • Create a directory that will host your source codes
 mkdir $HOME/Documents/OPC_UA_first_project
 mkdir $HOME/Documents/OPC_UA_first_project/src
  • Create a directory that will host your library and go to it
 mkdir $HOME/Documents/OPC_UA_first_project/lib
 cd $HOME/Documents/OPC_UA_first_project/lib

2.3. Clone open62541 git repository[edit source]

  • Clone the repository needed to compile the library (you need to have git commands enable on your Linux):
 git clone https://github.com/open62541/open62541.git
 cd open62541
 git submodule update --init --recursive
 mkdir build && cd build

2.4. Cross-building the library[edit source]

We told you that the SDK would be useful, here we are ! In fact, we are currently preparing a library usable with ARM binaries to execute our code on the cortex A7 of STM32MP1.

  • We source our shell to cross compile with the SDK:
 source <path_to_SDK>/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
  • to make sure that your source succeed you can try "echo $CROSS_COMPILE" and should get the following answer :
 echo $CROSS_COMPILE
arm-ostl-linux-gnueabi-
Warning white.png Warning
Be careful, your source operation is only available in this shell window
  • Now we cross compile the library by using the cmake command. All compilation flags can be found here on the official documentation of open62541. The main ones have been chosen in this example to make both Client/Server and PubSub communication.
 cmake -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=MinSizeRel -DUA_ENABLE_PUBSUB=ON  -DUA_ENABLE_PUBSUB_ETH_UADP=ON -DUA_NAMESPACE_ZERO=MINIMAL UA_ENABLE_STATUSCODE_DESCRIPTIONS=OFF UA_ENABLE_TYPEDESCRIPTION=OFF UA_LOGLEVEL=200 ..
 make
  • Your library is now built and put into the bin folder. We can check it :
 ls bin/
libopen62541.a
  • If you want to be sure that your library is well cross-compiled, enter the following command:
 readelf -a bin/libopen62541.a

You should observe a lot of R_ARM notice and, at the end, the following returns:

File Attributes
 Tag_CPU_name: "Cortex-A7"
 Tag_CPU_arch: v7
 Tag_CPU_arch_profile: Application
Info white.png Information
Maybe you will have to develop OPC UA programs executable on your PC too later (and then communicate with your STM32MP1 why not ? ). However, you cannot use this library for x86 binaries, so the best way would be to have another library which is not cross-compiled. Do not worry, the steps are the same, just do not source your shell.

3. Building your first program[edit source]

As other libraries, we need to edit our Makefile to inform him the paths where it will able to find open62541 library, headers etc... As a first program, we will use an example given by open62541 team, which is a simple OPC UA Client.

  • First, go to your src project folder
 cd $HOME/Documents/OPC_UA_first_project/src
  • Create a new file called myServer.c and whose content can be found here. Do not compile the code as they do it on the webpage !.
#include <open62541/plugin/log_stdout.h>
#include <open62541/server.h>
#include <open62541/server_config_default.h>

#include <signal.h>
#include <stdlib.h>

static volatile UA_Boolean running = true;
static void stopHandler(int sig) {
    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "received ctrl-c");
    running = false;
}

int main(void) {
    signal(SIGINT, stopHandler);
    signal(SIGTERM, stopHandler);

    UA_Server *server = UA_Server_new();
    UA_ServerConfig_setDefault(UA_Server_getConfig(server));

    UA_StatusCode retval = UA_Server_run(server, &running);

    UA_Server_delete(server);
    return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
}
  • Now create a new file called Makefile and whose content is the next one :
# Makefile template for OPC UA

PROG = myServer.bin

SRCS = myServer.c #you can add here your other .c files

OBJS = $(SRCS:%.c=%.o)

#the path of open62541 library
PATHLIB = -L ../lib/open62541/build/bin/

#the name of the library
LIB = open62541

#path of headers files
INCLUDE += -I ../lib/open62541/include/
INCLUDE += -I ../lib/open62541/plugins/include/
INCLUDE += -I ../lib/open62541/build/src_generated/
INCLUDE += -I ../lib/open62541/arch/
INCLUDE += -I ../lib/open62541/deps/
INCLUDE += -I ../lib/open62541/src/pubsub/

CLEANFILES = $(PROG)

# Add / change option in CFLAGS and LDFLAGS
CFLAGS += -Wall 
CFLAGS += $(INCLUDE)

LDFLAGS += $(PATHLIB) -l$(LIB)

all: $(PROG)

$(PROG): $(OBJS)
	$(CC) -o $@ $^ $(LDFLAGS)

clean:
	rm -f $(CLEANFILES) $(patsubst %.c,%.o, $(SRCS))
  • You can now build the program :
 make 
  • You should see your executable program in your folder :
 ls
Makefile  myServer.bin  myServer.c  myServer.o

4. Executing the program on your STM32MP1[edit source]

  • You have now to put myServer.bin on your board. You have different ways to do this, you can refer to How to cross-compile with the Developer Package part 9.3 if you want more information. In our case we will take a simple way to do this:
 scp myServer.bin root@<IP of your board>:/usr/local
  • Then open another shell and connect you to your board in ssh:
 ssh root@<IP of your board>
  • Go to the folder where you have put the program and execute it:
 cd /usr/local
 ./myServer.bin
  • You should see something like this:
[2021-01-14 09:41:22.659 (UTC+0100)] warn/server	AccessControl: Unconfigured AccessControl. Users have all permissions.
[2021-01-14 09:41:22.659 (UTC+0100)] info/server	AccessControl: Anonymous login is enabled
[2021-01-14 09:41:22.659 (UTC+0100)] warn/server	Username/Password configured, but no encrypting SecurityPolicy. This can leak 
credentials on the network.
[2021-01-14 09:41:22.659 (UTC+0100)] warn/userland	AcceptAll Certificate Verification. Any remote certificate will be accepted.
[2021-01-14 09:41:22.659 (UTC+0100)] info/network	TCP network layer listening on <TCP port> 

There you are, you have now your first OPC UA program running on your board !

5. Going further : make your first OPC UA Client/Server[edit source]

As an example to illustrate all this article, let's make an OPC UA Client/Server run on 2 different STM32MP1 (you also can do it with 2 shells on your PC, or 2 different PCs, or 1 PC and 1 board... Just make sure to have the right version of the library, cross-compiled or not, to do this). We have 2 STM32MP1 linked by Ethernet to the same network. Our PC used for the development of the project is also in the same network (it will help us to easily send our files by scp command later).

  • As we are using 2 boards in this example, we can begin to source our shell to not forget !
 source <path_to_SDK>/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
  • Then create all the folders that you will need for this little project, we begin with the library side:
 mkdir <your_project_path>/opc_ua_client_server && cd <your_project_path>/opc_ua_client_server
 mkdir lib && cd lib
 git clone https://github.com/open62541/open62541.git
 cd open62541
 git submodule update --init --recursive
 mkdir build && cd build
 cmake -DBUILD_SHARED_LIBS=OFF -DCMAKE_BUILD_TYPE=MinSizeRel -DUA_ENABLE_PUBSUB=ON  -DUA_ENABLE_PUBSUB_ETH_UADP=ON -DUA_NAMESPACE_ZERO=MINIMAL UA_ENABLE_STATUSCODE_DESCRIPTIONS=OFF UA_ENABLE_TYPEDESCRIPTION=OFF UA_LOGLEVEL=200 ..
 make
  • Now, we will add the source code side:
 cd ../../..
 mkdir src && cd src

  • Create a common file for both client and server common.h:
#ifndef COMMON_H
#define COMMON_H

const char * IP_SERVER = "10.48.0.23"; //the address needs to be the IP of your board which will be your server (ifconfig)
const int PORT_SERVER = 12345; //choose your port for the server

#endif /* COMMON_H */
  • Now we will create files for server:
 mkdir server && cd server 
  • We will create myServer.c and Makefile
/** DATA MODEL INFORMATION **
 * 
 * 
 * 
 * ------* Supermarket
 *       |
 *       |
 *       |--------* Products
 *       |        |
 *       |        |
 *       |        |----------* Apples (R/W)
 *       |        |
 *       |        |
 *       |        |----------* Bananas (R/W)
 *       |        
 *       |        
 *       |--------* Name (R)
 * 
 * 
 * The information model is based on a nodes model, and each endpoint of the tree has different values with Read/Write rights (R/W). 
 * The client will be able to manage the quantity of fruits, but only read the name of the market. 
 * 
 */

#include <open62541/plugin/log_stdout.h>
#include <open62541/server.h>
#include <open62541/server_config_default.h>

#include <signal.h>
#include <stdlib.h>
#include "../common.h"


static UA_VariableAttributes vnAttr;
static UA_VariableAttributes tpAttr;
static UA_VariableAttributes bAttr;

/* end tree node */
static  UA_NodeId nodeApples;
static  UA_NodeId nodeBananas;
static  UA_NodeId nodeName;

static volatile UA_Boolean running = true;

static void stopHandler(int sig) {
    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "received ctrl-c");
    running = false;
}

//display the data model tree
static void display_tree();

// Read callback
static void
readCallback(UA_Server *server,
               const UA_NodeId *sessionId, void *sessionContext,
               const UA_NodeId *nodeid, void *nodeContext,
               const UA_NumericRange *range, const UA_DataValue *data) {
    

    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "read from client on node : %.*s ",
     (int)nodeid->identifier.string.length, nodeid->identifier.string.data);

}

// Write callback
static void
writeCallback(UA_Server *server,
               const UA_NodeId *sessionId, void *sessionContext,
               const UA_NodeId *nodeid, void *nodeContext,
               const UA_NumericRange *range, const UA_DataValue *data) {
    

    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "write from client on node : %.*s", (int)nodeid->identifier.string.length, nodeid->identifier.string.data);

}


int main(int argc, char * argv[]) { 
    signal(SIGINT, stopHandler);
    signal(SIGTERM, stopHandler);

    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Initialisation ...\n");

    UA_Server * server = UA_Server_new();

    //get port number
    UA_Int16 port_number = (UA_Int16) PORT_SERVER;

    //Server config creation 
    UA_ServerConfig_setMinimal(UA_Server_getConfig(server), port_number, 0);

    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Configuration completed\n");

        

   

    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Server created\n");

    

    //--------------------------------------------DATA-------------------------------------------

    //Adding a new namepace to the server
    UA_Int16 ns_supermarket = UA_Server_addNamespace(server,"NS_Supermarket");
    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "New Namespace added with the number : %d",ns_supermarket);


    //adding a new Object Supermarket which is the major Node
    UA_NodeId node_supermaret_id; /* get the nodeid assigned by the server */
    UA_ObjectAttributes sAttr = UA_ObjectAttributes_default;
    UA_Server_addObjectNode(server, UA_NODEID_STRING(2,"Node_Supermarket"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                            UA_QUALIFIEDNAME(2, "Supermarket"), UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
                            sAttr, NULL, &node_supermaret_id);


    //adding the variable Name to server
    vnAttr = UA_VariableAttributes_default;
    UA_String marketName = UA_STRING("Fruits_Market_And_Co.");
    vnAttr.accessLevel = UA_ACCESSLEVELMASK_READ;
    UA_Variant_setScalar(&vnAttr.value, &marketName, &UA_TYPES[UA_TYPES_STRING]);
    UA_Server_addVariableNode(server, UA_NODEID_STRING(2,"Node_Market_Name"), node_supermaret_id,
                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                              UA_QUALIFIEDNAME(2, "Market_Name"),
                              UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), vnAttr, NULL, &nodeName);

    
    //adding a new Object Product which is a child Node of Supermarket
    UA_NodeId node_products_id; /* get the nodeid assigned by the server */
    UA_ObjectAttributes oAttr = UA_ObjectAttributes_default;
    UA_Server_addObjectNode(server, UA_NODEID_STRING(2,"Node_Products"),
                            node_supermaret_id,
                            UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                            UA_QUALIFIEDNAME(2, "Products"), UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
                            oAttr, NULL, &node_products_id);

    //adding the variable node Apples under products
    tpAttr = UA_VariableAttributes_default;
    UA_UInt32 apples = 60;
    tpAttr.accessLevel = UA_ACCESSLEVELMASK_READ ^ UA_ACCESSLEVELMASK_WRITE;
    UA_Variant_setScalar(&tpAttr.value, &apples, &UA_TYPES[UA_TYPES_UINT32]);
    UA_Server_addVariableNode(server, UA_NODEID_STRING(2,"Node_Apples"), node_products_id,
                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                              UA_QUALIFIEDNAME(2, "Apples"),
                              UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), tpAttr, NULL, &nodeApples);


    //adding the variable node Bananas under products
    bAttr = UA_VariableAttributes_default;
    UA_UInt32 bananas = 34;
    bAttr.accessLevel = UA_ACCESSLEVELMASK_READ ^ UA_ACCESSLEVELMASK_WRITE;
    UA_Variant_setScalar(&bAttr.value, &bananas, &UA_TYPES[UA_TYPES_UINT32]);
    UA_Server_addVariableNode(server, UA_NODEID_STRING(2,"Node_Bananas"), node_products_id,
                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                              UA_QUALIFIEDNAME(2, "Bananas"),
                              UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), bAttr, NULL, &nodeBananas);

    

    //Adding Callback to all Nodes
    UA_ValueCallback callback ;
    callback.onRead = readCallback;
    callback.onWrite = writeCallback;
    UA_Server_setVariableNode_valueCallback(server, UA_NODEID_STRING(2,"Node_Bananas"), callback);
    UA_Server_setVariableNode_valueCallback(server, UA_NODEID_STRING(2,"Node_Apples"), callback);
    UA_Server_setVariableNode_valueCallback(server, UA_NODEID_STRING(2,"Node_Market_Name"), callback);
    //-------------------------------------------------------------------------------------------
    
    display_tree(server);
    UA_StatusCode retval = UA_Server_run(server, &running);
    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "shutdown server ...");
    display_tree(server);
    UA_Server_delete(server);
    return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
}

//display the data model tree information (server side)
static void display_tree(UA_Server * serv) {

    UA_String str = * (UA_String *) vnAttr.value.data;
    UA_Variant value;
    UA_Variant_init(&value);
    UA_StatusCode retval = UA_Server_readValue(serv, nodeApples ,&value);
    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, ">>> %d", retval);
    UA_UInt32 nA = * (UA_UInt32 *) value.data;
    UA_Server_readValue(serv, nodeBananas ,&value);
    UA_UInt32 nB = * (UA_UInt32 *) value.data;

    printf("\n\n");
    printf("------* Supermarket\n");
    printf("      |\n");
    printf("      |\n");
    printf("      |--------* Products\n");
    printf("      |        |\n");
    printf("      |        |\n");
    printf("      |        |----------* Apples n = %d\n", (int) nA);
    printf("      |        |\n");
    printf("      |        |\n");
    printf("      |        |----------* Bananas n = %d\n", (int) nB);
    printf("      |\n");
    printf("      |\n");
    printf("      |--------* Name = %.*s", (int)str.length, str.data);
    printf("\n\n");

    UA_Variant_clear(&value);

}
# Makefile template for OPC UA

PROG = myServer.bin

SRCS = myServer.c #you can add here your other .c files

OBJS = $(SRCS:%.c=%.o)

#the path of open62541 library
PATHLIB = -L ../../lib/open62541/build/bin/

#the name of the library
LIB = open62541

#path of headers files
INCLUDE += -I ../../lib/open62541/include/
INCLUDE += -I ../../lib/open62541/plugins/include/
INCLUDE += -I ../../lib/open62541/build/src_generated/
INCLUDE += -I ../../lib/open62541/arch/
INCLUDE += -I ../../lib/open62541/deps/
CLEANFILES = $(PROG)

# Add / change option in CFLAGS and LDFLAGS
CFLAGS += -Wall 
CFLAGS += $(INCLUDE)

LDFLAGS += $(PATHLIB) -l$(LIB)

all: $(PROG)

$(PROG): $(OBJS)
	$(CC) -o $@ $^ $(LDFLAGS)

clean:
	rm -f $(CLEANFILES) $(patsubst %.c,%.o, $(SRCS))
  • you can build the server part:
 make
  • the binary myServer.bin is now cross-compiled and we can send it on our server STM32MP1 board.
 scp myServer.bin root@<IP of your server board>:/usr/local
  • Now let's do the same with client side:
 cd ..
 mkdir client && cd client
  • We will create myClient.c and Makefile:
#include <open62541/client_config_default.h>
#include <open62541/client_highlevel.h>
#include <open62541/plugin/log_stdout.h>

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "../common.h"

static volatile UA_Boolean running = true;

static void stopHandler(int sig) {
    UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "received ctrl-c");
    running = false;
}

int main(void) {
    signal(SIGINT, stopHandler);
    signal(SIGTERM, stopHandler);

    /* Create the client wich will listen on the port described in common.h */
    UA_Client *client = UA_Client_new();
    UA_ClientConfig_setDefault(UA_Client_getConfig(client));
    char address[64];
    char header[sizeof("opc.tcp://")] = "opc.tcp://";
    strcat(address, header);
    strcat(address, IP_SERVER);
    strcat(address, ":");
    char port[12];
    sprintf(port, "%d", PORT_SERVER);
    strcat(address, port);
    UA_StatusCode retval = UA_Client_connect(client, address); //IP / port of your server

    if(retval != UA_STATUSCODE_GOOD) {
        UA_Client_delete(client);
        return (int)retval;
    }


    //begin routine ---------------------

    while (running == true){
        
        //Variable to read from Server
        UA_String marketName;
        UA_UInt32 applesNumber;
        UA_UInt32 bananasNumber;

        //Variant that is used as buffer 
        UA_Variant value;
        UA_Variant_init(&value);

        //We read the name of the Supermarket
        retval = UA_Client_readValueAttribute(client, UA_NODEID_STRING(2,"Node_Market_Name"), &value);
        if(retval == UA_STATUSCODE_GOOD &&
            UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_STRING])) {
            marketName = *(UA_String *) value.data;
            UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,"The Market Name is : %.*s \n",(int)marketName.length, marketName.data);  
        }

        sleep(1);

        //We try to modify the name of Supermarket (should not work because we do not have writing rights)
        UA_String newName = UA_STRING("My_New_Fruit_Market.");
        UA_Variant_setScalar(&value, &newName, &UA_TYPES[UA_TYPES_STRING]);
        retval = UA_Client_writeValueAttribute(client, UA_NODEID_STRING(2,"Node_Market_Name"), &value);
        if(retval != UA_STATUSCODE_GOOD){
            UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "You do not have rights to modify the market name\n");
        }

        sleep(1);

        //We read the number of apples in the market 
        retval = UA_Client_readValueAttribute(client, UA_NODEID_STRING(2,"Node_Apples"), &value);
        if(retval == UA_STATUSCODE_GOOD &&
            UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_UINT32])) {
            applesNumber = *(UA_UInt32 *) value.data;
            UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,"The number of Apples is : %.d \n",(int)applesNumber);  
        }

        sleep(1);

        //We try to change the number of apples in the market (should work because we have writing rights)
        UA_UInt32 valA = applesNumber + 2;
        UA_Variant_setScalar(&value, &valA, &UA_TYPES[UA_TYPES_UINT32]);
        retval = UA_Client_writeValueAttribute(client, UA_NODEID_STRING(2,"Node_Apples"), &value);
        if(retval != UA_STATUSCODE_GOOD){
            UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Error when trying to change Apples number\n");
        }

        sleep(1);

        //We read the number of bananas in the market 
        retval = UA_Client_readValueAttribute(client, UA_NODEID_STRING(2,"Node_Bananas"), &value);
        if(retval == UA_STATUSCODE_GOOD &&
            UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_UINT32])) {
            bananasNumber = *(UA_UInt32 *) value.data;
            UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,"The number of Bananas is : %.d \n",(int)bananasNumber);  
        }

        sleep(1);

        //We try to change the number of apples in the market (should work because we have writing rights)
        UA_UInt32 valB = bananasNumber + 1;
        UA_Variant_setScalar(&value, &valB, &UA_TYPES[UA_TYPES_UINT32]);
        retval = UA_Client_writeValueAttribute(client, UA_NODEID_STRING(2,"Node_Bananas"), &value);
        if(retval != UA_STATUSCODE_GOOD){
            UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Error when trying to change Bananas number\n");
        }

        sleep(1);

    }

    //-----------------------------------
    

    /* Clean up */
    UA_Client_delete(client); /* Disconnects the client  */
    return EXIT_SUCCESS;
}
# Makefile template for OPC UA

PROG = myClient.bin

SRCS = myClient.c #you can add here your other .c files

OBJS = $(SRCS:%.c=%.o)

#the path of open62541 library
PATHLIB = -L ../../lib/open62541/build/bin/

#the name of the library
LIB = open62541

#path of headers files
INCLUDE += -I ../../lib/open62541/include/
INCLUDE += -I ../../lib/open62541/plugins/include/
INCLUDE += -I ../../lib/open62541/build/src_generated/
INCLUDE += -I ../../lib/open62541/arch/
INCLUDE += -I ../../lib/open62541/deps/
CLEANFILES = $(PROG)

# Add / change option in CFLAGS and LDFLAGS
CFLAGS += -Wall 
CFLAGS += $(INCLUDE)

LDFLAGS += $(PATHLIB) -l$(LIB)

all: $(PROG)

$(PROG): $(OBJS)
	$(CC) -o $@ $^ $(LDFLAGS)

clean:
	rm -f $(CLEANFILES) $(patsubst %.c,%.o, $(SRCS))
  • you can build the client part:
 make
  • the binary myClient.bin is now cross-compiled and we can send it on our client STM32MP1 board.
 scp myClient.bin root@<IP of your client board>:/usr/local

Now, your just have to open a shell for both of your board, and go to /usr/local/ folder, find binaries and execute them starting with server.

Info white.png Information
Find here the official open62541 website which give you access both to the most recent documentation and to the official Github of this stack.




No categories assignedEdit