Hardwired TCP/IP Chapter 19: W55MH32 FTP Client Example
Hardwired TCP/IP Chapter 19: W55MH32 FTP Client Example

Hardwired TCP/IP Chapter 19: W55MH32 FTP Client Example
In this article, we will provide a detailed explanation on how to implement the client mode of the FTP protocol on the W55MH32 chip. Through practical examples, we will also explain to you how to use the client mode of the FTP protocol on the W55MH32 to access the FTP server and download files.
Other network protocols used in this routine, 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 it here.
1 Introduction to the FTP Protocol
FTP (File Transfer Protocol) is a standard network protocol used for transferring files between clients and servers. The FTP client protocol is implemented based on the FTP protocol and is used to guide the client on how to communicate with the FTP server, enabling functions such as file upload, download, and directory operations. Since FTP was originally designed for plaintext transmission and is not secure enough, adding an SSL/TLS encryption layer to FTP can provide encrypted control connections and data connections. The following is an introduction to the main content and working mechanism of the FTP client protocol.
2 Characteristics of FTP Protocol
1. Based on TCP transmission:
FTP uses two TCP connections: a control connection (port 21) and a data connection (port 20 or a dynamically assigned port in PASV mode) to ensure reliable data transmission.
1. Separate control and data:
- The control connection is used to send commands and receive responses.
- The data connection is used for the transmission of file content or directory information.
2. Support for multiple transmission modes:
- Active mode (Active Mode): The server initiates the connection to the client's data port.
- Passive mode (Passive Mode): The client initiates the connection to the server's provided data port, addressing NAT firewall restrictions.
3. Support for multiple file operations:
- File upload (STOR), download (RETR), deletion (DELE).
- Directory operations (MKD, RMD, CWD, PWD).
- Retrieving file list (LIST, NLST).
4. Plain text transmission (traditional FTP):
- Usernames, passwords, and data are transmitted in plain text, which is insecure.
- Security improvements: FTPS (FTP Secure, based on SSL/TLS) and SFTP (Secure File Transfer Protocol, based on SSH).
5. Flexible user authentication mechanism:
- Supports anonymous login (anonymous users can use email as the password).
- Supports authenticated usernames and passwords.
3 Application scenarios of the FTP protocol
Next, let's take a look at what operations and applications can be accomplished using the FTP protocol on the W55MH32?
Version upgrade: The embedded device downloads the latest firmware file from the remote server via the FTP client and performs the upgrade.
Log download: The embedded device generates logs, monitoring data, or user interaction records during operation, and uploads them to the remote server via the FTP client.
Configuration saving: Users can upload configuration files to the FTP server for backup or sharing.
Offline mode data synchronization: The embedded device saves data locally when running in offline mode, and synchronizes it to the server via FTP after network recovery.
4 FTP Workflow
1. Establish a control connection
- Client initialization: The client starts the FTP client program and specifies the address and port number (port 21) of the FTP server to connect to.
- TCP connection establishment: The client initiates a connection request to the server's 21 port via the TCP protocol. The server listens on this port and, upon receiving the request, establishes a TCP connection with the client. This connection is called the control connection and is mainly used for transmitting FTP commands and server response information.
- Authentication: After the connection is established, the server prompts the client to enter a username and password for authentication. The client sends the corresponding username and password information to the server. After the server verifies the credentials, it allows the client to proceed with subsequent operations. Some anonymous FTP servers also allow users to log in with "anonymous" as the username and an email address as the password, providing public file access services.
2. Selection of transmission mode
The client and server negotiate the data transmission mode on the control connection. There are mainly two modes:
- Active mode (PORT mode): The client informs the server of its data port (a randomly opened port by the client) through the control connection. The server uses port 20 to actively connect to the client's data port to transmit data.
- Passive mode (PASV mode): The client sends the PASV command to the server, and the server informs the client of a temporary data port it has opened (usually a port above 1024), and then the client uses a random port to connect to this temporary data port of the server to transmit data.
3. Data transmission
Based on the user's operation requirements, file or directory-related operations are performed through the data connection:
- Upload files: The client sends the STOR (store) command to the server, and then transmits the local file data to the server through the data connection. After receiving the data, the server stores it in the specified directory.
- Download files: The client sends the RETR (retrieve) command to the server to request the download of a file from the server. The server transmits the file data through the data connection to the client, and the client receives the data and saves it to the local specified location.
- Directory operations: The client can also send commands such as LIST (list directory contents), CWD (change working directory), MKD (create directory), RMD (delete directory), etc. The server executes the corresponding operations and returns the operation results through the control connection. When transmitting data such as directory lists, etc., it will also be transmitted through the data connection when executing these commands.
4. Closing the connection
- Data connection closure: After completing file transmission or other operations, the data connection will be closed. If there are other operations to be performed, the client and server can re-establish the data connection as needed.
- Control connection closure: When the client completes all operations, it sends the QUIT command to the server. The server receives the command and closes the control connection. Thus, the FTP session between the client and the server ends.
5 Explanation of Active Mode and Passive Mode
Active Mode:
- The client opens a port and starts listening.
- The client informs the server of its own IP and port through the control connection.
- The server actively connects to the port specified by the client and transmits data.
Passive Mode:
- The client initiates the connection request in a passive mode.
- The server opens a random port and informs the client through the control connection.
- The client initiatively connects to the port specified by the server to transmit data.
Comparison of advantages and disadvantages:
- The active mode is more suitable for environments where there are no firewall restrictions on the server-side network.
- The passive mode is more suitable for situations where the client is behind a NAT or firewall.
6 FTP client implementation functions
The core functions of an FTP client include:
1. Connecting to an FTP server.
2. User authentication.
3. Uploading and downloading files.
4. Browsing and managing the directory structure of the server.
5. Supporting the switching between active mode and passive mode.
6. Providing the feature of resuming interrupted transfers (for some advanced clients).
7 FTP Message Analysis
FTP messages are divided into command and response messages. Command messages are used to send operation requests, while response messages are used to return results.
The format of command messages is "<command> <parameters>\r\n", and the field explanations are as follows:
- <Command>: FTP commands (such as USER, PASS).
- <Parameter>: Additional information for the command (such as username, file name).
For example, "USER username\r\n". Common commands include login (USER, PASS), file operations (RETR, STOR), directory operations (LIST, CWD), etc. Each FTP message consists of the command or response code, status code and additional data. The status code is used to indicate the operation result.
The following are common FTP commands:
- USER: Provide the username for identity verification.
- PASS: Provide the password for identity verification.
- CWD: Change the current working directory.
- PWD: Display the current working directory.
- LIST: List the files and subdirectories in the directory.
- RETR: Download files from the server.
- STOR: Upload files to the server.
- DELE: Delete the specified file.
- MKD: Create a new directory.
- RMD: Delete a directory.
- QUIT: Terminate the session and exit.
- TYPE: Set the file transfer type (ASCII or Binary).
- PORT: Specify the port for the data connection.
- PASV: Enable passive mode, where the server specifies a port for the client to connect to.
The response message format is "<status code> <description>\r\n", and the field explanations are as follows:
<status code>: Three-digit number representing the status.
<description>: Text description of the status.
For example, "230 User logged in, proceed.\r\n". Here are some common response codes in FTP:
- 1xx (Informative response): Mainly provides some preliminary information, usually indicating that the server is processing the request and has not completed the operation.
- 2xx (Successful response): Indicates that the command has been successfully executed. This is one of the types of responses that clients most hope to see, indicating that the operation requested (such as login, file transfer, etc.) has been completed successfully.
- 3xx (Additional information response): Indicates that the server needs some additional information to complete the operation. Usually occurs during authentication or file location processes.
- 4xx (Temporary error response): Indicates that the client's request has a problem, but the error is temporary and can be resolved by some adjustments (such as re-sending the request, etc.).
- 5xx (Permanent error response): Indicates that the client's request has an error, and this error is relatively serious and is difficult to correct through simple adjustments.
Next, let's take a look at an example of the FTP message for obtaining a directory:
1. The client establishes a TCP connection to the server's port 21.
2. The server responds: 220 Welcome to FTP Server\r\n
3. The client sends: USER wiznet\r\n
4. The server responds: 331 User wiznet OK. Password required\r\n
5. The client sends: PASS wiznet\r\n
6. The server responds: 230 User logged in\r\n
7. The client sends: PORT 192,168,1,5,20,100\r\n (Active mode. 192,168,1,5 is the client's address, 20,100 is the client's expected port number, 20*256 + 100 = 5260)
8. The server responds: 200 PORT command successful\r\n
9. The client sends: LIST\r\n (DIR command, to obtain the file information of the current directory)
10. The server replies: 150 Opening ASCII mode data connection for file list\r\n
11. The server initiates a TCP connection to the client's expected port number and transmits the directory information. After the transmission is completed, the TCP connection is closed.
12. The client sends: QUIT\r\n (To exit the FTP session)
13. The server responds: 221 Goodbye\r\n
8 The implementation process
Next, let's take a look at how to implement the FTP protocol Client mode on the W55MH32.
Note: The test instance requires that the PC and the W55MH32 be on the same network segment.
Step 1: Initialization of FTP Client Mode
1. void ftpc_init(uint8_t *src_ip, uint8_t sn_ctrl, uint8_t sn_data)
2. {
3. ftpc.dsock_mode = ACTIVE_MODE;
4.
5. local_ip.cVal[0] = src_ip[0];
6. local_ip.cVal[1] = src_ip[1];
7. local_ip.cVal[2] = src_ip[2];
8. local_ip.cVal[3] = src_ip[3];
9. local_port = 35000;
10. socket_ctrl = sn_ctrl;
11. socket_data = sn_data;
12. strcpy(ftpc.workingdir, "/");
13. socket(socket_ctrl, Sn_MR_TCP, FTP_destport, 0x0);
14. }
15.
The main function of the ftpc_init() function is to initialize the configuration and state of the FTP client, including setting the transmission mode, local IP address and port, socket, working directory, and creating a control socket for command transmission.
Step 2: Run the ftpc_run() function within the main loop
1. while (1)
2. {
3. ftpc_run(ethernet_buf);
4. }
The ftpc_run() function is as follows:
1. uint8_t ftpc_run(uint8_t *dbuf)
2. {
3. uint16_t size = 0;
4. long ret = 0;
5. #if defined(F_FILESYSTEM)
6. uint32_t send_byte;
7. #endif
8. uint32_t recv_byte;
9. uint32_t blocklen;
10. uint32_t remain_filesize;
11. uint32_t remain_datasize;
12. uint8_t dat[50] = {
13. 0,
14. };
15.
16. switch (getSn_SR(socket_ctrl))
17. {
18. case SOCK_ESTABLISHED:
19. if (!connect_state_control_ftpc)
20. {
21. printf("%d:FTP Connected\r\n", socket_ctrl);
22. strcpy(ftpc.workingdir, "/");
23. connect_state_control_ftpc = 1;
24. }
25. if (gMenuStart)
26. {
27. gMenuStart = 0;
28. printf("\r\n----------------------------------------\r\n");
29. printf("Press menu key\r\n");
30. printf("----------------------------------------\r\n");
31. printf("1> View FTP Server Directory\r\n");
32. printf("2> View My Directory\r\n");
33. printf("3> Sets the type of file to be transferred. Current state : %s\r\n", (ftpc.type == ASCII_TYPE) ? "Ascii" : "Binary");
34. printf("4> Sets Data Connection. Current state : %s\r\n", (ftpc.dsock_mode == ACTIVE_MODE) ? "Active" : "Passive");
35. printf("5> Put File to Server\r\n");
36. printf("6> Get File from Server\r\n");
37. #if defined(F_FILESYSTEM)
38. printf("7> Delete My File\r\n");
39. #endif
40. printf("----------------------------------------\r\n");
41. while (1)
42. {
43. memset(gMsgBuf, 0, sizeof(gMsgBuf));
44. scanf("%s", gMsgBuf);
45. if (gMsgBuf[0] == '1')
46. {
47. if (ftpc.dsock_mode == PASSIVE_MODE)
48. {
49. sprintf((char *)dat, "PASV\r\n");
50. send(socket_ctrl, (uint8_t *)dat, strlen((char *)dat));
51. Command.First = f_dir;
52. break;
53. }
54. else
55. {
56. wiz_NetInfo gWIZNETINFO;
57. ctlnetwork(CN_GET_NETINFO, (void *)&gWIZNETINFO);
58. sprintf((char *)dat, "PORT %d,%d,%d,%d,%d,%d\r\n", gWIZNETINFO.ip[0], gWIZNETINFO.ip[1], gWIZNETINFO.ip[2], gWIZNETINFO.ip[3], (uint8_t)(local_port >> 8), (uint8_t)(local_port & 0x00ff));
59. send(socket_ctrl, (uint8_t *)dat, strlen((char *)dat));
60. Command.First = f_dir;
61.
62. gModeActivePassiveflag = 1;
63. break;
64. }
65. }
66. else if (gMsgBuf[0] == '5')
67. {
68. if (ftpc.dsock_mode == PASSIVE_MODE)
69. {
70. sprintf((char *)dat, "PASV\r\n");
71. send(socket_ctrl, (uint8_t *)dat, strlen((char *)dat));
72. Command.First = f_put;
73. break;
74. }
75. else
76. {
77. wiz_NetInfo gWIZNETINFO;
78. ctlnetwork(CN_GET_NETINFO, (void *)&gWIZNETINFO);
79. sprintf((char *)dat, "PORT %d,%d,%d,%d,%d,%d\r\n", gWIZNETINFO.ip[0], gWIZNETINFO.ip[1], gWIZNETINFO.ip[2], gWIZNETINFO.ip[3], (uint8_t)(local_port >> 8), (uint8_t)(local_port & 0x00ff));
80. send(socket_ctrl, (uint8_t *)dat, strlen((char *)dat));
81. Command.First = f_put;
82.
83. gModeActivePassiveflag = 1;
84. break;
85. }
86. }
87. else if (gMsgBuf[0] == '6')
88. {
89. if (ftpc.dsock_mode == PASSIVE_MODE)
90. {
91. sprintf((char *)dat, "PASV\r\n");
92. send(socket_ctrl, (uint8_t *)dat, strlen((char *)dat));
93. Command.First = f_get;
94. break;
95. }
96. else
97. {
98. wiz_NetInfo gWIZNETINFO;
99. ctlnetwork(CN_GET_NETINFO, (void *)&gWIZNETINFO);
100. sprintf((char *)dat, "PORT %d,%d,%d,%d,%d,%d\r\n", gWIZNETINFO.ip[0], gWIZNETINFO.ip[1], gWIZNETINFO.ip[2], gWIZNETINFO.ip[3], (uint8_t)(local_port >> 8), (uint8_t)(local_port & 0x00ff));
101. send(socket_ctrl, (uint8_t *)dat, strlen((char *)dat));
102. Command.First = f_get;
103.
104. gModeActivePassiveflag = 1;
105. break;
106. }
107. }
108. else if (gMsgBuf[0] == '2')
109. {
110. #if defined(F_FILESYSTEM)
111. scan_files(ftpc.workingdir, dbuf, (int *)&size);
112. printf("\r\n%s\r\n", dbuf);
113. #else
114. if (strncmp(ftpc.workingdir, "/$Recycle.Bin", sizeof("/$Recycle.Bin")) != 0)
115. size = sprintf((char *)dbuf, "drwxr-xr-x 1 ftp ftp 0 Dec 31 2014 $Recycle.Bin\r\n-rwxr-xr-x 1 ftp ftp 512 Dec 31 2014 test.txt\r\n");
116. printf("\r\n%s\r\n", dbuf);
117. #endif
118. gMenuStart = 1;
119. break;
120. }
121. else if (gMsgBuf[0] == '3')
122. {
123. printf("1> ASCII\r\n");
124. printf("2> BINARY\r\n");
125. while (1)
126. {
127. memset(gMsgBuf, 0, sizeof(gMsgBuf));
128. scanf("%s", gMsgBuf);
129. if (gMsgBuf[0] == '1')
130. {
131. sprintf((char *)dat, "TYPE %c\r\n", TransferAscii);
132. ftpc.type = ASCII_TYPE;
133. send(socket_ctrl, (uint8_t *)dat, strlen((char *)dat));
134. break;
135. }
136. else if (gMsgBuf[0] == '2')
137. {
138. sprintf((char *)dat, "TYPE %c\r\n", TransferBinary);
139. ftpc.type = IMAGE_TYPE;
140. send(socket_ctrl, (uint8_t *)dat, strlen((char *)dat));
141. break;
142. }
143. else if (gMsgBuf[0] != 0x00)
144. {
145. printf("\r\nRetry...\r\n");
146. }
147. }
148. break;
149. }
150. else if (gMsgBuf[0] == '4')
151. {
152. printf("1> ACTIVE\r\n");
153. printf("2> PASSIVE\r\n");
154. while (1)
155. {
156. memset(gMsgBuf, 0, sizeof(gMsgBuf));
157. scanf("%s", gMsgBuf);
158. if (gMsgBuf[0] == '1')
159. {
160. ftpc.dsock_mode = ACTIVE_MODE;
161. break;
162. }
163. else if (gMsgBuf[0] == '2')
164. {
165. ftpc.dsock_mode = PASSIVE_MODE;
166. break;
167. }
168. else if (gMsgBuf[0] != 0x00)
169. {
170. printf("\r\nRetry...\r\n");
171. }
172. }
173. gMenuStart = 1;
174. break;
175. }
176. #if defined(F_FILESYSTEM)
177. else if (msg_c == '7')
178. {
179. printf(">del filename?");
180. memset(gMsgBuf, 0, sizeof(gMsgBuf));
181. scanf("%s", gMsgBuf);
182. sprintf((char *)dat, "STOR %s\r\n", gMsgBuf);
183. if (f_unlink((const char *)ftpc.filename) != 0)
184. {
185. printf("\r\nCould not delete.\r\n");
186. }
187. else
188. {
189. printf("\r\nDeleted.\r\n");
190. }
191. gMenuStart = 1;
192. break;
193. }
194. #endif
195. else if (gMsgBuf[0] != 0x00)
196. {
197. printf("\r\nRetry...\r\n");
198. }
199. }
200. }
201. if (gDataSockReady)
202. {
203. gDataSockReady = 0;
204. switch (Command.First)
205. {
206. case f_dir:
207. sprintf((char *)dat, "LIST\r\n");
208. send(socket_ctrl, (uint8_t *)dat, strlen((char *)dat));
209. break;
210. case f_put:
211. printf(">put file name?");
212. memset(gMsgBuf, 0, sizeof(gMsgBuf));
213. scanf("%s", gMsgBuf);
214. sprintf((char *)dat, "STOR %s\r\n", gMsgBuf);
215. send(socket_ctrl, (uint8_t *)dat, strlen((char *)dat));
216. break;
217. case f_get:
218. printf(">get file name?");
219. memset(gMsgBuf, 0, sizeof(gMsgBuf));
220. scanf("%s", gMsgBuf);
221. sprintf((char *)dat, "RETR %s\r\n", gMsgBuf);
222. send(socket_ctrl, (uint8_t *)dat, strlen((char *)dat));
223. break;
224. default:
225. printf("Command.First = default\r\n");
226. break;
227. }
228. }
229. if ((size = getSn_RX_RSR(socket_ctrl)) > 0)
230. { // Don't need to check SOCKERR_BUSY because it doesn't not occur.
231. memset(dbuf, 0, _MAX_SS);
232. if (size > _MAX_SS)
233. size = _MAX_SS - 1;
234. ret = recv(socket_ctrl, dbuf, size);
235. dbuf[ret] = '\0';
236. if (ret != size)
237. {
238. if (ret == SOCK_BUSY)
239. return 0;
240. if (ret < 0)
241. {
242. printf("%d:recv() error:%ld\r\n", socket_ctrl, ret);
243. close(socket_ctrl);
244. return ret;
245. }
246. }
247. printf("Rcvd Command: %s\r\n", dbuf);
248. proc_ftpc((char *)dbuf, size);
249. }
250. break;
251. case SOCK_CLOSE_WAIT:
252. printf("%d:CloseWait\r\n", socket_ctrl);
253. if ((ret = disconnect(socket_ctrl)) != SOCK_OK)
254. return ret;
255. printf("%d:Closed\r\n", socket_ctrl);
256. break;
257. case SOCK_CLOSED:
258. printf("%d:FTPStart\r\n", socket_ctrl);
259. if ((ret = socket(socket_ctrl, Sn_MR_TCP, FTP_destport, 0x0)) != socket_ctrl)
260. {
261. printf("%d:socket() error:%ld\r\n", socket_ctrl, ret);
262. close(socket_ctrl);
263. return ret;
264. }
265. break;
266. case SOCK_INIT:
267. printf("%d:Opened\r\n", socket_ctrl);
268. if ((ret = connect(socket_ctrl, local_ip.cVal, FTP_destport)) != SOCK_OK)
269. {
270. printf("%d:Connect error\r\n", socket_ctrl);
271. return ret;
272. }
273. connect_state_control_ftpc = 0;
274. printf("%d:Connectting...\r\n", socket_ctrl);
275. break;
276. default:
277. break;
278. }
279. switch (getSn_SR(socket_data))
280. {
281. case SOCK_ESTABLISHED:
282. if (!connect_state_data_ftpc)
283. {
284. printf("%d:FTP Data socket Connected\r\n", socket_data);
285. connect_state_data_ftpc = 1;
286. }
287. if (gDataPutGetStart)
288. {
289. switch (Command.Second)
290. {
291. case s_dir:
292. printf("dir waiting...\r\n");
293. if ((size = getSn_RX_RSR(socket_data)) > 0)
294. { // Don't need to check SOCKERR_BUSY because it doesn't not occur.
295. printf("ok\r\n");
296. memset(dbuf, 0, _MAX_SS);
297. if (size > _MAX_SS)
298. size = _MAX_SS - 1;
299. ret = recv(socket_data, dbuf, size);
300. dbuf[ret] = '\0';
301. if (ret != size)
302. {
303. if (ret == SOCK_BUSY)
304. return 0;
305. if (ret < 0)
306. {
307. printf("%d:recv() error:%ld\r\n", socket_ctrl, ret);
308. close(socket_data);
309. return ret;
310. }
311. }
312. printf("Rcvd Data:\n\r%s\n\r", dbuf);
313. gDataPutGetStart = 0;
314. Command.Second = s_nocmd;
315. }
316. break;
317. case s_put:
318. printf("put waiting...\r\n");
319. if (strlen(ftpc.workingdir) == 1)
320. sprintf(ftpc.filename, "/%s", (uint8_t *)gMsgBuf);
321. else
322. sprintf(ftpc.filename, "%s/%s", ftpc.workingdir, (uint8_t *)gMsgBuf);
323. #if defined(F_FILESYSTEM)
324. ftpc.fr = f_open(&(ftpc.fil), (const char *)ftpc.filename, FA_READ);
325. if (ftpc.fr == FR_OK)
326. {
327. remain_filesize = ftpc.fil.fsize;
328. printf("f_open return FR_OK\r\n");
329. do
330. {
331. memset(dbuf, 0, _MAX_SS);
332. if (remain_filesize > _MAX_SS)
333. send_byte = _MAX_SS;
334. else
335. send_byte = remain_filesize;
336. ftpc.fr = f_read(&(ftpc.fil), (void *)dbuf, send_byte, (UINT *)&blocklen);
337. if (ftpc.fr != FR_OK)
338. {
339. break;
340. }
341. printf("#");
342. send(socket_data, dbuf, blocklen);
343. remain_filesize -= blocklen;
344. } while (remain_filesize != 0);
345. printf("\r\nFile read finished\r\n");
346. ftpc.fr = f_close(&(ftpc.fil));
347. }
348. else
349. {
350. printf("File Open Error: %d\r\n", ftpc.fr);
351. ftpc.fr = f_close(&(ftpc.fil));
352. }
353. #else
354. remain_filesize = strlen(ftpc.filename);
355. do
356. {
357. memset(dbuf, 0, _MAX_SS);
358. blocklen = sprintf((char *)dbuf, "%s", ftpc.filename); // Upload file content
359. printf("########## dbuf:%s\r\n", dbuf);
360. send(socket_data, dbuf, blocklen);
361. remain_filesize -= blocklen;
362. } while (remain_filesize != 0);
363. #endif
364. gDataPutGetStart = 0;
365. Command.Second = s_nocmd;
366. disconnect(socket_data);
367. break;
368. case s_get:
369. printf("get waiting...\r\n");
370. if (strlen(ftpc.workingdir) == 1)
371. sprintf(ftpc.filename, "/%s", (uint8_t *)gMsgBuf);
372. else
373. sprintf(ftpc.filename, "%s/%s", ftpc.workingdir, (uint8_t *)gMsgBuf);
374. #if defined(F_FILESYSTEM)
375. ftpc.fr = f_open(&(ftpc.fil), (const char *)ftpc.filename, FA_CREATE_ALWAYS | FA_WRITE);
376. if (ftpc.fr == FR_OK)
377. {
378. printf("f_open return FR_OK\r\n");
379. while (1)
380. {
381. if ((remain_datasize = getSn_RX_RSR(socket_data)) > 0)
382. {
383. while (1)
384. {
385. memset(dbuf, 0, _MAX_SS);
386. if (remain_datasize > _MAX_SS)
387. recv_byte = _MAX_SS;
388. else
389. recv_byte = remain_datasize;
390. ret = recv(socket_data, dbuf, recv_byte);
391. ftpc.fr = f_write(&(ftpc.fil), (const void *)dbuf, (UINT)ret, (UINT *)&blocklen);
392. remain_datasize -= blocklen;
393. if (ftpc.fr != FR_OK)
394. {
395. printf("f_write failed\r\n");
396. break;
397. }
398. if (remain_datasize <= 0)
399. break;
400. }
401. if (ftpc.fr != FR_OK)
402. {
403. printf("f_write failed\r\n");
404. break;
405. }
406. printf("#");
407. }
408. else
409. {
410. if (getSn_SR(socket_data) != SOCK_ESTABLISHED)
411. break;
412. }
413. }
414. printf("\r\nFile write finished\r\n");
415. ftpc.fr = f_close(&(ftpc.fil));
416. gDataPutGetStart = 0;
417. }
418. else
419. {
420. printf("File Open Error: %d\r\n", ftpc.fr);
421. }
422. #else
423. while (1)
424. {
425. if ((remain_datasize = getSn_RX_RSR(socket_data)) > 0)
426. {
427. while (1)
428. {
429. memset(dbuf, 0, _MAX_SS);
430. if (remain_datasize > _MAX_SS)
431. recv_byte = _MAX_SS;
432. else
433. recv_byte = remain_datasize;
434. ret = recv(socket_data, dbuf, recv_byte);
435. printf("########## dbuf:%s\r\n", dbuf);
436. remain_datasize -= ret;
437. if (remain_datasize <= 0)
438. break;
439. }
440. }
441. else
442. {
443. if (getSn_SR(socket_data) != SOCK_ESTABLISHED)
444. break;
445. }
446. }
447. gDataPutGetStart = 0;
448. Command.Second = s_nocmd;
449. #endif
450. break;
451. default:
452. printf("Command.Second = default\r\n");
453. break;
454. }
455. }
456. break;
457. case SOCK_CLOSE_WAIT:
458. printf("%d:CloseWait\r\n", socket_data);
459. if ((size = getSn_RX_RSR(socket_data)) > 0)
460. { // Don't need to check SOCKERR_BUSY because it doesn't not occur.
461. ret = recv(socket_data, dbuf, size);
462. dbuf[ret] = '\0';
463. if (ret != size)
464. {
465. if (ret == SOCK_BUSY)
466. return 0;
467. if (ret < 0)
468. {
469. printf("%d:recv() error:%ld\r\n", socket_ctrl, ret);
470. close(socket_data);
471. return ret;
472. }
473. }
474. printf("Rcvd Data:\n\r%s\n\r", dbuf);
475. }
476. if ((ret = disconnect(socket_data)) != SOCK_OK)
477. return ret;
478. printf("%d:Closed\r\n", socket_data);
479. break;
480. case SOCK_CLOSED:
481. if (ftpc.dsock_state == DATASOCK_READY)
482. {
483. if (ftpc.dsock_mode == PASSIVE_MODE)
484. {
485. printf("%d:FTPDataStart, port : %d\r\n", socket_data, local_port);
486. if ((ret = socket(socket_data, Sn_MR_TCP, local_port, 0x0)) != socket_data)
487. {
488. printf("%d:socket() error:%ld\r\n", socket_data, ret);
489. close(socket_data);
490. return ret;
491. }
492. local_port++;
493. if (local_port > 50000)
494. local_port = 35000;
495. }
496. else
497. {
498. printf("%d:FTPDataStart, port : %d\r\n", socket_data, local_port);
499. if ((ret = socket(socket_data, Sn_MR_TCP, local_port, 0x0)) != socket_data)
500. {
501. printf("%d:socket() error:%ld\r\n", socket_data, ret);
502. close(socket_data);
503. return ret;
504. }
505. local_port++;
506. if (local_port > 50000)
507. local_port = 35000;
508. }
509. ftpc.dsock_state = DATASOCK_START;
510. }
511. break;
512.
513. case SOCK_INIT:
514. printf("%d:Opened\r\n", socket_data);
515. if (ftpc.dsock_mode == ACTIVE_MODE)
516. {
517. if ((ret = listen(socket_data)) != SOCK_OK)
518. {
519. printf("%d:Listen error\r\n", socket_data);
520. return ret;
521. }
522. gDataSockReady = 1;
523. printf("%d:Listen ok\r\n", socket_data);
524. }
525. else
526. {
527. if ((ret = connect(socket_data, remote_ip.cVal, remote_port)) != SOCK_OK)
528. {
529. printf("%d:Connect error\r\n", socket_data);
530. return ret;
531. }
532. gDataSockReady = 1;
533. }
534. connect_state_data_ftpc = 0;
535. break;
536. default:
537. break;
538. }
539. return 0;
540. }
In this function, two TCP state machines will be executed separately. One is for FTP control, and the other is for FTP data transmission. The FTP data transmission state machine will only be activated when data transmission is required (uploading or downloading files).
First, we see the FTP control state machine. The general process is as shown in the following figure:
When the user selects different options in the option menu, the system will send corresponding operation instructions based on the selected option. These operation instructions will be sent to the server, and then the server will return the corresponding response content. In the proc_ftpc() function, the program will determine whether the operation is successful based on the response code returned by the server, and execute the next step according to the specific situation of the response code. Once the corresponding operation is completed, the program will automatically return to the option menu so that the user can continue with the subsequent operations.
9 Run results
After the burning routine is executed, the PHY link is first detected, then the network address is obtained through DHCP and the network address information is printed out. The FTP connection information is also printed, and prompts are given for inputting information for connection, as shown in the following figure:
The FileZilla Server Interface is the graphical user interface (GUI) of FileZilla Server, used for managing and configuring FileZilla Server. FileZilla Server is an open-source, cross-platform FTP and FTP over TLS (FTPS) server, often used for file sharing and data transmission. Download link: Server - FileZilla Chinese Website. After downloading and installing, open it.
Step 1: Set up the server and create an account (username: wiznet, password: 123456)
Step 2: Create a shared folder for file operations on both the client and the server.
Step 3: On the Serial Port Assistant interface, according to the serial port message prompt "Rcvd Command: 220-FileZilla Server ????????? 0.9.60 beta", first enter the username, then enter the password (note: the content to be sent should end with a carriage return and line feed character), and then the serial port will send 6 options
Step 4: We select 6, and then obtain the file from the server.
Step 5: Next, enter the name of the file you want to obtain. As shown in the figure, the file content has been successfully retrieved.
The other operations are similar. Therefore, we won't go into detailed explanations for each one here.
10 Summary
This article explains how to implement the client mode of the FTP protocol on the W55MH32 chip. Through practical examples, it demonstrates the process of accessing the FTP server and downloading files using this client mode, covering key steps such as initializing the FTP client mode, running related functions in the main loop to interact with the server, etc. The article details the concept, characteristics, application scenarios, workflow, active and passive modes, client functions, and message parsing of the FTP protocol, helping readers understand its practical application value in file transfer.
The next article will focus on the WOL (Wake-on-LAN) network wake-up function, explaining its core principle and application in network device management, and also discussing how to implement the WOL function on the W55MH32 chip. Stay tuned!
WIZnet is a non-fabrication 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).