1 /***************************************************************************
2 * Copyright (c) 2024 Microsoft Corporation
3 *
4 * This program and the accompanying materials are made available under the
5 * terms of the MIT License which is available at
6 * https://opensource.org/licenses/MIT.
7 *
8 * SPDX-License-Identifier: MIT
9 **************************************************************************/
10
11 #include "nx_api.h"
12 #include "nx_azure_iot.h"
13 #ifndef DEMO_DHCP_DISABLE
14 #include "nxd_dhcp_client.h"
15 #endif /* DEMO_DHCP_DISABLE */
16 #include "nxd_dns.h"
17 #include "nx_secure_tls_api.h"
18 #include <setjmp.h>
19 #include <cmocka.h> /* macros: https://api.cmocka.org/group__cmocka__asserts.html */
20
21 /* Include the demo. */
22 extern VOID demo_entry(NX_IP* ip_ptr, NX_PACKET_POOL* pool_ptr, NX_DNS* dns_ptr, UINT (*unix_time_callback)(ULONG *unix_time));
23
24 /* Define the helper thread for running Azure SDK on ThreadX (THREADX IoT Platform). */
25 #ifndef DEMO_HELPER_STACK_SIZE
26 #define DEMO_HELPER_STACK_SIZE (2048)
27 #endif /* DEMO_HELPER_STACK_SIZE */
28
29 #ifndef DEMO_HELPER_THREAD_PRIORITY
30 #define DEMO_HELPER_THREAD_PRIORITY (4)
31 #endif /* DEMO_HELPER_THREAD_PRIORITY */
32
33 /* Define user configurable symbols. */
34 #ifndef DEMO_IP_STACK_SIZE
35 #define DEMO_IP_STACK_SIZE (2048)
36 #endif /* DEMO_IP_STACK_SIZE */
37
38 #ifndef DEMO_PACKET_COUNT
39 #define DEMO_PACKET_COUNT (32)
40 #endif /* DEMO_PACKET_COUNT */
41
42 #ifndef DEMO_PACKET_SIZE
43 #define DEMO_PACKET_SIZE (1536)
44 #endif /* DEMO_PACKET_SIZE */
45
46 #define DEMO_POOL_SIZE ((DEMO_PACKET_SIZE + sizeof(NX_PACKET)) * DEMO_PACKET_COUNT)
47
48 #ifndef DEMO_ARP_CACHE_SIZE
49 #define DEMO_ARP_CACHE_SIZE (512)
50 #endif /* DEMO_ARP_CACHE_SIZE */
51
52 #ifndef DEMO_IP_THREAD_PRIORITY
53 #define DEMO_IP_THREAD_PRIORITY (1)
54 #endif /* DEMO_IP_THREAD_PRIORITY */
55
56 #ifdef DEMO_DHCP_DISABLE
57 #ifndef DEMO_IPV4_ADDRESS
58 /*#define DEMO_IPV4_ADDRESS IP_ADDRESS(192, 168, 100, 33)*/
59 #error "SYMBOL DEMO_IPV4_ADDRESS must be defined. This symbol specifies the IP address of device. "
60 #endif /* DEMO_IPV4_ADDRESS */
61
62 #ifndef DEMO_IPV4_MASK
63 /*#define DEMO_IPV4_MASK 0xFFFFFF00UL*/
64 #error "SYMBOL DEMO_IPV4_MASK must be defined. This symbol specifies the IP address mask of device. "
65 #endif /* DEMO_IPV4_MASK */
66
67 #ifndef DEMO_GATEWAY_ADDRESS
68 /*#define DEMO_GATEWAY_ADDRESS IP_ADDRESS(192, 168, 100, 1)*/
69 #error "SYMBOL DEMO_GATEWAY_ADDRESS must be defined. This symbol specifies the gateway address for routing. "
70 #endif /* DEMO_GATEWAY_ADDRESS */
71
72 #ifndef DEMO_DNS_SERVER_ADDRESS
73 /*#define DEMO_DNS_SERVER_ADDRESS IP_ADDRESS(192, 168, 100, 1)*/
74 #error "SYMBOL DEMO_DNS_SERVER_ADDRESS must be defined. This symbol specifies the dns server address for routing. "
75 #endif /* DEMO_DNS_SERVER_ADDRESS */
76 #else
77 #define DEMO_IPV4_ADDRESS IP_ADDRESS(0, 0, 0, 0)
78 #define DEMO_IPV4_MASK IP_ADDRESS(0, 0, 0, 0)
79 #endif /* DEMO_DHCP_DISABLE */
80
81 #ifndef NETWORK_DRIVER
82 #define NETWORK_DRIVER _nx_pcap_network_driver
83 #endif /* NETWORK_DRIVER */
84
85
86 static TX_THREAD demo_helper_thread;
87 static NX_PACKET_POOL pool_0;
88 static NX_IP ip_0;
89 static NX_DNS dns_0;
90 #ifndef DEMO_DHCP_DISABLE
91 static NX_DHCP dhcp_0;
92 #endif /* DEMO_DHCP_DISABLE */
93
94
95 /* Define the stack/cache for ThreadX. */
96 static ULONG demo_ip_stack[DEMO_IP_STACK_SIZE / sizeof(ULONG)];
97 #ifndef DEMO_POOL_STACK_USER
98 static ULONG demo_pool_stack[DEMO_POOL_SIZE / sizeof(ULONG)];
99 static ULONG demo_pool_stack_size = sizeof(demo_pool_stack);
100 #else
101 extern ULONG demo_pool_stack[];
102 extern ULONG demo_pool_stack_size;
103 #endif
104 static ULONG demo_arp_cache_area[DEMO_ARP_CACHE_SIZE / sizeof(ULONG)];
105 static ULONG demo_helper_thread_stack[DEMO_HELPER_STACK_SIZE / sizeof(ULONG)];
106
107 /* Define the prototypes for demo thread. */
108 static void demo_helper_thread_entry(ULONG parameter);
109 static void test_entry(void **state);
110
111 #ifndef DEMO_DHCP_DISABLE
112 static void dhcp_wait();
113 #endif /* DEMO_DHCP_DISABLE */
114
115 static UINT dns_create();
116
117 static UINT unix_time_get(ULONG *unix_time);
118
119 /* Include the platform IP driver. */
120 extern void NETWORK_DRIVER(NX_IP_DRIVER*);
121
122 int g_argc = 0;
123 char **g_argv = NULL;
124
125 /* Define main entry point. */
main(int argc,char ** argv)126 int main(int argc, char **argv)
127 {
128
129 /* Initialize random seed. */
130 srand(time(0));
131
132 /* Save arguments passed from command line. */
133 g_argc = argc;
134 g_argv = argv;
135
136 /* Enter the ThreadX kernel. */
137 tx_kernel_enter();
138 }
139
140 /* Define what the initial system looks like. */
tx_application_define(void * first_unused_memory)141 void tx_application_define(void *first_unused_memory)
142 {
143
144 UINT status;
145
146 /* Initialize the NetX system. */
147 nx_system_initialize();
148
149 /* Create a packet pool. */
150 status = nx_packet_pool_create(&pool_0, "NetX Main Packet Pool", DEMO_PACKET_SIZE,
151 (UCHAR *)demo_pool_stack , demo_pool_stack_size);
152
153 /* Check for pool creation error. */
154 if (status)
155 {
156 printf("nx_packet_pool_create fail: %u\r\n", status);
157 return;
158 }
159
160 /* Create an IP instance. */
161 status = nx_ip_create(&ip_0, "NetX IP Instance 0",
162 DEMO_IPV4_ADDRESS, DEMO_IPV4_MASK,
163 &pool_0, NETWORK_DRIVER,
164 (UCHAR*)demo_ip_stack, sizeof(demo_ip_stack),
165 DEMO_IP_THREAD_PRIORITY);
166
167 /* Check for IP create errors. */
168 if (status)
169 {
170 printf("nx_ip_create fail: %u\r\n", status);
171 return;
172 }
173
174 /* Enable ARP and supply ARP cache memory for IP Instance 0. */
175 status = nx_arp_enable(&ip_0, (VOID *)demo_arp_cache_area, sizeof(demo_arp_cache_area));
176
177 /* Check for ARP enable errors. */
178 if (status)
179 {
180 printf("nx_arp_enable fail: %u\r\n", status);
181 return;
182 }
183
184 /* Enable ICMP traffic. */
185 status = nx_icmp_enable(&ip_0);
186
187 /* Check for ICMP enable errors. */
188 if (status)
189 {
190 printf("nx_icmp_enable fail: %u\r\n", status);
191 return;
192 }
193
194 /* Enable TCP traffic. */
195 status = nx_tcp_enable(&ip_0);
196
197 /* Check for TCP enable errors. */
198 if (status)
199 {
200 printf("nx_tcp_enable fail: %u\r\n", status);
201 return;
202 }
203
204 /* Enable UDP traffic. */
205 status = nx_udp_enable(&ip_0);
206
207 /* Check for UDP enable errors. */
208 if (status)
209 {
210 printf("nx_udp_enable fail: %u\r\n", status);
211 return;
212 }
213
214 /* Initialize TLS. */
215 nx_secure_tls_initialize();
216
217 /* Create demo helper thread. */
218 status = tx_thread_create(&demo_helper_thread, "Demo Thread",
219 demo_helper_thread_entry, 0,
220 demo_helper_thread_stack, DEMO_HELPER_STACK_SIZE,
221 DEMO_HELPER_THREAD_PRIORITY, DEMO_HELPER_THREAD_PRIORITY,
222 TX_NO_TIME_SLICE, TX_AUTO_START);
223
224 /* Check status. */
225 if (status)
226 {
227 printf("Demo helper thread creation fail: %u\r\n", status);
228 return;
229 }
230 }
231
232 /* Define demo helper thread entry. */
demo_helper_thread_entry(ULONG parameter)233 void demo_helper_thread_entry(ULONG parameter)
234 {
235 const struct CMUnitTest tests[] =
236 {
237 cmocka_unit_test(test_entry),
238 };
239
240 setbuf(stdout, NULL);
241 exit(cmocka_run_group_tests(tests, NULL, NULL));
242 }
243
log_callback(az_log_classification classification,UCHAR * msg,UINT msg_len)244 static void log_callback(az_log_classification classification, UCHAR *msg, UINT msg_len)
245 {
246 if (classification == AZ_LOG_IOT_AZURERTOS)
247 {
248 printf("%.*s", msg_len, (CHAR *)msg);
249 }
250 }
251
test_entry(void ** state)252 static void test_entry(void **state)
253 {
254 UINT status;
255 ULONG ip_address = 0;
256 ULONG network_mask = 0;
257 ULONG gateway_address = 0;
258
259 #ifndef DEMO_DHCP_DISABLE
260 dhcp_wait();
261 #else
262 nx_ip_gateway_address_set(&ip_0, DEMO_GATEWAY_ADDRESS);
263 #endif /* DEMO_DHCP_DISABLE */
264
265 /* Get IP address and gateway address. */
266 nx_ip_address_get(&ip_0, &ip_address, &network_mask);
267 nx_ip_gateway_address_get(&ip_0, &gateway_address);
268
269 /* Output IP address and gateway address. */
270 printf("IP address: %lu.%lu.%lu.%lu\r\n",
271 (ip_address >> 24),
272 (ip_address >> 16 & 0xFF),
273 (ip_address >> 8 & 0xFF),
274 (ip_address & 0xFF));
275 printf("Mask: %lu.%lu.%lu.%lu\r\n",
276 (network_mask >> 24),
277 (network_mask >> 16 & 0xFF),
278 (network_mask >> 8 & 0xFF),
279 (network_mask & 0xFF));
280 printf("Gateway: %lu.%lu.%lu.%lu\r\n",
281 (gateway_address >> 24),
282 (gateway_address >> 16 & 0xFF),
283 (gateway_address >> 8 & 0xFF),
284 (gateway_address & 0xFF));
285
286 /* Create DNS. */
287 status = dns_create();
288
289 /* Check for DNS create errors. */
290 if (status)
291 {
292 printf("dns_create fail: %u\r\n", status);
293 return;
294 }
295
296 nx_azure_iot_log_init(log_callback);
297
298 /* Start demo. */
299 demo_entry(&ip_0, &pool_0, &dns_0, unix_time_get);
300 }
301
302 #ifndef DEMO_DHCP_DISABLE
dhcp_wait()303 static void dhcp_wait()
304 {
305 ULONG actual_status;
306
307 printf("DHCP In Progress...\r\n");
308
309 /* Create the DHCP instance. */
310 nx_dhcp_create(&dhcp_0, &ip_0, "DHCP Client");
311
312 /* Start the DHCP Client. */
313 nx_dhcp_start(&dhcp_0);
314
315 /* Wait util address is solved. */
316 nx_ip_status_check(&ip_0, NX_IP_ADDRESS_RESOLVED, &actual_status, NX_WAIT_FOREVER);
317 }
318 #endif /* DEMO_DHCP_DISABLE */
319
dns_create()320 static UINT dns_create()
321 {
322
323 UINT status;
324 ULONG dns_server_address[3];
325 UINT dns_server_address_size = 12;
326
327 /* Create a DNS instance for the Client. Note this function will create
328 the DNS Client packet pool for creating DNS message packets intended
329 for querying its DNS server. */
330 status = nx_dns_create(&dns_0, &ip_0, (UCHAR *)"DNS Client");
331 if (status)
332 {
333 return(status);
334 }
335
336 /* Is the DNS client configured for the host application to create the packet pool? */
337 #ifdef NX_DNS_CLIENT_USER_CREATE_PACKET_POOL
338
339 /* Yes, use the packet pool created above which has appropriate payload size
340 for DNS messages. */
341 status = nx_dns_packet_pool_set(&dns_0, ip_0.nx_ip_default_packet_pool);
342 if (status)
343 {
344 nx_dns_delete(&dns_0);
345 return(status);
346 }
347 #endif /* NX_DNS_CLIENT_USER_CREATE_PACKET_POOL */
348
349 #ifndef DEMO_DHCP_DISABLE
350 /* Retrieve DNS server address. */
351 nx_dhcp_interface_user_option_retrieve(&dhcp_0, 0, NX_DHCP_OPTION_DNS_SVR, (UCHAR *)(dns_server_address),
352 &dns_server_address_size);
353 #else
354 dns_server_address[0] = DEMO_DNS_SERVER_ADDRESS;
355 #endif /* DEMO_DHCP_DISABLE */
356
357 /* Add an IPv4 server address to the Client list. */
358 status = nx_dns_server_add(&dns_0, dns_server_address[0]);
359 if (status)
360 {
361 nx_dns_delete(&dns_0);
362 return(status);
363 }
364
365 /* Output DNS Server address. */
366 printf("DNS Server address: %lu.%lu.%lu.%lu\r\n",
367 (dns_server_address[0] >> 24),
368 (dns_server_address[0] >> 16 & 0xFF),
369 (dns_server_address[0] >> 8 & 0xFF),
370 (dns_server_address[0] & 0xFF));
371
372 return(NX_SUCCESS);
373 }
374
unix_time_get(ULONG * unix_time)375 static UINT unix_time_get(ULONG *unix_time)
376 {
377
378 *unix_time = (ULONG)time(NULL);
379
380 return(NX_SUCCESS);
381 }
382