more function and examples for embedded agent
[public/netxms.git] / doc / misc / embedded_nxcp.c
CommitLineData
050f5603
VK
1/**
2 * NXCP message builder for embedded systems
3 *
4 * Copyright (c) 2014 Raden Solutions
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19/**
20 * Configuration
21 */
22#define MAX_MSG_SIZE 512
23#define KEEP_MESSAGE_ID 1
24#define ALLOW_STRING_FIELDS 1
25#define ALLOW_INT64_FIELDS 0
26#define ALLOW_FLOAT_FIELDS 0
27#define ALLOW_BINARY_FIELDS 0
28
29/**
30 * Data types
31 */
32#define CSCP_DT_INTEGER 0
33#define CSCP_DT_STRING 1
34#define CSCP_DT_INT64 2
35#define CSCP_DT_INT16 3
36#define CSCP_DT_BINARY 4
37#define CSCP_DT_FLOAT 5
38
39/**
40 * Message flags
41 */
42#define MF_BINARY 0x0001
43#define MF_END_OF_FILE 0x0002
44#define MF_DONT_ENCRYPT 0x0004
45#define MF_END_OF_SEQUENCE 0x0008
46#define MF_REVERSE_ORDER 0x0010
47#define MF_CONTROL 0x0020
48
49
50#pragma pack(1)
51
52/**
53 * Data field structure
54 */
55typedef struct
56{
57 uint32_t id; // Variable identifier
58 char type; // Data type
59 char padding; // Padding
60 uint16_t wInt16;
61 union
62 {
63 uint32_t dwInteger;
64 uint64_t qwInt64;
65 double dFloat;
66 struct
67 {
68 uint32_t len;
69 uint16_t value[1];
70 } string;
71 } data;
72} NXCP_DF;
73
74#define df_int16 wInt16
75#define df_int32 data.dwInteger
76#define df_int64 data.qwInt64
77#define df_real data.dFloat
78#define df_string data.string
79
80/**
81 * Message structure
82 */
83typedef struct
84{
85 uint16_t code; // Message (command) code
86 uint16_t flags; // Message flags
87 uint32_t size; // Message size (including header) in bytes
88 uint32_t id; // Unique message identifier
89 uint32_t numFields; // Number of fields in message
90} NXCP_MESSAGE_HEADER;
91
92#pragma pack()
93
94/**
95 * NXCP message buffer
96 */
97char nxcp_message[MAX_MSG_SIZE] = "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00";
98
99#if KEEP_MESSAGE_ID
100static uint32_t nxcp_message_id = 1;
101#endif
102static char *curr;
103
104/**
105 * Initialize message
106 */
25d6a4aa 107void nxcp_init_message(uint16_t code)
050f5603 108{
25d6a4aa
VK
109 ((NXCP_MESSAGE_HEADER *)nxcp_message)->code = htons(code);
110 ((NXCP_MESSAGE_HEADER *)nxcp_message)->flags = 0;
050f5603
VK
111 ((NXCP_MESSAGE_HEADER *)nxcp_message)->numFields = 0;
112 curr = nxcp_message + 16;
113}
114
115/**
116 * Add INT16 field
117 */
118void nxcp_add_int16(uint32_t id, uint16_t value)
119{
120 NXCP_DF *df = (NXCP_DF *)curr;
121 df->id = htonl(id);
122 df->type = CSCP_DT_INT16;
123 df->df_int16 = htons(value);
124 curr += 8;
125 ((NXCP_MESSAGE_HEADER *)nxcp_message)->numFields++;
126}
127
128/**
129 * Add INT32 field
130 */
131void nxcp_add_int32(uint32_t id, uint32_t value)
132{
133 NXCP_DF *df = (NXCP_DF *)curr;
134 df->id = htonl(id);
135 df->type = CSCP_DT_INTEGER;
136 df->df_int32 = htonl(value);
137 curr += 16;
138 ((NXCP_MESSAGE_HEADER *)nxcp_message)->numFields++;
139}
140
141#if ALLOW_INT64_FIELDS
142
143/**
144 * Add INT64 field
145 */
146void nxcp_add_int64(uint32_t id, uint64_t value)
147{
148 NXCP_DF *df = (NXCP_DF *)curr;
149 df->id = htonl(id);
150 df->type = CSCP_DT_INT64;
151 df->df_int64 = htonll(value);
152 curr += 16;
153 ((NXCP_MESSAGE_HEADER *)nxcp_message)->numFields++;
154}
155
156#endif
157
158#if ALLOW_STRING_FIELDS
159
160/**
161 * Add string field
162 */
163void nxcp_add_string(uint32_t id, const char *value)
164{
165 uint32_t l;
166 const char *p;
167 NXCP_DF *df = (NXCP_DF *)curr;
168 df->id = htonl(id);
169 df->type = CSCP_DT_STRING;
0402dbc0 170 for(l = 0, p = value, curr += 12; *p != 0; l += 2, p++)
050f5603
VK
171 {
172 *(curr++) = 0;
173 *(curr++) = *p;
174 }
175 df->df_string.len = htonl(l);
176 int padding = 8 - (l + 12) % 8;
177 curr += (padding < 8) ? padding : 0;
178 ((NXCP_MESSAGE_HEADER *)nxcp_message)->numFields++;
179}
180
181#endif
182
183#if ALLOW_BINARY_FIELDS
184
185/**
186 * Add binary field
187 */
188void nxcp_add_binary(uint32_t id, const char *value, uint32_t len)
189{
190 NXCP_DF *df = (NXCP_DF *)curr;
191 df->id = htonl(id);
192 df->type = CSCP_DT_BINARY;
193 df->df_string.len = htonl(len);
194 curr += 12;
195 memcpy(curr, value, len);
196 curr += len;
197 int padding = 8 - (len + 12) % 8;
198 curr += (padding < 8) ? padding : 0;
199 ((NXCP_MESSAGE_HEADER *)nxcp_message)->numFields++;
200}
201
202#endif
203
204/**
205 * Finalize message. Returns number of bytes to be sent from nxcp_message array.
206 */
207uint32_t nxcp_finalize()
208{
209 uint32_t l = (uint32_t)(curr - nxcp_message);
210 ((NXCP_MESSAGE_HEADER *)nxcp_message)->size = htonl(l);
211 ((NXCP_MESSAGE_HEADER *)nxcp_message)->numFields = htonl(((NXCP_MESSAGE_HEADER *)nxcp_message)->numFields);
212#if KEEP_MESSAGE_ID
213 ((NXCP_MESSAGE_HEADER *)nxcp_message)->id = htonl(nxcp_message_id++);
214#endif
215 return l;
216}
25d6a4aa
VK
217
218/**
219 * Do preprocessing on message received into nxcp_message array. Returns message ID.
220 */
221uint32_t nxcp_preprocess_message()
222{
223 ((NXCP_MESSAGE_HEADER *)nxcp_message)->code = ntohs(((NXCP_MESSAGE_HEADER *)nxcp_message)->code);
224 ((NXCP_MESSAGE_HEADER *)nxcp_message)->size = ntohl(((NXCP_MESSAGE_HEADER *)nxcp_message)->size);
225 ((NXCP_MESSAGE_HEADER *)nxcp_message)->numFields = ntohl(((NXCP_MESSAGE_HEADER *)nxcp_message)->numFields);
226 ((NXCP_MESSAGE_HEADER *)nxcp_message)->id = htonl(((NXCP_MESSAGE_HEADER *)nxcp_message)->id);
227 return ((NXCP_MESSAGE_HEADER *)nxcp_message)->id;
228}
229
230/**
231 * Get request completion code. For simplicity function expects RCC to be first data field.
232 */
233uint32_t nxcp_get_rcc()
234{
235 CSCP_DF *field = (CSCP_DF *)(nxcp_message + 16);
236 if ((field->type == CSCP_DT_INTEGER) && (field->id == htonl(28)))
237 {
238 return ntohl(df->df_int32);
239 }
240 return 0;
241}
050f5603
VK
242
243#if 0
244
245/**
7777b139 246 * Login
050f5603 247 */
7777b139 248void login(const char *login, const char *passwd, const char *deviceId)
050f5603 249{
25d6a4aa 250 nxcp_init_message(0x0001);
7777b139
VK
251 nxcp_add_string(1, login);
252 nxcp_add_string(2, password);
253 nxcp_add_string(433, deviceId);
050f5603
VK
254 uint32_t l = nxcp_finalize();
255 /* now send l bytes from nxcp_message to the network */
256 send(sock, nxcp_message, l, 0);
257}
258
7777b139
VK
259/**
260 * Data push example
261 */
262void data_push()
263{
25d6a4aa 264 nxcp_init_message(0x00BB);
7777b139
VK
265
266 uint32_t id = 0x10000000;
267
268 // first parameter
269 nxcp_add_int32(id++, 0);
270 nxcp_add_string(id++, "Parameter1");
271 nxcp_add_string(id++, "value1");
272
273 // second parameter
274 nxcp_add_int32(id++, 0);
275 nxcp_add_string(id++, "Parameter2");
276 nxcp_add_string(id++, "value2");
277
278 // parameter count
279 nxcp_add_int32(111, 2);
280
281 send(sock, nxcp_message, l, 0);
282}
283
25d6a4aa
VK
284void send_location()
285{
286 nxcp_init_message(0x0109);
287
288 nxcp_add_int16(342, 2); // location type - GPS
289 nxcp_add_int32(343, lat); // latitude (float value * 1000000)
290 nxcp_add_int32(344, lon); // longitude (float value * 1000000)
291 nxcp_add_int16(438, 0); // accuracy in meters
292 nxcp_add_int64(439, ts); // timestamp as UNIX time
293
294 // it is also possible to report battery level if applicable
295 // (if not applicable, do not set this field)
296 nxcp_add_int16(427, 100); // battery level %
297
298 send(sock, nxcp_message, l, 0);
299}
300
301/**
302 * Check ID and return code in received message
303 */
304void check_result()
305{
306 recv(sock, nxcp_message, MAX_MSG_SIZE, 0);
307
308 uint32_t id = nxcp_preprocess_message(); // will match request ID
309 uint32_t rcc = nxcp_get_rcc(); // will be 0 for success
310}
311
050f5603 312#endif