1 /* This is a small demo of TFTP on the high-performance NetX TCP/IP stack. This demo
2 relies on ThreadX and NetX , to show a simple file transfer from the client
3 and then back to the server. */
4
5 /* Indicate if using a NetX TFTP services. To port a NetX TFTP application to NetX TFTP
6 undefine this term. */
7
8
9 #include "tx_api.h"
10 #include "nx_api.h"
11 #include "nxd_tftp_client.h"
12 #include "nxd_tftp_server.h"
13 #ifndef NX_TFTP_NO_FILEX
14 #include "fx_api.h"
15 #endif
16
17
18 #define USE_DUO
19
20 /* If the host application is using NetX Duo, determine which IP version to use.
21 Make sure IPv6 in NetX Duo is enabled if planning to use TFTP over IPv6 */
22 #ifdef USE_DUO
23 #define IP_TYPE 6
24 #endif /* USE_DUO */
25
26 #define DEMO_STACK_SIZE 4096
27 #define DEMO_DATA "ABCDEFGHIJKLMNOPQRSTUVWXYZ "
28
29 /* To use another file storage utility define this symbol:
30 #define NX_TFTP_NO_FILEX
31 */
32
33 /* Define the ThreadX, NetX, and FileX object control blocks... */
34
35 TX_THREAD server_thread;
36 TX_THREAD client_thread;
37 NX_PACKET_POOL server_pool;
38 NX_IP server_ip;
39 NX_PACKET_POOL client_pool;
40 NX_IP client_ip;
41 FX_MEDIA ram_disk;
42
43 /* Define the NetX TFTP object control blocks. */
44
45 NX_TFTP_CLIENT client;
46 NX_TFTP_SERVER server;
47
48 /* Define the application global variables */
49
50 #define CLIENT_ADDRESS IP_ADDRESS(1, 2, 3, 5)
51 #define SERVER_ADDRESS IP_ADDRESS(1, 2, 3, 4)
52
53 NXD_ADDRESS server_ip_address;
54 NXD_ADDRESS client_ip_address;
55
56 UINT error_counter = 0;
57
58 /* Define buffer used in the demo application. */
59 UCHAR buffer[255];
60 ULONG data_length;
61
62
63 /* Define the memory area for the FileX RAM disk. */
64 #ifndef NX_TFTP_NO_FILEX
65 UCHAR ram_disk_memory[32000];
66 UCHAR ram_disk_sector_cache[512];
67 #endif
68
69
70 /* Define function prototypes. */
71
72 VOID _fx_ram_driver(FX_MEDIA *media_ptr);
73 VOID _nx_ram_network_driver(NX_IP_DRIVER *driver_req_ptr);
74 void client_thread_entry(ULONG thread_input);
75 void server_thread_entry(ULONG thread_input);
76
77
78 /* Define main entry point. */
79
main()80 int main()
81 {
82
83 /* Enter the ThreadX kernel. */
84 tx_kernel_enter();
85 }
86
87
88 /* Define what the initial system looks like. */
89
tx_application_define(void * first_unused_memory)90 void tx_application_define(void *first_unused_memory)
91 {
92
93 UINT status;
94 UCHAR *pointer;
95
96
97 /* Setup the working pointer. */
98 pointer = (UCHAR *) first_unused_memory;
99
100
101 /* Create the main TFTP server thread. */
102 status = tx_thread_create(&server_thread, "TFTP Server Thread", server_thread_entry, 0,
103 pointer, DEMO_STACK_SIZE,
104 4,4, TX_NO_TIME_SLICE, TX_AUTO_START);
105
106 pointer += DEMO_STACK_SIZE ;
107
108 /* Check for errors. */
109 if (status)
110 error_counter++;
111
112
113 /* Create the main TFTP client thread at a slightly lower priority. */
114 status = tx_thread_create(&client_thread, "TFTP Client Thread", client_thread_entry, 0,
115 pointer, DEMO_STACK_SIZE,
116 5, 5, TX_NO_TIME_SLICE, TX_DONT_START);
117
118 pointer += DEMO_STACK_SIZE ;
119
120 /* Check for errors. */
121 if (status)
122 error_counter++;
123
124 /* Initialize the NetX system. */
125 nx_system_initialize();
126
127 /* Note: The data portion of a packet is exactly 512 bytes, but the packet payload size must
128 be at least 580 bytes. The remaining bytes are used for the UDP, IP, and Ethernet
129 headers and byte alignment requirements. */
130
131 status = nx_packet_pool_create(&server_pool, "TFTP Server Packet Pool", NX_TFTP_PACKET_SIZE, pointer, 8192);
132 pointer = pointer + 8192;
133
134 /* Check for errors. */
135 if (status)
136 error_counter++;
137
138 /* Create the IP instance for the TFTP Server. */
139 status = nx_ip_create(&server_ip, "NetX Server IP Instance", SERVER_ADDRESS, 0xFFFFFF00UL,
140 &server_pool, _nx_ram_network_driver, pointer, 2048, 1);
141 pointer = pointer + 2048;
142
143 /* Check for errors. */
144 if (status)
145 error_counter++;
146
147 #ifndef NX_DISABLE_IPV4
148 /* Enable ARP and supply ARP cache memory for IP Instance 0. */
149 status = nx_arp_enable(&server_ip, (void *) pointer, 1024);
150 pointer = pointer + 1024;
151
152 /* Check for errors. */
153 if (status)
154 error_counter++;
155 #endif /* NX_DISABLE_IPV4 */
156
157 /* Enable UDP. */
158 status = nx_udp_enable(&server_ip);
159
160 /* Check for errors. */
161 if (status)
162 error_counter++;
163
164
165 /* Create the TFTP server. */
166 #ifdef USE_DUO
167 #if (IP_TYPE == 6)
168 #ifdef FEATURE_NX_IPV6
169 /* Specify the tftp server global address. */
170 server_ip_address.nxd_ip_version = NX_IP_VERSION_V6;
171 server_ip_address.nxd_ip_address.v6[0] = 0x20010db1;
172 server_ip_address.nxd_ip_address.v6[1] = 0xf101;
173 server_ip_address.nxd_ip_address.v6[2] = 0;
174 server_ip_address.nxd_ip_address.v6[3] = 0x102;
175 #endif
176 #else
177 server_ip_address.nxd_ip_version = NX_IP_VERSION_V4;
178 server_ip_address.nxd_ip_address.v4 = SERVER_ADDRESS;
179
180 #endif
181
182 status = nxd_tftp_server_create(&server, "TFTP Server Instance", &server_ip, &ram_disk,
183 pointer, DEMO_STACK_SIZE, &server_pool);
184 #else
185 status = nx_tftp_server_create(&server, "TFTP Server Instance", &server_ip, &ram_disk,
186 pointer, DEMO_STACK_SIZE, &server_pool);
187 #endif
188
189 pointer = pointer + DEMO_STACK_SIZE;
190
191 /* Check for errors for the server. */
192 if (status)
193 error_counter++;
194
195 /* Create a packet pool for the TFTP client. */
196
197 /* Note: The data portion of a packet is exactly 512 bytes, but the packet payload size must
198 be at least 580 bytes. The remaining bytes are used for the UDP, IP, and Ethernet
199 headers and byte alignment requirements. */
200
201 status = nx_packet_pool_create(&client_pool, "TFTP Client Packet Pool", NX_TFTP_PACKET_SIZE, pointer, 8192);
202 pointer = pointer + 8192;
203
204 /* Create an IP instance for the TFTP client. */
205 status = nx_ip_create(&client_ip, "TFTP Client IP Instance", CLIENT_ADDRESS, 0xFFFFFF00UL,
206 &client_pool, _nx_ram_network_driver, pointer, 2048, 1);
207 pointer = pointer + 2048;
208
209 #ifndef NX_DISABLE_IPV4
210 /* Enable ARP and supply ARP cache memory for IP Instance 1. */
211 status = nx_arp_enable(&client_ip, (void *) pointer, 1024);
212 pointer = pointer + 1024;
213 #endif /* NX_DISABLE_IPV4 */
214
215 /* Enable UDP for client IP instance. */
216 status = nx_udp_enable(&client_ip);
217
218 /* Check for errors. */
219 if (status)
220 error_counter++;
221
222 tx_thread_resume(&client_thread);
223 }
224
server_thread_entry(ULONG thread_input)225 void server_thread_entry(ULONG thread_input)
226 {
227
228 UINT status, running;
229 #if (IP_TYPE == 6)
230 #ifdef FEATURE_NX_IPV6
231 UINT address_index;
232 UINT iface_index;
233 #endif
234 #endif
235
236 NX_PARAMETER_NOT_USED(thread_input);
237
238 /* Allow time for the network driver and NetX to get initialized. */
239 tx_thread_sleep(NX_IP_PERIODIC_RATE);
240
241 #ifndef NX_TFTP_NO_FILEX
242
243 /* Format the RAM disk - the memory for the RAM disk was defined above. */
244 status = fx_media_format(&ram_disk,
245 _fx_ram_driver, /* Driver entry */
246 ram_disk_memory, /* RAM disk memory pointer */
247 ram_disk_sector_cache, /* Media buffer pointer */
248 sizeof(ram_disk_sector_cache), /* Media buffer size */
249 "MY_RAM_DISK", /* Volume Name */
250 1, /* Number of FATs */
251 32, /* Directory Entries */
252 0, /* Hidden sectors */
253 256, /* Total sectors */
254 128, /* Sector size */
255 1, /* Sectors per cluster */
256 1, /* Heads */
257 1); /* Sectors per track */
258
259 /* Check for errors. */
260 if (status != FX_SUCCESS)
261 {
262 return;
263 }
264
265 /* Open the RAM disk. */
266 status = fx_media_open(&ram_disk, "RAM DISK", _fx_ram_driver, ram_disk_memory, ram_disk_sector_cache, sizeof(ram_disk_sector_cache));
267
268 /* Check for errors. */
269 if (status != FX_SUCCESS)
270 {
271 return;
272 }
273
274 #endif /* NX_TFTP_NO_FILEX */
275
276 #if (IP_TYPE == 6)
277 #ifdef FEATURE_NX_IPV6
278
279 /* Enable ICMPv6 services. */
280 status |= nxd_icmp_enable(&server_ip);
281 if (status != NX_SUCCESS)
282 {
283 return;
284 }
285
286 /* Enable IPv6 services for the server. */
287 status = nxd_ipv6_enable(&server_ip);
288 if (status != NX_SUCCESS)
289 {
290 return;
291 }
292
293 /* This assumes the primary interface. See the NetX Duo
294 User Guide for more information on address configuration. */
295 iface_index = 0;
296 status = nxd_ipv6_address_set(&server_ip, iface_index, NX_NULL, 10, &address_index);
297 status += nxd_ipv6_address_set(&server_ip, iface_index, &server_ip_address, 64, &address_index);
298
299 if (status != NX_SUCCESS)
300 {
301 return;
302 }
303
304 /* Wait for DAD to validate the address. */
305 tx_thread_sleep(5 * NX_IP_PERIODIC_RATE);
306 #endif
307
308 #endif /* IP_TYPE == 6 */
309
310 /* Start the NetX TFTP server. */
311 #ifdef USE_DUO
312 status = nxd_tftp_server_start(&server);
313 #else
314 status = nx_tftp_server_start(&server);
315 #endif
316
317 /* Check for errors. */
318 if (status)
319 {
320 error_counter++;
321 return;
322 }
323
324 /* Run for a while */
325 running = NX_TRUE;
326 while(running)
327 tx_thread_sleep(NX_IP_PERIODIC_RATE);
328
329 #ifdef USE_DUO
330 nxd_tftp_server_delete(&server);
331 #else
332 nx_tftp_server_delete(&server);
333 #endif
334
335 /* Flush the media of changed file data, close all open files and ensure
336 directory information is also written out to the media.*/
337 status = fx_media_close(&ram_disk);
338 if (status)
339 error_counter++;
340
341 return;
342 }
343
344 /* Define the TFTP client thread. */
345
client_thread_entry(ULONG thread_input)346 void client_thread_entry(ULONG thread_input)
347 {
348
349 NX_PACKET *my_packet;
350 UINT status;
351 UINT all_done = NX_FALSE;
352 #if (IP_TYPE == 6)
353 #ifdef FEATURE_NX_IPV6
354 UINT address_index;
355 UINT iface_index;
356 #endif
357 #endif
358
359 NX_PARAMETER_NOT_USED(thread_input);
360
361 /* Allow time for the network driver and NetX to get initialized. */
362 tx_thread_sleep(NX_IP_PERIODIC_RATE);
363
364 #if (IP_TYPE == 6)
365 #ifdef FEATURE_NX_IPV6
366
367 /* Enable ECMPv6 services for the client. */
368 status = nxd_icmp_enable(&client_ip);
369 if (status != NX_SUCCESS)
370 {
371 return;
372 }
373
374 /* Enable IPv6 services for the client. */
375 status = nxd_ipv6_enable(&client_ip);
376 if (status != NX_SUCCESS)
377 {
378 return;
379 }
380
381 /* Set the Client IPv6 address */
382 client_ip_address.nxd_ip_version = NX_IP_VERSION_V6;
383 client_ip_address.nxd_ip_address.v6[0] = 0x20010db1;
384 client_ip_address.nxd_ip_address.v6[1] = 0xf101;
385 client_ip_address.nxd_ip_address.v6[2] = 0;
386 client_ip_address.nxd_ip_address.v6[3] = 0x101;
387
388 /* This assumes the primary interface. See the NetX Duo
389 User Guide for more information on address configuration. */
390 iface_index = 0;
391 status = nxd_ipv6_address_set(&client_ip, iface_index, NX_NULL, 10, &address_index);
392 status += nxd_ipv6_address_set(&client_ip, iface_index, &client_ip_address, 64, &address_index);
393
394 if (status != NX_SUCCESS)
395 {
396 return;
397 }
398
399 /* Wait for the link local and global addresses to be validated. */
400 tx_thread_sleep(5 * NX_IP_PERIODIC_RATE);
401 #endif
402 #endif /*(IP_TYPE == 6) */
403
404
405 /* The TFTP services used below include the NetX equivalent service which will work with
406 NetX Duo TFTP. However, it is recommended for developers to port their applications
407 to the newer services that take the NXD_ADDRESS type and support both IPv4 and IPv6
408 communication.
409 */
410
411 /* Create a TFTP client. */
412 #ifdef USE_DUO
413 status = nxd_tftp_client_create(&client, "TFTP Client", &client_ip, &client_pool, IP_TYPE);
414 #else
415 status = nx_tftp_client_create(&client, "TFTP Client", &client_ip, &client_pool);
416 #endif
417
418 /* Check status. */
419 if (status)
420 return;
421
422 /* Open a TFTP file for writing. */
423 #ifdef USE_DUO
424 status = nxd_tftp_client_file_open(&client, "test.txt", &server_ip_address, NX_TFTP_OPEN_FOR_WRITE, NX_IP_PERIODIC_RATE, IP_TYPE);
425 #else
426 status = nx_tftp_client_file_open(&client, "test.txt", SERVER_ADDRESS, NX_TFTP_OPEN_FOR_WRITE, NX_IP_PERIODIC_RATE);
427 #endif
428
429 /* Check status. */
430 if (status)
431 return;
432
433 /* Allocate a TFTP packet. */
434 #ifdef USE_DUO
435 status = nxd_tftp_client_packet_allocate(&client_pool, &my_packet, NX_IP_PERIODIC_RATE, IP_TYPE);
436 #else
437 status = nx_tftp_client_packet_allocate(&client_pool, &my_packet, NX_IP_PERIODIC_RATE);
438 #endif
439 /* Check status. */
440 if (status)
441 error_counter++;
442
443 /* Write ABCs into the packet payload! */
444 memcpy(my_packet -> nx_packet_prepend_ptr, DEMO_DATA, sizeof(DEMO_DATA)); /* Use case of memcpy is verified. */
445
446 /* Adjust the write pointer. */
447 my_packet -> nx_packet_length = sizeof(DEMO_DATA);
448 my_packet -> nx_packet_append_ptr = my_packet -> nx_packet_prepend_ptr + sizeof(DEMO_DATA);
449
450 /* Write this packet to the file via TFTP. */
451 #ifdef USE_DUO
452 status = nxd_tftp_client_file_write(&client, my_packet, NX_IP_PERIODIC_RATE, IP_TYPE);
453 #else
454 status = nx_tftp_client_file_write(&client, my_packet, NX_IP_PERIODIC_RATE);
455 #endif
456
457 /* Check status. */
458 if (status)
459 error_counter++;
460
461 /* Close this file. */
462 #ifdef USE_DUO
463 status = nxd_tftp_client_file_close(&client, IP_TYPE);
464 #else
465 status = nx_tftp_client_file_close(&client);
466 #endif
467
468 /* Check status. */
469 if (status)
470 error_counter++;
471
472 /* Open the same file for reading. */
473 #ifdef USE_DUO
474 status = nxd_tftp_client_file_open(&client, "test.txt", &server_ip_address, NX_TFTP_OPEN_FOR_READ, NX_IP_PERIODIC_RATE, IP_TYPE);
475 #else
476 status = nx_tftp_client_file_open(&client, "test.txt", SERVER_ADDRESS, NX_TFTP_OPEN_FOR_READ, NX_IP_PERIODIC_RATE);
477 #endif
478
479 /* Check status. */
480 if (status)
481 error_counter++;
482 do
483 {
484
485 /* Read the file back. */
486 #ifdef USE_DUO
487 status = nxd_tftp_client_file_read(&client, &my_packet, NX_IP_PERIODIC_RATE, IP_TYPE);
488 #else
489 status = nx_tftp_client_file_read(&client, &my_packet, NX_IP_PERIODIC_RATE);
490 #endif
491 /* Check for retranmission/dropped packet error. Benign. Try again... */
492 if (status == NX_TFTP_INVALID_BLOCK_NUMBER)
493 {
494
495 continue;
496 }
497 else if (status == NX_TFTP_END_OF_FILE)
498 {
499
500 /* All done. */
501 all_done = NX_TRUE;
502 }
503 else if (status != NX_SUCCESS)
504 {
505
506 /* Internal error, invalid packet or error on read. */
507 break;
508 }
509
510
511 /* Do something with the packet data and release when done. */
512 nx_packet_data_retrieve(my_packet, buffer, &data_length);
513 buffer[data_length] = 0;
514 printf("Receive data: %s\n", buffer);
515
516 printf("release packet in demo.\n");
517
518 nx_packet_release(my_packet);
519
520 } while (all_done == NX_FALSE);
521
522 /* Close the file again. */
523 #ifdef USE_DUO
524 status = nxd_tftp_client_file_close(&client, IP_TYPE);
525 #else
526 status = nx_tftp_client_file_close(&client);
527 #endif
528
529 /* Check status. */
530 if (status)
531 error_counter++;
532
533 /* Delete the client. */
534 #ifdef USE_DUO
535 status = nxd_tftp_client_delete(&client);
536 #else
537 status = nx_tftp_client_delete(&client);
538 #endif
539
540 /* Check status. */
541 if (status)
542 error_counter++;
543
544 return;
545 }
546