- Last edited 5 months ago ago
How to install OPC UA
This stage explains how to properly install a library to use it on STM32MP1 boards.
Contents
1 Overview[edit]
Refer to the OPC UA overview for more details about this communication protocol.
2 Installation process[edit]
This section gives an overview of how to get the open62541 library for STM32MP1.
2.1 Install the SDK[edit]
- If the SDK is not yet installed, refer to STM32MP1_Developer_Package#Installing_the_SDK chapter before going further. It is essential later to cross-compile the library.
2.2 Create a new project[edit]
It is not required to follow this step, however this tutorial is based on a fake project to give an example of how to proceed.
- Create a directory to host the source codes
mkdir $HOME/Documents/OPC_UA_first_project mkdir $HOME/Documents/OPC_UA_first_project/src
- Create a directory to host the 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]
- Clone the repository needed to compile the library (git commands must be 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]
The SDK is useful as it builds a library usable with ARM binaries to execute the code on the cortex A7 of STM32MP1.
- Source the 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 succeeds try "echo $CROSS_COMPILE" to get the following answer:
echo $CROSS_COMPILE arm-ostl-linux-gnueabi-
- To cross compile the library use 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
- The library is now built and put into the bin folder. Check it here:
ls bin/ libopen62541.a
- To be sure that the library is well cross-compiled, enter the following command:
readelf -a bin/libopen62541.a
Many R_ARM notices are displayed with at the end, the following returns:
File Attributes Tag_CPU_name: "Cortex-A7" Tag_CPU_arch: v7 Tag_CPU_arch_profile: Application
3 Building your first program[edit]
As similar to other libraries, the Makefile must be edited with the path information where to find open62541 library, headers etc. As a first program the example used here is 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 whose content can be found here. Do not compile the code as it is done on the webpage.
1 #include <open62541/plugin/log_stdout.h>
2 #include <open62541/server.h>
3 #include <open62541/server_config_default.h>
4
5 #include <signal.h>
6 #include <stdlib.h>
7
8 static volatile UA_Boolean running = true;
9 static void stopHandler(int sig) {
10 UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "received ctrl-c");
11 running = false;
12 }
13
14 int main(void) {
15 signal(SIGINT, stopHandler);
16 signal(SIGTERM, stopHandler);
17
18 UA_Server *server = UA_Server_new();
19 UA_ServerConfig_setDefault(UA_Server_getConfig(server));
20
21 UA_StatusCode retval = UA_Server_run(server, &running);
22
23 UA_Server_delete(server);
24 return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
25 }
- Now create a new file called Makefile whose content is:
# 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))
- Now build the program:
make
- The executable program appears in the folder:
ls Makefile myServer.bin myServer.c myServer.o
4 Executing the program on STM32MP1[edit]
- Put myServer.bin on the board. This may be done in different ways, refer to How to cross-compile with the Developer Package part 9.3 for more information. In this case there is a simple way to do this:
scp myServer.bin root@<IP of your board>:/usr/local
- Then open another shell and connect to the board in ssh:
ssh root@<IP of your board>
- Go to the folder where the program is located and execute it:
cd /usr/local ./myServer.bin
- Output similar appears:
[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>
The first OPC UA program is now running on your board
5 Going further: make your first OPC UA Client/Server[edit]
As an example to illustrate this article, let's make an OPC UA Client/Server run on two different STM32MP1 (it can also be done with two shells on the PC, or two different PCs, or one PC and one board. Just make sure to have the right version of the library, cross-compiled or not, to do this). The two STM32MP1 are linked by Ethernet to the same network. The PC used for the development of the project is also in the same network (this helps to easily send the files by scp command later).
- Since two boards are used in this example, in order to not forget source the shell:
source <path_to_SDK>/environment-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
- Then create all the folders needed for this little project, 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, with the source code side add:
cd ../../.. mkdir src && cd src
- Create a common file for both client and server common.h:
1 #ifndef COMMON_H
2 #define COMMON_H
3
4 const char * IP_SERVER = "10.48.0.23"; //the address needs to be the IP of your board which is your server (ifconfig)
5 const int PORT_SERVER = 12345; //choose your port for the server
6
7 #endif /* COMMON_H */
- Now create files for the server:
mkdir server && cd server
- Create myServer.c and Makefile
1 /** DATA MODEL INFORMATION **
2 *
3 *
4 *
5 * ------* Supermarket
6 * |
7 * |
8 * |--------* Products
9 * | |
10 * | |
11 * | |----------* Apples (R/W)
12 * | |
13 * | |
14 * | |----------* Bananas (R/W)
15 * |
16 * |
17 * |--------* Name (R)
18 *
19 *
20 * The information model is based on a nodes model, and each endpoint of the tree has different values with Read/Write rights (R/W).
21 * The client will be able to manage the quantity of fruits, but only read the name of the market.
22 *
23 */
24
25 #include <open62541/plugin/log_stdout.h>
26 #include <open62541/server.h>
27 #include <open62541/server_config_default.h>
28
29 #include <signal.h>
30 #include <stdlib.h>
31 #include "../common.h"
32
33
34 static UA_VariableAttributes vnAttr;
35 static UA_VariableAttributes tpAttr;
36 static UA_VariableAttributes bAttr;
37
38 /* end tree node */
39 static UA_NodeId nodeApples;
40 static UA_NodeId nodeBananas;
41 static UA_NodeId nodeName;
42
43 static volatile UA_Boolean running = true;
44
45 static void stopHandler(int sig) {
46 UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "received ctrl-c");
47 running = false;
48 }
49
50 //display the data model tree
51 static void display_tree();
52
53 // Read callback
54 static void
55 readCallback(UA_Server *server,
56 const UA_NodeId *sessionId, void *sessionContext,
57 const UA_NodeId *nodeid, void *nodeContext,
58 const UA_NumericRange *range, const UA_DataValue *data) {
59
60
61 UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "read from client on node : %.*s ",
62 (int)nodeid->identifier.string.length, nodeid->identifier.string.data);
63
64 }
65
66 // Write callback
67 static void
68 writeCallback(UA_Server *server,
69 const UA_NodeId *sessionId, void *sessionContext,
70 const UA_NodeId *nodeid, void *nodeContext,
71 const UA_NumericRange *range, const UA_DataValue *data) {
72
73
74 UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "write from client on node : %.*s", (int)nodeid->identifier.string.length, nodeid->identifier.string.data);
75
76 }
77
78
79 int main(int argc, char * argv[]) {
80 signal(SIGINT, stopHandler);
81 signal(SIGTERM, stopHandler);
82
83 UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Initialisation ...\n");
84
85 UA_Server * server = UA_Server_new();
86
87 //get port number
88 UA_Int16 port_number = (UA_Int16) PORT_SERVER;
89
90 //Server config creation
91 UA_ServerConfig_setMinimal(UA_Server_getConfig(server), port_number, 0);
92
93 UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Configuration completed\n");
94
95
96
97
98
99 UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Server created\n");
100
101
102
103 //--------------------------------------------DATA-------------------------------------------
104
105 //Adding a new namepace to the server
106 UA_Int16 ns_supermarket = UA_Server_addNamespace(server,"NS_Supermarket");
107 UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "New Namespace added with the number : %d",ns_supermarket);
108
109
110 //adding a new Object Supermarket which is the major Node
111 UA_NodeId node_supermaret_id; /* get the nodeid assigned by the server */
112 UA_ObjectAttributes sAttr = UA_ObjectAttributes_default;
113 UA_Server_addObjectNode(server, UA_NODEID_STRING(2,"Node_Supermarket"),
114 UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
115 UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
116 UA_QUALIFIEDNAME(2, "Supermarket"), UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
117 sAttr, NULL, &node_supermaret_id);
118
119
120 //adding the variable Name to server
121 vnAttr = UA_VariableAttributes_default;
122 UA_String marketName = UA_STRING("Fruits_Market_And_Co.");
123 vnAttr.accessLevel = UA_ACCESSLEVELMASK_READ;
124 UA_Variant_setScalar(&vnAttr.value, &marketName, &UA_TYPES[UA_TYPES_STRING]);
125 UA_Server_addVariableNode(server, UA_NODEID_STRING(2,"Node_Market_Name"), node_supermaret_id,
126 UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
127 UA_QUALIFIEDNAME(2, "Market_Name"),
128 UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), vnAttr, NULL, &nodeName);
129
130
131 //adding a new Object Product which is a child Node of Supermarket
132 UA_NodeId node_products_id; /* get the nodeid assigned by the server */
133 UA_ObjectAttributes oAttr = UA_ObjectAttributes_default;
134 UA_Server_addObjectNode(server, UA_NODEID_STRING(2,"Node_Products"),
135 node_supermaret_id,
136 UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
137 UA_QUALIFIEDNAME(2, "Products"), UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
138 oAttr, NULL, &node_products_id);
139
140 //adding the variable node Apples under products
141 tpAttr = UA_VariableAttributes_default;
142 UA_UInt32 apples = 60;
143 tpAttr.accessLevel = UA_ACCESSLEVELMASK_READ ^ UA_ACCESSLEVELMASK_WRITE;
144 UA_Variant_setScalar(&tpAttr.value, &apples, &UA_TYPES[UA_TYPES_UINT32]);
145 UA_Server_addVariableNode(server, UA_NODEID_STRING(2,"Node_Apples"), node_products_id,
146 UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
147 UA_QUALIFIEDNAME(2, "Apples"),
148 UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), tpAttr, NULL, &nodeApples);
149
150
151 //adding the variable node Bananas under products
152 bAttr = UA_VariableAttributes_default;
153 UA_UInt32 bananas = 34;
154 bAttr.accessLevel = UA_ACCESSLEVELMASK_READ ^ UA_ACCESSLEVELMASK_WRITE;
155 UA_Variant_setScalar(&bAttr.value, &bananas, &UA_TYPES[UA_TYPES_UINT32]);
156 UA_Server_addVariableNode(server, UA_NODEID_STRING(2,"Node_Bananas"), node_products_id,
157 UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
158 UA_QUALIFIEDNAME(2, "Bananas"),
159 UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE), bAttr, NULL, &nodeBananas);
160
161
162
163 //Adding Callback to all Nodes
164 UA_ValueCallback callback ;
165 callback.onRead = readCallback;
166 callback.onWrite = writeCallback;
167 UA_Server_setVariableNode_valueCallback(server, UA_NODEID_STRING(2,"Node_Bananas"), callback);
168 UA_Server_setVariableNode_valueCallback(server, UA_NODEID_STRING(2,"Node_Apples"), callback);
169 UA_Server_setVariableNode_valueCallback(server, UA_NODEID_STRING(2,"Node_Market_Name"), callback);
170 //-------------------------------------------------------------------------------------------
171
172 display_tree(server);
173 UA_StatusCode retval = UA_Server_run(server, &running);
174 UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "shutdown server ...");
175 display_tree(server);
176 UA_Server_delete(server);
177 return retval == UA_STATUSCODE_GOOD ? EXIT_SUCCESS : EXIT_FAILURE;
178 }
179
180 //display the data model tree information (server side)
181 static void display_tree(UA_Server * serv) {
182
183 UA_String str = * (UA_String *) vnAttr.value.data;
184 UA_Variant value;
185 UA_Variant_init(&value);
186 UA_StatusCode retval = UA_Server_readValue(serv, nodeApples ,&value);
187 UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, ">>> %d", retval);
188 UA_UInt32 nA = * (UA_UInt32 *) value.data;
189 UA_Server_readValue(serv, nodeBananas ,&value);
190 UA_UInt32 nB = * (UA_UInt32 *) value.data;
191
192 printf("\n\n");
193 printf("------* Supermarket\n");
194 printf(" |\n");
195 printf(" |\n");
196 printf(" |--------* Products\n");
197 printf(" | |\n");
198 printf(" | |\n");
199 printf(" | |----------* Apples n = %d\n", (int) nA);
200 printf(" | |\n");
201 printf(" | |\n");
202 printf(" | |----------* Bananas n = %d\n", (int) nB);
203 printf(" |\n");
204 printf(" |\n");
205 printf(" |--------* Name = %.*s", (int)str.length, str.data);
206 printf("\n\n");
207
208 UA_Variant_clear(&value);
209
210 }
1 # Makefile template for OPC UA
2
3 PROG = myServer.bin
4
5 SRCS = myServer.c #you can add here your other .c files
6
7 OBJS = $(SRCS:%.c=%.o)
8
9 #the path of open62541 library
10 PATHLIB = -L ../../lib/open62541/build/bin/
11
12 #the name of the library
13 LIB = open62541
14
15 #path of headers files
16 INCLUDE += -I ../../lib/open62541/include/
17 INCLUDE += -I ../../lib/open62541/plugins/include/
18 INCLUDE += -I ../../lib/open62541/build/src_generated/
19 INCLUDE += -I ../../lib/open62541/arch/
20 INCLUDE += -I ../../lib/open62541/deps/
21 CLEANFILES = $(PROG)
22
23 # Add / change option in CFLAGS and LDFLAGS
24 CFLAGS += -Wall
25 CFLAGS += $(INCLUDE)
26
27 LDFLAGS += $(PATHLIB) -l$(LIB)
28
29 all: $(PROG)
30
31 $(PROG): $(OBJS)
32 $(CC) -o $@ $^ $(LDFLAGS)
33
34 clean:
35 rm -f $(CLEANFILES) $(patsubst %.c,%.o, $(SRCS))
- Build the server part:
make
- The binary myServer.bin is now cross-compiled and can be sent on the server STM32MP1 board.
scp myServer.bin root@<IP of your server board>:/usr/local
- Now do the same with client side:
cd .. mkdir client && cd client
- Create myClient.c and Makefile:
1 #include <open62541/client_config_default.h>
2 #include <open62541/client_highlevel.h>
3 #include <open62541/plugin/log_stdout.h>
4
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <time.h>
8 #include "../common.h"
9
10 static volatile UA_Boolean running = true;
11
12 static void stopHandler(int sig) {
13 UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "received ctrl-c");
14 running = false;
15 }
16
17 int main(void) {
18 signal(SIGINT, stopHandler);
19 signal(SIGTERM, stopHandler);
20
21 /* Create the client wich will listen on the port described in common.h */
22 UA_Client *client = UA_Client_new();
23 UA_ClientConfig_setDefault(UA_Client_getConfig(client));
24 char address[64];
25 char header[sizeof("opc.tcp://")] = "opc.tcp://";
26 strcat(address, header);
27 strcat(address, IP_SERVER);
28 strcat(address, ":");
29 char port[12];
30 sprintf(port, "%d", PORT_SERVER);
31 strcat(address, port);
32 UA_StatusCode retval = UA_Client_connect(client, address); //IP / port of your server
33
34 if(retval != UA_STATUSCODE_GOOD) {
35 UA_Client_delete(client);
36 return (int)retval;
37 }
38
39
40 //begin routine ---------------------
41
42 while (running == true){
43
44 //Variable to read from Server
45 UA_String marketName;
46 UA_UInt32 applesNumber;
47 UA_UInt32 bananasNumber;
48
49 //Variant that is used as buffer
50 UA_Variant value;
51 UA_Variant_init(&value);
52
53 //We read the name of the Supermarket
54 retval = UA_Client_readValueAttribute(client, UA_NODEID_STRING(2,"Node_Market_Name"), &value);
55 if(retval == UA_STATUSCODE_GOOD &&
56 UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_STRING])) {
57 marketName = *(UA_String *) value.data;
58 UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,"The Market Name is : %.*s \n",(int)marketName.length, marketName.data);
59 }
60
61 sleep(1);
62
63 //We try to modify the name of Supermarket (should not work because we do not have writing rights)
64 UA_String newName = UA_STRING("My_New_Fruit_Market.");
65 UA_Variant_setScalar(&value, &newName, &UA_TYPES[UA_TYPES_STRING]);
66 retval = UA_Client_writeValueAttribute(client, UA_NODEID_STRING(2,"Node_Market_Name"), &value);
67 if(retval != UA_STATUSCODE_GOOD){
68 UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "You do not have rights to modify the market name\n");
69 }
70
71 sleep(1);
72
73 //We read the number of apples in the market
74 retval = UA_Client_readValueAttribute(client, UA_NODEID_STRING(2,"Node_Apples"), &value);
75 if(retval == UA_STATUSCODE_GOOD &&
76 UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_UINT32])) {
77 applesNumber = *(UA_UInt32 *) value.data;
78 UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,"The number of Apples is : %.d \n",(int)applesNumber);
79 }
80
81 sleep(1);
82
83 //We try to change the number of apples in the market (should work because we have writing rights)
84 UA_UInt32 valA = applesNumber + 2;
85 UA_Variant_setScalar(&value, &valA, &UA_TYPES[UA_TYPES_UINT32]);
86 retval = UA_Client_writeValueAttribute(client, UA_NODEID_STRING(2,"Node_Apples"), &value);
87 if(retval != UA_STATUSCODE_GOOD){
88 UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Error when trying to change Apples number\n");
89 }
90
91 sleep(1);
92
93 //We read the number of bananas in the market
94 retval = UA_Client_readValueAttribute(client, UA_NODEID_STRING(2,"Node_Bananas"), &value);
95 if(retval == UA_STATUSCODE_GOOD &&
96 UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_UINT32])) {
97 bananasNumber = *(UA_UInt32 *) value.data;
98 UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,"The number of Bananas is : %.d \n",(int)bananasNumber);
99 }
100
101 sleep(1);
102
103 //We try to change the number of apples in the market (should work because we have writing rights)
104 UA_UInt32 valB = bananasNumber + 1;
105 UA_Variant_setScalar(&value, &valB, &UA_TYPES[UA_TYPES_UINT32]);
106 retval = UA_Client_writeValueAttribute(client, UA_NODEID_STRING(2,"Node_Bananas"), &value);
107 if(retval != UA_STATUSCODE_GOOD){
108 UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Error when trying to change Bananas number\n");
109 }
110
111 sleep(1);
112
113 }
114
115 //-----------------------------------
116
117
118 /* Clean up */
119 UA_Client_delete(client); /* Disconnects the client */
120 return EXIT_SUCCESS;
121 }
1 # Makefile template for OPC UA
2
3 PROG = myClient.bin
4
5 SRCS = myClient.c #you can add here your other .c files
6
7 OBJS = $(SRCS:%.c=%.o)
8
9 #the path of open62541 library
10 PATHLIB = -L ../../lib/open62541/build/bin/
11
12 #the name of the library
13 LIB = open62541
14
15 #path of headers files
16 INCLUDE += -I ../../lib/open62541/include/
17 INCLUDE += -I ../../lib/open62541/plugins/include/
18 INCLUDE += -I ../../lib/open62541/build/src_generated/
19 INCLUDE += -I ../../lib/open62541/arch/
20 INCLUDE += -I ../../lib/open62541/deps/
21 CLEANFILES = $(PROG)
22
23 # Add / change option in CFLAGS and LDFLAGS
24 CFLAGS += -Wall
25 CFLAGS += $(INCLUDE)
26
27 LDFLAGS += $(PATHLIB) -l$(LIB)
28
29 all: $(PROG)
30
31 $(PROG): $(OBJS)
32 $(CC) -o $@ $^ $(LDFLAGS)
33
34 clean:
35 rm -f $(CLEANFILES) $(patsubst %.c,%.o, $(SRCS))
- Build the client part:
make
- The binary myClient.bin is now cross-compiled and it can sent on the client STM32MP1 board.
scp myClient.bin root@<IP of your client board>:/usr/local
Now, open a shell for both of your boards, and go to /usr/local/ folder, find binaries and execute them starting with the server.