demo_node_operator.c
Go to the documentation of this file.
1 /*******************************************************************************
2  * Copyright (C) 2019 Moxa Inc. All rights reserved.
3  * SPDX-License-Identifier: Apache-2.0
4  *
5  * Demo Node Operator
6  *
7  * Date Author Comment
8  * 2019-06-05 Rich Liao Created it.
9  ******************************************************************************/
10 
25 #include <unistd.h>
26 #include <string.h>
27 
29 #include <mx_node_sdk/mx_node_interface_basic.h>
30 #include <mx_node_sdk/mx_node_interface_data_access.h>
31 
32 #define NUM_DATA 12
33 
35 typedef enum
36 {
41 
42 typedef struct _MY_DATA
43 {
46  struct timeval timestamp;
47 } MY_DATA;
48 
49 struct timeval now();
51 void rotate(char* str);
52 
56 
59 const char* mx_node_operator_get_version()
60 {
61  return "1.0";
62 }
63 
65 {
67 }
68 
70 {
71  g_operator_handle = operator_handle;
73 
74  for (int i = 0; i < NUM_DATA; ++i)
75  {
76  g_my_data[i].data.type = i;
77  if (MX_NODE_VALUE_TYPE_STRING == g_my_data[i].data.type)
78  {
79  g_my_data[i].data.value.s = malloc(8);
80  strcpy(g_my_data[i].data.value.s, "abcdefg");
81  }
82  else
83  memset(&g_my_data[i].data.value, 0, sizeof(g_my_data[i].data.value));
84  }
85 
86  return add_my_nodes();
87 }
88 
90 {
91  for (int i = 0; i < NUM_DATA; ++i)
92  {
93  if (MX_NODE_VALUE_TYPE_STRING == g_my_data[i].data.type)
94  free(g_my_data[i].data.value.s);
95  }
96 }
97 
99 {
102  {
103  for (int i = 0; i < NUM_DATA; ++i)
104  {
105  g_my_data[i].timestamp = now();
106  switch (g_my_data[i].data.type)
107  {
109  g_my_data[i].data.value.b = !g_my_data[i].data.value.b;
110  break;
112  g_my_data[i].data.value.i8++;
113  break;
115  g_my_data[i].data.value.i16++;
116  break;
118  g_my_data[i].data.value.i32++;
119  break;
121  g_my_data[i].data.value.i64++;
122  break;
124  g_my_data[i].data.value.u8++;
125  break;
127  g_my_data[i].data.value.u16++;
128  break;
130  g_my_data[i].data.value.u32++;
131  break;
133  g_my_data[i].data.value.u64++;
134  break;
136  g_my_data[i].data.value.f++;
137  break;
139  g_my_data[i].data.value.d++;
140  break;
142  rotate(g_my_data[i].data.value.s);
143  break;
144  default:
145  continue;
146  }
147  mx_node_update_node(g_my_data[i].node_handle, &g_my_data[i].data, &g_my_data[i].timestamp);
148  }
149  sleep(3);
150  }
152 }
153 
155 {
157  {
159  while (g_state != OPERATOR_STATE_STOP);
160  }
161 }
163 
166 {
167  for (int i = 0; i < NUM_DATA; ++i)
168  {
169  if (node_handle == g_my_data[i].node_handle)
170  {
171  *node_value = g_my_data[i].data;
172  *node_timestamp = g_my_data[i].timestamp;
173  return MX_NODE_RESULT_GOOD;
174  }
175  }
176  return MX_NODE_RESULT_BAD;
177 }
178 
180 {
181  for (int i = 0; i < NUM_DATA; ++i)
182  {
183  if (node_handle == g_my_data[i].node_handle)
184  {
185  g_my_data[i].data = *node_value;
186  g_my_data[i].timestamp = now();
187  return MX_NODE_RESULT_GOOD;
188  }
189  }
190  return MX_NODE_RESULT_BAD;
191 }
194 
196 {
197  // DemoFolder
198  // |--DemoObject
199  // |--DemoBoolean
200  // |--DemoTimeZone (property, value: 480)
201  // |--DemoInt8
202  // |--DemoTimeZone (property, value: 480)
203  // |--DemoInt16
204  // |--DemoTimeZone (property, value: 480)
205  // |--DemoInt32
206  // |--DemoTimeZone (property, value: 480)
207  // |--DemoInt64
208  // |--DemoTimeZone (property, value: 480)
209  // |--DemoUInt8
210  // |--DemoTimeZone (property, value: 480)
211  // |--DemoUInt16
212  // |--DemoTimeZone (property, value: 480)
213  // |--DemoUInt32
214  // |--DemoTimeZone (property, value: 480)
215  // |--DemoUInt64
216  // |--DemoTimeZone (property, value: 480)
217  // |--DemoFloat
218  // |--DemoTimeZone (property, value: 480)
219  // |--DemoDouble
220  // |--DemoTimeZone (property, value: 480)
221  // |--DemoString
222  // |--DemoTimeZone (property, value: 480)
223 
224  MX_NODE_RESULT res;
225 
226  // folder
227  MX_NODE_NODE folder;
228  {
229  strcpy(folder.node_name, "DemoFolder");
231  strcpy(folder.description, "DemoFolder's Description");
232  }
233  MX_NODE_NODE_HANDLE folder_handle;
234  res = mx_node_add_node(g_operator_handle, &folder, &folder_handle);
235  if (res != MX_NODE_RESULT_GOOD)
236  return res;
237 
238  // object
239  MX_NODE_NODE object;
240  {
241  strcpy(object.node_name, "DemoObject");
242  object.node_type = MX_NODE_NODE_TYPE_OBJECT;
243  strcpy(object.description, "DemoObject's Description");
244  }
245  MX_NODE_NODE_HANDLE object_handle;
246  res = mx_node_add_node(g_operator_handle, &object, &object_handle);
247  if (res != MX_NODE_RESULT_GOOD)
248  return res;
249  res = mx_node_set_parent_node(object_handle, folder_handle);
250  if (res != MX_NODE_RESULT_GOOD)
251  return res;
252 
253  // variable
254  char* node_name[NUM_DATA] = {
255  "DemoBoolean", "DemoInt8", "DemoInt16", "DemoInt32",
256  "DemoInt64", "DemoUInt8", "DemoUInt16", "DemoUInt32",
257  "DemoUInt64", "DemoFloat", "DemoDouble", "DemoString"
258  };
259 
260  for (int i = 0; i < NUM_DATA; ++i)
261  {
262  MX_NODE_NODE variable;
263  {
264  strcpy(variable.node_name, node_name[i]);
266  strcpy(variable.description, node_name[i]);
267  strcat(variable.description, "'s Description");
269  variable.variable.value = g_my_data[i].data;
270  }
271  res = mx_node_add_node(g_operator_handle, &variable, &g_my_data[i].node_handle);
272  if (res != MX_NODE_RESULT_GOOD)
273  return res;
274  res = mx_node_set_parent_node(g_my_data[i].node_handle, object_handle);
275  if (res != MX_NODE_RESULT_GOOD)
276  return res;
277  }
278 
279  // property
280  MX_NODE_NODE property;
281  {
282  strcpy(property.node_name, "DemoTimeZone");
283  property.node_type = MX_NODE_NODE_TYPE_PROPERTY;
284  strcpy(property.description, "DemoTimeZone's Description");
285  property.property.access_right = MX_NODE_ACCESS_RIGHT_READONLY;
286  property.property.value.type = MX_NODE_VALUE_TYPE_INT32;
287  property.property.value.value.i32 = 480;
288  }
289  for (int i = 0; i < NUM_DATA; ++i)
290  {
291  MX_NODE_NODE_HANDLE property_handle;
292  res = mx_node_add_node(g_operator_handle, &property, &property_handle);
293  if (res != MX_NODE_RESULT_GOOD)
294  return res;
295  res = mx_node_set_parent_node(property_handle, g_my_data[i].node_handle);
296  if (res != MX_NODE_RESULT_GOOD)
297  return res;
298  }
299 
300  return MX_NODE_RESULT_GOOD;
301 }
302 
303 struct timeval now()
304 {
305  struct timeval t;
306  gettimeofday(&t, NULL);
307  return t;
308 }
309 
310 void rotate(char* str)
311 {
312  if (str[0] != '\0')
313  {
314  char tmp = str[0];
315  int i = 0;
316  while (str[i + 1] != '\0')
317  {
318  str[i] = str[i + 1];
319  ++i;
320  }
321  str[i] = tmp;
322  }
323 }
MX_NODE_VARIANT value
MX_NODE_RESULT mx_node_add_node(MX_NODE_NODE_OPERATOR_HANDLE operator_handle, MX_NODE_NODE *node, MX_NODE_NODE_HANDLE *node_handle)
Add a node to OPC UA server.
MX_NODE_RESULT mx_node_operator_write_node(MX_NODE_NODE_HANDLE node_handle, const MX_NODE_VARIANT *node_value)
Write data by handle index.
volatile OPERATOR_STATE g_state
A variant structure is used to store different type&#39;s data.
void mx_node_operator_start()
A notify to inform node operator start with non-blocking.
size_t MX_NODE_NODE_HANDLE
Handle of a node.
Definition: mx_node_node.h:42
#define INTERFACE_MX_NODE_BASIC
Interface basic&#39;s flag.
struct _MY_DATA MY_DATA
MX_NODE_VARIABLE variable
enum _MX_NODE_RESULT MX_NODE_RESULT
A result enumeration represents success or not.
#define NUM_DATA
include interfaces
MX_NODE_VARIANT data
void mx_node_operator_stop()
A notify to inform node operator stopping.
A node&#39;s sturcture contain name, description, node type and attribute.
MY_DATA g_my_data[NUM_DATA]
MX_NODE_RESULT mx_node_set_parent_node(MX_NODE_NODE_HANDLE node_handle, MX_NODE_NODE_HANDLE parent_node_handle)
Set a node&#39;s parent.
#define INTERFACE_MX_NODE_DATA_ACCESS
Interface data access&#39;s flag.
const char * mx_node_operator_get_version()
Get node operator&#39;s version.
MX_NODE_RESULT mx_node_operator_read_node(MX_NODE_NODE_HANDLE node_handle, MX_NODE_VARIANT *node_value, struct timeval *node_timestamp)
Read a node&#39;s data and timestamp.
long long mx_node_operator_get_supported_interfaces()
Get supported interfaces.
void rotate(char *str)
MX_NODE_ACCESS_RIGHT access_right
struct timeval now()
char node_name[MAX_NODE_NAME_LEN]
char description[MAX_NODE_DESC_LEN]
MX_NODE_VALUE_TYPE type
void mx_node_operator_uninitialize()
Do node operator&#39;s uninitialize.
MX_NODE_RESULT add_my_nodes()
MX_NODE_NODE_HANDLE node_handle
union _MX_NODE_VARIANT::@0 value
struct timeval timestamp
MX_NODE_NODE_TYPE node_type
MX_NODE_RESULT mx_node_operator_initialize(MX_NODE_NODE_OPERATOR_HANDLE operator_handle)
Do node operator&#39;s initialize, like create nodes.
MX_NODE_RESULT mx_node_update_node(MX_NODE_NODE_HANDLE node_handle, MX_NODE_VARIANT *value, struct timeval *timestamp)
Update a node&#39;s data and timestamp.
MX_NODE_NODE_OPERATOR_HANDLE g_operator_handle
size_t MX_NODE_NODE_OPERATOR_HANDLE
Handle of a node operator.
Definition: mx_node_node.h:37
OPERATOR_STATE
custom define