Hardwired TCP/IP Chapter 14: W55MH32 TFTP Example
Hardwired TCP/IP Chapter 14: W55MH32 TFTP Example

Hardwired TCP/IP Chapter 14: W55MH32 TFTP Example
In this article, we will provide a detailed explanation on how to implement the TFTP protocol on the W55MH32 chip. Through practical examples, we will also explain to you how to use the TFTP client mode to obtain text files from the server.
Other network protocols used in this example, such as DHCP, please refer to the relevant sections. Regarding the initialization process of the W55MH32, please refer to the Network Install section. We will not elaborate on this here.
1 Introduction to the TFTP Protocol
The TFTP (Trivial File Transfer Protocol) protocol is a lightweight file transfer protocol, which is commonly used in scenarios requiring fast and simple file exchange, especially during the startup and configuration of network devices. Unlike FTP (File Transfer Protocol), TFTP is designed very simply, only providing basic file reading and writing functions, and uses UDP as the transport layer protocol, thus lacking the complexity and retransmission mechanism of TCP.
2 Characteristics of the TFTP Protocol
Simplicity: The TFTP protocol is designed simply. Its header format is concise, and the types of operation commands are few, which makes it relatively easy to implement and requires less resource consumption.
Lightweight: The TFTP protocol does not require complex connection establishment and management processes. It has low overhead and is therefore suitable for use in environments with low performance requirements and limited resources.
Based on UDP: TFTP uses UDP as the transport layer protocol, taking advantage of UDP's fast transmission and connectionless characteristics, enabling fast data transmission. However, this also means that TFTP does not provide reliable transmission guarantees and requires reliability mechanisms to be implemented at the application layer.
Port fixed: TFTP uses the fixed port 69 to listen for client requests. The port used for data transmission is dynamically allocated, and a temporary port is selected for each transmission.
Data block size limit: Each data packet can transmit a maximum of 512 bytes of data. If the file is large, it will be transmitted in multiple parts, with each sending a 512-byte data block. The last data block may be less than 512 bytes, indicating the end of the file.
3 Application scenarios of the TFTP protocol
Next, let's take a look at what operations and applications can be accomplished using the TFTP protocol on the W55MH32?
Firmware upgrade: For network devices such as routers and switches, the TFTP protocol is often used to transfer firmware to these devices for firmware updates. The TFTP protocol ensures that firmware files are transmitted to the target devices quickly and accurately.
Configuration file transfer: The TFTP protocol is also commonly used to manage the configuration files of network devices. Transfer the configuration files to the network devices for configuration updates, or download the configuration files from the network devices for backup or analysis.
Firmware upgrade for IoT devices: Due to its simplicity and efficiency, the TFTP protocol has become a commonly used protocol for firmware upgrade of IoT devices.
4 The basic workflow of the TFTP protocol
Request sending: The client sends a read request (RRQ, Read Request) or a write request (WRQ, Write Request) to the server. These requests contain the file name to be read or written and the transmission mode (such as binary or ASCII code).
Establishing connection: After receiving the request from the client, the server, based on the file name and transmission mode in the request, opens the corresponding file (for write requests) or prepares to send the file data (for read requests), and sends a confirmation message to the client, thereby establishing the connection.
Data transmission: In the case of a write request, the client starts sending file data to the server, and the server receives and writes the file. The data is sent in the form of data blocks, with each data block typically being 512 bytes (but can be adjusted according to network conditions).
In the case of a read request, the server starts sending file data to the client, and the client receives and saves the file. Similarly, the data is also sent in the form of data blocks.
Response and confirmation: Whenever the client or server sends a data block, the receiving party sends an acknowledgment packet (ACK, Acknowledgment) to confirm the receipt of that data block. This acknowledgment packet contains the number of the received data block to ensure the order and integrity of the data.
Continuing transmission or ending: Based on the acknowledgment packet, the sender will continue to send the next data block until the entire file is transmitted. If an error occurs during the transmission process, the server will send an error information packet (ERROR) to the client, interrupting the transmission process.
Closing connection: After the file transmission is completed, the client and server will close the connection.
5 TFTP Protocol Message Analysis
Common operation codes:
1: Read Request (RRQ), used to request to read a file from the server.
2: Write Request (WRQ), used to request to write a file to the server.
3: Data (DATA), used to transmit file data.
4: Acknowledgment (ACK), used to confirm the received data blocks.
5: Error Information (ERROR), used to report errors that occur during the transmission process.
The message format of common operation codes is as follows:
Message type | Message format | Operation code | Other key fields and explanations |
Read Request (RRQ) | The total length is variable, consisting of a 2-byte operation code, a variable-length file name (ending with 1 byte 0), and a variable-length transmission mode (ending with 1 byte 0). | 1 | File name: Name of the file to be read Transmission mode: "netascii" indicates ASCII code mode, "octet" indicates binary mode |
Write Request (WRQ) | The total length is variable, consisting of a 2-byte operation code, a variable-length file name (ending with 1 byte 0), and a variable-length transmission mode (ending with 1 byte 0). | 2 | File name: Name of the file to be read Transmission mode: "netascii" indicates ASCII code mode, "octet" indicates binary mode |
(DATA) | Composed of a 2-byte operation code, a 2-byte data block identifier, and up to 512 bytes of data. | 3 | Data block number: Starts from 1 and is used to identify the sequence of data blocks Data: The actual transmitted file content |
Acknowledgment (ACK) | Composed of a 2-byte operation code and a 2-byte data block identification number | 4 | Data block number: Consistent with the received data block number, used for confirming reception |
(ERROR) | Composed of a 2-byte operation code, a 2-byte error code, and a variable-length error message (ending with 1 byte of 0) | 5 | Error code: Clearly identify the error type Error message: Provide a detailed description of the error situation |
Message example:
Client read request message:
|Message parsing|
Trivial File Transfer Protocol
Opcode: Read Request (1) (Operation code is 01, read request message)
Source File: tftp_test_file.txt (The file to be read is explicitly named tftp_test_file.txt)
Type: octet (The transmission mode is octet.)
Option: timeout = 5
|Original message|
00 01 74 66 74 70 5f 74 65 73 74 5f 66 69 6c 65 2e 74 78 74 00 6f 63 74 65 74 00 74 69 6d 65 6f 75 74 00 35 00
Server response message:
|Message parsing|
Trivial File Transfer Protocol
Opcode: Option Acknowledgement (6) (Operation code is 06, extended operation code)
[Destination File: tftp_test_file.txt]
[Read Request in frame 125]
Option: timeout = 5
|Original message|
00 06 74 69 6d 65 6f 75 74 00 35 00
Client response message:
|Message parsing|
Trivial File Transfer Protocol
Opcode: Acknowledgement (4) (Operation code is 04, response message)
[Destination File: tftp_test_file.txt]
[Read Request in frame 125]
Block: 0 (The data block is labeled as 00 0)
[Full Block Number: 0]
|Original message|
00 04 00 00
Server response message:
|Message parsing|
Trivial File Transfer Protocol
Opcode: Data Packet (3) (Operation code is 03, data message)
[Destination File: tftp_test_file.txt]
[Read Request in frame 125]
Block: 1 (The data block is labeled as 00 01)
[Full Block Number: 1]
Data (36 bytes)
Data: 736461666173646661736466617364666666666666666641617364666173666166736466 (Data)
[Length: 36]
|Original message|
00 03 00 01 73 64 61 66 61 73 64 66 61 73 64 66 61 73 64 66 66 66 66 66 66 66 66 41 61 73 64 66 61 73 66 61 66 73 64 66
Client response message:
|Message parsing|
Trivial File Transfer Protocol
Opcode: Acknowledgement (4) (Operation code is 04, response message)
[Destination File: tftp_test_file.txt]
[Read Request in frame 125]
Block: 1 (The data block is labeled as 00 01)
[Full Block Number: 1]
|Original message|
00 04 00 01
6 The implementation process
Next, we implement the TFTP protocol for file reading on the W55MH32. Note: The test instances require that the PC and W55MH32 be on the same network segment.
In the main function, the do_tftp_client() function is called to continuously check and handle the status of the TFTP client, and based on the read result (success or failure), enter the corresponding processing state.
1. do_tftp_client(SOCKET_ID, ethernet_buf);
The do_tftp_client() function is as follows:
1. void do_tftp_client(uint8_t sn, uint8_t *buff)
2. {
3. uint32_t tftp_server_ip = inet_addr(TFTP_SERVER_IP);
4. uint8_t tftp_read_file_name[] = TFTP_SERVER_FILE_NAME;
5.
6.
7. TFTP_init(sn, buff);
8. while (1)
9. {
10. if (tftp_read_flag == 0)
11. {
12. printf("tftp server ip: %s, file name: %s\r\n", TFTP_SERVER_IP, TFTP_SERVER_FILE_NAME);
13. printf("send request\r\n");
14. TFTP_read_request(tftp_server_ip, TFTP_SERVER_FILE_NAME);
15. tftp_read_flag = 1;
16. }
17. else
18. {
19. tftp_state = TFTP_run();
20. if (tftp_state == TFTP_SUCCESS)
21. {
22. printf("tftp read success, file name: %s\r\n", tftp_read_file_name);
23. while (1)
24. {
25. }
26. }
27. else if (tftp_state == TFTP_FAIL)
28. {
29. printf("tftp read fail, file name: %s\r\n", tftp_read_file_name);
30. while (1)
31. {
32. }
33. }
34. }
35. }
36. }
After entering the do_tftp_client() function, the TFTP client processing begins. The steps are as follows:
Step 1: TFTP initialization
The TFTP_init() function is called to initialize the TFTP client. The parameters sn and buff represent the socket number and socket buffer, respectively.
1. void TFTP_init(uint8_t socket, uint8_t *buf)
2. {
3. init_tftp();
4.
5. g_tftp_socket = open_tftp_socket(socket);
6. g_tftp_rcv_buf = buf;
7. }
1. static void init_tftp(void)
2. {
3. g_filename[0] = 0;
4.
5. set_server_ip(0);
6. set_server_port(0);
7. set_local_port(0);
8.
9. set_tftp_state(STATE_NONE);
10. set_block_number(0);
11.
12. // timeout flag
13. g_resend_flag = 0;
14. tftp_retry_cnt = tftp_time_cnt = 0;
16. g_progress_state = TFTP_PROGRESS;
17. }
Step 2: Send TFTP Read Request
When tftp_read_flag is 0, it indicates that the read request has not been sent yet. At this point, print the IP address of the TFTP server and the file name to be read, and then call the TFTP_read_request() function to send the read request to the server. After sending the request, set tftp_read_flag to 1, indicating that the request has been sent.
1. void TFTP_read_request(uint32_t server_ip, uint8_t *filename)
2. {
3. set_server_ip(server_ip);
4. #ifdef __TFTP_DEBUG__
5. DBG_PRINT(INFO_DBG, "[%s] Set Tftp Server : %x\r\n", __func__, server_ip);
6. #endif
7.
8. g_progress_state = TFTP_PROGRESS;
9. send_tftp_rrq(filename, (uint8_t *)TRANS_BINARY, &default_tftp_opt, 1);
10. }
Step 3: Run the TFTP protocol and handle the results
When tftp_read_flag is 1, call the TFTP_run() function to handle the TFTP protocol operation. Based on the returned tftp_state, determine the result: if it is TFTP_SUCCESS, print the success message and enter an infinite loop; if it is TFTP_FAIL, print the failure message and enter an infinite loop.
The TFTP_run() function is as follows:
int TFTP_run(void)
2. {
3. int len;
4. uint16_t from_port;
5. uint32_t from_ip;
6.
7. /* Timeout Process */
8. if (g_resend_flag)
9. {
10. if (tftp_time_cnt >= g_timeout)
11. {
12. switch (get_tftp_state())
13. {
14. case STATE_WRQ:
15. break;
16.
17. case STATE_RRQ:
18. send_tftp_rrq(g_filename, (uint8_t *)TRANS_BINARY, &default_tftp_opt, 1);
19. break;
20.
21. case STATE_OACK:
22. case STATE_DATA:
23. send_tftp_ack(get_block_number());
24. break;
25.
26. case STATE_ACK:
27. break;
28.
29. default:
30. break;
31. }
32.
33. tftp_time_cnt = 0;
34. tftp_retry_cnt++;
35.
36. if (tftp_retry_cnt >= 5)
37. {
38. init_tftp();
39. g_progress_state = TFTP_FAIL;
40. }
41. }
42. }
43.
44. /* Receive Packet Process */
45. len = recv_udp_packet(g_tftp_socket, g_tftp_rcv_buf, MAX_MTU_SIZE, &from_ip, &from_port);
46. if (len < 0)
47. {
48. #ifdef __TFTP_DEBUG__
49. DBG_PRINT(ERROR_DBG, "[%s] recv_udp_packet error\r\n", __func__);
50. #endif
51. return g_progress_state;
52. }
53.
54. recv_tftp_packet(g_tftp_rcv_buf, len, from_ip, from_port);
55.
56. return g_progress_state;
57. }
When processing the received TFTP data packets, the recv_tftp_packet() function is called first.
The recv_tftp_packet() function is as follows:
1. static void recv_tftp_packet(uint8_t *packet, uint32_t packet_len, uint32_t from_ip, uint16_t from_port)
2. {
3. uint16_t opcode;
4.
5. /* Verify Server IP */
6. if (from_ip != get_server_ip())
7. {
8. #ifdef __TFTP_DEBUG__
9. DBG_PRINT(ERROR_DBG, "[%s] Server IP faults\r\n", __func__);
10. DBG_PRINT(ERROR_DBG, "from IP : %08x, Server IP : %08x\r\n", from_ip, get_server_ip());
11. #endif
12. return;
13. }
14.
15. opcode = ntohs(*((uint16_t *)packet));
17. /* Set Server Port */
18. if ((get_tftp_state() == STATE_WRQ) || (get_tftp_state() == STATE_RRQ))
19. {
20. set_server_port(from_port);
21. #ifdef __TFTP_DEBUG__
22. DBG_PRINT(INFO_DBG, "[%s] Set Server Port : %d\r\n", __func__, from_port);
23. #endif
24. }
25.
26. switch (opcode)
27. {
28. case TFTP_RRQ: /* When Server */
29. recv_tftp_rrq(packet, packet_len);
30. break;
31. case TFTP_WRQ: /* When Server */
32. recv_tftp_wrq(packet, packet_len);
33. break;
34. case TFTP_DATA:
35. recv_tftp_data(packet, packet_len);
36. break;
37. case TFTP_ACK:
38. recv_tftp_ack(packet, packet_len);
39. break;
40. case TFTP_OACK:
41. recv_tftp_oack(packet, packet_len);
42. break;
43. case TFTP_ERROR:
44. recv_tftp_error(packet, packet_len);
45. break;
46.
47. default:
48. // Unknown Mesage
49. break;
50. }
51. }
After entering this function, the first step is to verify the source IP address of the received data packet. Only if it is consistent with the server's IP address will the processing continue; otherwise, it will directly return. Then, the operation code (opcode) is obtained from the data packet. Based on the obtained opcode, the corresponding processing function is called: if it is a TFTP read request (RRQ), the recv_tftp_rrq() function is called; if it is a write request (WRQ), the recv_tftp_wrq() function is called; for the received data packet, the recv_tftp_data() function is called; the confirmation of the data packet is handled by the recv_tftp_ack() function; the OACK packet is handled by the recv_tftp_oack() function; if an error data packet is encountered, the recv_tftp_error() function is called to parse the error code and error information. Finally, the g_progress_state is returned to indicate the current status of the TFTP operation.
7 Run results
After the burning routine is executed, the PHY link detection is carried out first, followed by the DHCP process for obtaining the network address result. Finally, the server IP and text name are printed, and the text content is read, as shown in the following figure:
8 Summary
This article explains how to implement the TFTP protocol on the W55MH32 chip. Through practical examples, it details the process of obtaining text files from the server using the TFTP client mode, covering the core steps such as TFTP initialization, sending read requests, running the protocol and handling results. The article also analyzes the introduction, features, application scenarios, basic workflow and message parsing of the TFTP protocol, helping readers understand its practical application value in file transfer.
The next article will focus on the SNMP protocol, analyzing its core principles and applications in network management, and explaining how to implement the SNMP function on related devices. Stay tuned!
WIZnet is a non-chipfoundry semiconductor company founded in 1998. Its products include the Internet processor iMCU™, which adopts TOE (TCP/IP Offloading Engine) technology and is based on a unique patented fully hardwired TCP/IP. iMCU™ is designed for embedded Internet devices in various applications.
WIZnet has over 70 distributors worldwide, with offices in Hong Kong, South Korea, and the United States, providing technical support and product marketing.
The region managed by the Hong Kong office includes: Australia, India, Turkey, and Asia (excluding South Korea and Japan).