)摘自【正點(diǎn)原子】領(lǐng)航者 ZYNQ 之嵌入式開發(fā)指南
2)實(shí)驗(yàn)平臺:正點(diǎn)原子領(lǐng)航者ZYNQ開發(fā)板
3)平臺購買地址:https://item.taobao.com/item.htm?&id=606160108761
4)全套實(shí)驗(yàn)源碼+手冊+視頻下載:http://www.openedv.com/docs/boards/fpga/zdyz_linhanz.html
5)對正點(diǎn)原子FPGA感興趣的同學(xué)可以加群討論:876744900
6)關(guān)注正點(diǎn)原子公眾號,獲取最新資料
第三十五章基于lwip的tftp server實(shí)驗(yàn)
文件傳輸是網(wǎng)絡(luò)環(huán)境中的一項(xiàng)基本應(yīng)用,其作用是將一臺電子設(shè)備中的文件傳輸?shù)搅硪慌_可能相距很遠(yuǎn)的電子設(shè)備中。TFTP作為TCP/IP協(xié)議族中的一個用來在客戶機(jī)與服務(wù)器之間進(jìn)行文件傳輸?shù)膮f(xié)議,常用于無盤工作站、路由器以及遠(yuǎn)程測控設(shè)備從主機(jī)上獲取引導(dǎo)配置文件,實(shí)現(xiàn)遠(yuǎn)程升級。由于TFTP簡單且易實(shí)現(xiàn),本實(shí)驗(yàn)我們使用lwip協(xié)議棧實(shí)現(xiàn)TFTP Server的功能。本章包括以下幾個部分:
3535.1簡介
35.2實(shí)驗(yàn)任務(wù)
35.3硬件設(shè)計(jì)
35.4軟件設(shè)計(jì)
35.5下載驗(yàn)證
35.1簡介
一、TFTP簡介(基于RFC1350版本)
簡單文件傳輸協(xié)議TFTP (Trivial File Transfer Protocol) 是TCP/IP協(xié)議族中的一個用來在客戶機(jī)與服務(wù)器之間進(jìn)行簡單文件傳輸,基于UDP實(shí)現(xiàn)的應(yīng)用層協(xié)議,提供不復(fù)雜、開銷不大的文件傳輸服務(wù),端口號為 69。為了保證文件可靠傳輸TFTP有自己的差錯改正措施。TFTP 只支持文件傳輸、不支持交互、沒有龐大的命令集,也沒有目錄列表功能,以及不能對用戶進(jìn)行身份鑒別。
與常用的文件傳送協(xié)議 FTP (File Transfer Protocol) 相比,F(xiàn)TP基于TCP協(xié)議,提供交互式的訪問,允許客戶指明文件的類型與格式、允許執(zhí)行對目錄和文件的訪問,并且可以完成特定類型的目錄操作以及需要進(jìn)行身份驗(yàn)證。
可以說FTP是完整的、面向會話、常規(guī)用途的文件傳輸協(xié)議,而TFTP相當(dāng)于用作特殊目的簡化版的FTP。
TFTP的主要優(yōu)點(diǎn)有兩個。
第一,TFTP可用于UDP環(huán)境。例如,當(dāng)需要將程序或文件同時(shí)向許多機(jī)器下載時(shí)就往往需要使用TFTP。
第二,TFTP代碼所占的內(nèi)存較小。這對較小的計(jì)算機(jī)或某些特殊用途的設(shè)備(如無盤工作站等)是很重要的。這些設(shè)備不需要硬盤,只需要固化了TFTP、UDP和IP的小容量只讀存儲器即可。當(dāng)接通電源后,設(shè)備執(zhí)行只讀存儲器中的代碼,在網(wǎng)絡(luò)上廣播一個TFTP請求。網(wǎng)絡(luò)上的TFTP服務(wù)器就發(fā)送響應(yīng),其中包括可執(zhí)行二進(jìn)制程序。設(shè)備收到此文件后將其放入內(nèi)存,然后開始運(yùn)行程序。這種方式增加了靈活性,也減少了開銷。
TFTP的主要特點(diǎn)如下:
(1)每次傳送的數(shù)據(jù)報(bào)文中有512字節(jié)的數(shù)據(jù),但最后一次可不足512字節(jié)。
(2)數(shù)據(jù)報(bào)文按序編號,從1開始。
(3)支持ASCII碼或二進(jìn)制傳送。
(4)可對文件進(jìn)行讀或?qū)憽?br>(5)使用很簡單的首部。
(6)實(shí)現(xiàn)簡單而不是高的系統(tǒng)吞吐量
二、TFTP的五種報(bào)文
TFTP的報(bào)文格式如圖 35.1.1所示,可以看到TFTP有五種報(bào)文,每種報(bào)文有不同的操作碼,這五種報(bào)文分別是:RRQ、WRQ、DATA、ACK和ERROR報(bào)文。下面我們簡單的介紹下這五種報(bào)文。
RRQ/WRQ報(bào)文
模式字段中,包含兩種字符串中的一種,"netascii"表示ASCII文件,"octet"表示二進(jìn)制文件。對于RRQ,客戶向TFTP服務(wù)器發(fā)送讀請求后,服務(wù)器返回一個塊編號為1的DATA報(bào)文。而對于WRQ,客戶向TFTP服務(wù)器發(fā)送寫請求后,服務(wù)器返回的是塊編號為1的ACK報(bào)文。總之,不管是RRQ還是WRQ,接收DATA數(shù)據(jù)的一方發(fā)送ACK確認(rèn),而發(fā)送DATA數(shù)據(jù)的一方只負(fù)責(zé)發(fā)送數(shù)據(jù)。
圖 35.1.1 TFTP報(bào)文格式
a)DATA報(bào)文
發(fā)送方用于傳送數(shù)據(jù)塊。所有的塊都用數(shù)字順序編碼,從1開始。在所有的DATA報(bào)文中,這個塊必須準(zhǔn)確地等于512Byte,但最后一個塊可以小于或等于512Byte。當(dāng)發(fā)送的DATA報(bào)文中數(shù)據(jù)部分的長度小于512Byte,表示DATA報(bào)文發(fā)送完畢,所以小于數(shù)據(jù)部分512Byte的DATA數(shù)據(jù)報(bào)可以作為文件結(jié)束的標(biāo)志。特殊的情況是,當(dāng)文件中的數(shù)據(jù)正好是512Byte的整數(shù)倍時(shí),那么發(fā)送端必須再發(fā)送一個具有數(shù)據(jù)部分為0Byte的額外的DATA數(shù)據(jù)塊以表示傳輸?shù)慕Y(jié)束。數(shù)據(jù)可以采用ASCII碼或二進(jìn)制來傳送。
b)ACK報(bào)文
塊號表示它所收到的塊號(不是下一個期待的塊號,這與TCP中的ACK序號不同)。特殊情況是,當(dāng)客戶向服務(wù)器發(fā)送一個WRQ請求后,服務(wù)器返回給客戶的是一個塊號為0的ACK報(bào)文,表示服務(wù)器已經(jīng)準(zhǔn)備好了接收來自客戶的數(shù)據(jù)報(bào)。
c)EEROR報(bào)文(差錯報(bào)文)
ERROR報(bào)文既可以由客戶發(fā)送,也可以由服務(wù)器發(fā)送,當(dāng)一條連接(如讀連接或?qū)戇B接)不能建立或在數(shù)據(jù)傳輸中出現(xiàn)問題時(shí)使用。差錯碼定義了差錯的類型,差錯信息是一個可變字節(jié),包含原文中的差錯數(shù)據(jù)。
從上面的報(bào)文格式中可以看出,TFTP報(bào)文沒有差錯檢驗(yàn)和字段,所以接收端檢驗(yàn)數(shù)據(jù)是否出現(xiàn)差錯的唯一方法是通過該TFTP數(shù)據(jù)報(bào)的UDP首部中的檢驗(yàn)和字段。
三、TFTP傳輸過程
以TFTP客戶端向 TFTP 服務(wù)器發(fā)送寫請求為例,說明整個過程。
1)服務(wù)器使用默認(rèn)端口號69被動打開連接;
2)客戶主動打開連接,向服務(wù)器進(jìn)程發(fā)送WRQ報(bào)文,報(bào)文中包含寫入文件的文件名;
3)TFTP服務(wù)器進(jìn)程選擇一個新的端口和TFTP客戶進(jìn)程進(jìn)行通信,并向TFTP客戶進(jìn)程發(fā)送塊編號為0的的ACK報(bào)文;
4)客戶端收到服務(wù)器的ACK報(bào)文后發(fā)送DATA報(bào)文,數(shù)據(jù)段為512Byte,少于512Byte表明是文件的最后的數(shù)據(jù),塊編號逐次遞增;
5)TFTP服務(wù)器校驗(yàn)收到的DATA報(bào)文的塊編號,如果校驗(yàn)正確則將數(shù)據(jù)寫入文件,并發(fā)送ACK報(bào)文表明已接收到數(shù)據(jù),ACK報(bào)文的塊編號為本次接收的DATA報(bào)文的塊編號。另外還判斷數(shù)據(jù)段長度是否小于512 Byte,小于則表明文件傳輸完成,關(guān)閉連接,如果等于512Byte,則重復(fù)步驟4-5,直到所有請求的數(shù)據(jù)發(fā)送完畢。
從上面的傳輸過程可以看出,TFTP 是一種類似于停止等待協(xié)議(不是真正的停止等待協(xié)議,在停止等待協(xié)議中,接收方發(fā)送的 ack 表示期望收到的下一個分組,而在 TFTP 的 ACK 報(bào)文中,ACK的塊號表示的是本次成功收到的數(shù)據(jù)塊,而不是下一個期望的下一個數(shù)據(jù)塊)。TFTP 客戶端只有收到服務(wù)器的確認(rèn)報(bào)文ACK后才會接著向服務(wù)器發(fā)送新的數(shù)據(jù)。
另外需要注意的是TFTP 協(xié)議中,用于讀文件的連接和用于寫文件的連接的建立方式不同:建立讀連接的時(shí)候,客戶首先向服務(wù)器發(fā)送 RRQ 讀報(bào)文,服務(wù)器收到該報(bào)文后,直接發(fā)回給該客戶 DATA 報(bào)文,并且包含第一個數(shù)據(jù)塊(塊號為 1)。而建立寫連接的時(shí)候,客戶首先先服務(wù)器發(fā)送 WRQ 寫報(bào)文,服務(wù)器收到該報(bào)文后,則發(fā)回給客戶 ACK 報(bào)文,使用的塊號為 0;當(dāng)然上面兩種情況如果遇到請求報(bào)文出錯時(shí),均會發(fā)回 ERROR 報(bào)文作為響應(yīng)。
35.2實(shí)驗(yàn)任務(wù)
本章的實(shí)驗(yàn)任務(wù)是使用LWIP協(xié)議棧搭建TFTP服務(wù)器,PC電腦上的客戶端可以從TFTP服務(wù)器讀取文件也可向TFTP服務(wù)器寫入文件,文件存放在SD卡中。
35.3硬件設(shè)計(jì)
根據(jù)實(shí)驗(yàn)任務(wù)我們可以畫出本次實(shí)驗(yàn)的系統(tǒng)框圖,如下圖所示:
圖 35.3.1 系統(tǒng)框圖
在圖 5.3.1中,UART用于打印程序相關(guān)的信息,LWIP通過以太網(wǎng)傳輸數(shù)據(jù),SD用于存放文件,包括服務(wù)器創(chuàng)建的文件和客戶端寫入的文件。
step1:創(chuàng)建Vivado工程
本次實(shí)驗(yàn)的硬件設(shè)計(jì)可以在《LWIP echo server》實(shí)驗(yàn)的基礎(chǔ)上添加SD卡。
1-1 我們先打開《LWIP echo server》實(shí)驗(yàn)的Vivado工程,打開后將工程另存為 “l(fā)wip_tftp_server”工程,然后點(diǎn)擊“OK”按鈕。
step2:使用IP Integrator創(chuàng)建Processing System
2-1 在Vivado界面左側(cè)的Flow Navigator中,點(diǎn)擊IP INTEGRATOR下的Open Block Design以打開Diagram窗口。
2-2 在打開的下圖Diagram窗口,雙擊打開ZYNQ7 Processing System重定義窗口。
圖 35.3.2 重定義ZYNQ7 Processing System
2-3 在下圖所示的重定義窗口,如同《SD卡讀寫TXT文本實(shí)驗(yàn)》那樣配置SD卡。點(diǎn)擊左側(cè)的MIO Configuration,在右側(cè)的界面中展開“I/O Peripherals”,勾選“SD 0”,在“IO”列選擇SD 0的IO為“MIO40…45”,如下圖所示。
圖 35.3.3 PS以太網(wǎng)接口配置界面
2-4 由于不需要添加其它IP,按Ctrl+S快捷鍵保存Diagram。此時(shí)我們的第二步完成,進(jìn)入第三步
step3:生成頂層HDL
在sources面板中,右鍵點(diǎn)擊Block Design設(shè)計(jì)文件“system.bd”,然后依次執(zhí)行“Generate Output Products”和“Create HDL Wrapper”。
step4:生成Bitstream文件并導(dǎo)出到SDK
由于本實(shí)驗(yàn)未用到PL部分,所以無需生成Bitstream文件,只需導(dǎo)出到SDK即可。如果使用到PL,則需要添加引腳約束以及對該系統(tǒng)進(jìn)行綜合、實(shí)現(xiàn)并生成Bitstream文件。
4-1 導(dǎo)出硬件。
在菜單欄中選擇 File > Export > Export hardware。
并在彈出的對話框中,取消勾選“Include bitstream”,直接點(diǎn)擊“OK”按鈕。
因?yàn)槭窃谇耙还こ痰幕A(chǔ)上建立的,還保留著前一工程的結(jié)果,所以會彈出“Module Already Exported”對話框,我們點(diǎn)擊“Yes”按鈕。
4-2 硬件導(dǎo)出完成后,選擇菜單File->Launch SDK,啟動SDK開發(fā)環(huán)境。
35.4軟件設(shè)計(jì)
下面步驟操作比較麻煩,實(shí)際意義也不大,可以直接使用我們提供的例程里的SDK軟件工程。
此處我們刪除《LWIP echo server》實(shí)驗(yàn)的應(yīng)用工程,保留bsp工程。下面我們開始第五步——創(chuàng)建應(yīng)用工程。下面我們開始第五步——創(chuàng)建應(yīng)用工程
step5:在SDK中創(chuàng)建應(yīng)用工程
5-1在菜單欄中選擇“File->New->Application Project”,
在彈出的界面中,輸入工程名“l(fā)wip_tftp_server”,然后選擇“Next >”,在下一界面選擇“Empty Application”,然后點(diǎn)擊“Finish”按鈕。
5-2 在Project Explorer中,鼠標(biāo)右鍵點(diǎn)擊“l(fā)wip_tftp_server _bsp”,在彈出的菜單中選擇“Board Support Package Settings”,如下圖所示:
彈出對BSP的設(shè)置界面,勾選“l(fā)wip202”和“xilffs”以啟用lwip和文件系統(tǒng),如圖 35.4.1所示。
如果沒有開啟DHCP服務(wù)可以開啟DHCP服務(wù),點(diǎn)擊standalone下的lwip202,在右側(cè)界面中到“dhcp_options”,將其下的兩個選項(xiàng)的“Value”設(shè)置為“true”,如圖 35.4.2所示。
圖 35.4.1 BSP的設(shè)置界面
圖 35.4.2 開啟DHCP
5-3 由于Xilinx提供的lwip例程里有TFTP server的源代碼,所以我們無需自己手動編寫,直接添加即可。
雙擊打開“l(fā)wip_tftp_server”目錄下的system.mss文件。在system.mss文件的底部單擊“Import Example”,如下圖所示。
圖 35.4.3 Import lwip Example
5-4 在彈出的下圖所示界面中,點(diǎn)擊下方的“Examples Directory”。
圖 35.4.4 platform_config.h文件內(nèi)容
5-5 打開例程所在文件的目錄,里面有Xilinx關(guān)于lwip的全部例程源文件。我們選擇本次實(shí)驗(yàn)需要的源文件,如圖 35.4.6所示,并單擊鼠標(biāo)右鍵選擇復(fù)制。復(fù)制完成后,在打開的圖 35.4.5界面中,點(diǎn)擊“Cancel”退出。
圖 35.4.6 例程所在文件的目錄
5-6 單擊SDK軟件的lwip_tftp_server/src目錄,按下粘貼快捷鍵“Ctrl-v”,將復(fù)制的文件粘貼到該src目錄下,如下圖所示。
圖 35.4.7 src目錄
5-7 為了方便分析,我們將剛才復(fù)制到src目錄的源文件重命名,主要是刪除不需要的前綴,其中“l(fā)wip_example_tftpserver_common.h”改為“l(fā)wip_tftp_server.h”,如下圖所示:
圖 35.4.8 刪除不相關(guān)文件后的src文件夾內(nèi)容
5-8 修復(fù)錯誤。
由于重命名了“l(fā)wip_example_tftpserver_common.h”,所以需要將lwip_tftp_server.c源文件的 #include "lwip_tftpserver_common.h"修改為#include "lwip_tftp_server.h",如下圖所示:
圖 35.4.9 修改為#include "lwip_tftp_server.h"
此處為了方便顯示,將其注釋,實(shí)際在文件內(nèi)直接修改第34行即可。
打開platform_fs.c源文件,添加BYTE work[FF_MAX_SS](第9行),修改f_mkfs函數(shù)的調(diào)用,第15行,修改后的內(nèi)容如下:
該文件在初始化平臺時(shí)由init_platform函數(shù)調(diào)用,用于掛載SD卡,掛載不成功就將SD卡格式化成FAT32,格式化成功后再嘗試掛載。
5-9 現(xiàn)在我們打開main.c文件,為了方便分析源代碼,在main.c文件中將帶有下圖箭頭所指的預(yù)編譯指令刪除。
圖 35.4.10 刪除不需要的預(yù)編譯指令
刪除不適用的預(yù)編譯指令后的main.c代碼與我們《lwip echo server實(shí)驗(yàn)》的main.c代碼基本相同,區(qū)別在于本次TFTP server實(shí)驗(yàn)沒有使用IPv6,所以沒有IPv6的預(yù)編譯指令,其他完全相同,main.c代碼講解見《lwip echo server實(shí)驗(yàn)》。
5-10本實(shí)驗(yàn)可以說是在《lwip echo server實(shí)驗(yàn)》的基礎(chǔ)上增加了文件系統(tǒng),然后將Echo server的實(shí)現(xiàn)文件echo.c文件改寫成了TFTP Server的實(shí)現(xiàn)文件。因而本實(shí)驗(yàn)的主要代碼是TFTP Server的實(shí)現(xiàn),該實(shí)現(xiàn)在lwip_tftp_server.h和lwip_tftp_server.c中,由于這兩個文件的總代碼有近500行,因此我們挑選部分代碼進(jìn)行講解。此處以客戶端寫文件為例講解lwip_tftp_server.c中的寫文件實(shí)現(xiàn)源碼。講解以函數(shù)調(diào)用順序進(jìn)行。
首先我們看main函數(shù)中調(diào)用的start_application函數(shù),該函數(shù)實(shí)現(xiàn)如下:
可以看到該函數(shù)首先通過調(diào)用tftp_create_test_file函數(shù)創(chuàng)建了測試文件,用于tftp客戶端讀取tftp服務(wù)器的文件數(shù)據(jù),測試文件名為sample#.txt,其中“#”為數(shù)字1、2、3中的任一值,其文件內(nèi)容為“----- This is a test file for TFTP server application -----”。如果不執(zhí)行客戶端的讀取文件請求,可刪除該函數(shù)的調(diào)用及其實(shí)現(xiàn)。
由于TFTP基于UDP協(xié)議,從start_application函數(shù)可以看到lwip中使用UDP協(xié)議很簡單。首先通過udp_new函數(shù)創(chuàng)建一個新的UDP PCB,然后調(diào)用udp_bind函數(shù)綁定端口號,IP_ADDR_ANY表明為任意本地地址,TFTP_PORT是在lwip_tftp_server.h宏定義的端口號,其值為69,即TFTP的默認(rèn)端口。最后調(diào)用udp_recv函數(shù)設(shè)置接收回調(diào)函數(shù)就完成了UDP服務(wù)的創(chuàng)建,服務(wù)端的功能幾TFTP協(xié)議由回調(diào)函數(shù)實(shí)現(xiàn)。回調(diào)函數(shù)代碼如下:
當(dāng)TFTP客戶端發(fā)起寫入或讀取文件的請求后,lwip協(xié)議棧調(diào)用回調(diào)函數(shù)tftp_server_recv_cb。該回調(diào)函數(shù)通過tftp_get_opcode宏獲取客戶端發(fā)送報(bào)文的操作碼,不同的操作碼執(zhí)行該函數(shù)switch分支中的不同的case,如對于寫入文件請求,則執(zhí)行“case TFTP_WRQ”分支語句,該分支語句調(diào)用TFTP處理寫文件請求函數(shù)tftp_process_write,該函數(shù)實(shí)現(xiàn)如下:
該函數(shù)首先在文件系統(tǒng)中創(chuàng)建一個文件,文件名為客戶端寫入的文件名,然后為新創(chuàng)建的UDP PCB設(shè)置接收回調(diào)函數(shù),用于處理后面接收客戶端傳入的文件,最后發(fā)送塊編號為0的ACK報(bào)文以應(yīng)答客戶端啟動傳輸。TFTP寫入請求的接收回調(diào)函數(shù)實(shí)現(xiàn)如下:
從該回調(diào)函數(shù)可以看到,TFTP服務(wù)端對客戶端發(fā)送的數(shù)據(jù)報(bào)文的塊編號進(jìn)行校驗(yàn),如果不是我們期望的塊編號就重發(fā)上一次發(fā)送的ACK報(bào)文,如果是期望的塊編號,就將數(shù)據(jù)寫入文件中,然后遞增塊編號,并發(fā)送ACK報(bào)文給客戶端以確認(rèn)收到數(shù)據(jù)。
在該函數(shù)的最后判斷接收到的數(shù)據(jù)段長度是否小于指定的字節(jié)數(shù)TFTP_DATA_PACKET_MSG_LEN,如果是,則表明已經(jīng)接收了整個文件,因此可以結(jié)束連接。TFTP_DATA_PACKET_MSG_LEN在lwip_tftp_server.h宏定義為512。
以上大概的講解了TFTP Server接收客戶端寫入文件的實(shí)現(xiàn)。下面我們進(jìn)行實(shí)際操作,看看TFTP客戶端是否能向服務(wù)器寫入文件。
35.5下載驗(yàn)證
首先我們將下載器與領(lǐng)航者底板上的JTAG接口連接,下載器另外一端與電腦連接。然后使用Mini USB連接線將USB UART接口與電腦連接,用于串口通信。使用網(wǎng)線一端連接領(lǐng)航者開發(fā)板的以太網(wǎng)接口,另一端與電腦或路由器連接。連接完成后,在開發(fā)板上插入SD 卡或者插入帶卡套(適配器)的 TF 卡(SD 卡插槽位于開發(fā)板背面)。最后連接開發(fā)板的電源,并打開電源開關(guān)。如下圖所示:
圖 35.5.1領(lǐng)航者ZYNQ開發(fā)板實(shí)物圖
現(xiàn)在進(jìn)入最后一步。
step6:板級驗(yàn)證
6-1 在SDK軟件的下方的SDK Terminal窗口中點(diǎn)擊右上角的加號連接串口。
6-2 下載程序。下載完成后,可以看到串口打印的結(jié)果如下:
圖 35.5.2 顯示打印結(jié)果
其中“File system initialization successful”表明SD卡可以正常工作。打印的最后一句表明了該實(shí)驗(yàn)如何使用。由于是TFTP服務(wù)器實(shí)驗(yàn),所以我們需要TFTP客戶端,可以從網(wǎng)上下載,也可以使用Windows系統(tǒng)的CMD命令行界面,如果開啟了TFTP客戶端,開啟方法見步驟6-6。
6-3 下面我們先創(chuàng)建一個文件用來傳輸?shù)絋FTP服務(wù)器。文件存放位置任意,文件內(nèi)容任意。
我們在Vivado工程目錄新建一個名為“test”的文件夾,里面新建一個名為testfile.txt的文件,文件內(nèi)容為“這只是一個測試文件。”,如下圖所示:
圖 35.5.3 新建一個名為test_file.txt的文件
6-4 我們打開電腦的CMD(按win+r鍵后輸入cmd),然后輸入命令“cd /D F:\ZYNQ\Embedded_System\lwip_tftp_server\test”切換到 “F:\ZYNQ\Embedded_System\lwip_tftp_server\test”目錄下,如下圖所示:
圖35.5.4 切換到上傳文件所在的目錄
然后輸入“tftp -i 192.168.1.10 PUT testfile.txt”命令,回車,會顯示傳輸成功字樣,如下圖所示:
圖 35.5.5 進(jìn)行tftp連接
此時(shí)SDK串口終端也會打印如下信息:
圖 35.5.6 串口終端打印寫入完成信息
如果回車后出現(xiàn)像下圖所示界面所示“tftp不是內(nèi)部或外部命令,也不是可運(yùn)行的程序或批處理文件”,則表明未開啟Windows的tftp客戶端功能,開啟方式見6-5。
圖 35.5.7 未啟用tftp客戶端時(shí)的界面
向服務(wù)器寫入文件剛才測試完成了,現(xiàn)在測試從服務(wù)器端讀取文件,可以讀取剛才寫入的文件,也可以讀取服務(wù)器程序創(chuàng)建的測試文件。下面我們以讀取服務(wù)器程序創(chuàng)建的測試文件為例,進(jìn)行讀取文件測試。
在CMD中輸入“tftp -i 192.168.1.10 GET sample1.txt”命令,然后回車,會顯示傳輸成功字樣,如下圖所示:
圖 35.5.8 輸入讀取文件命令
此時(shí)SDK串口終端也會打印如下信息:
圖 35.5.9 讀取成功
此時(shí)我們打開test文件夾,會看到其中新增了sample1.txt,雙擊打開,其內(nèi)容如下:
圖 35.5.10 讀取的sample1.txt文件
可以看到讀取文件測試成功。現(xiàn)在我們把SD卡插到電腦上,查看其內(nèi)容如下:
圖 35.5.11 SD卡上的文件
可以看到客戶端上傳給TFTP服務(wù)器的文件確實(shí)寫到SD卡中。
6-5 下面我們介紹一下如何開啟Windows的tftp客戶端功能。在Win10或Win7系統(tǒng)中,按“Win+r”快捷鍵后,在下圖所示界面中輸入“control”。
圖 35.5.12 打開控制面板界面
進(jìn)入下圖所示控制面板界面,將查看方式設(shè)置為“類別”,單擊“程序”下的“卸載程序”,如下圖所示:
圖 35.5.13 點(diǎn)擊進(jìn)入“程序和功能”界面
在彈出的界面中,單擊“啟用或關(guān)閉Windows功能”,如下圖所示:
圖 35.5.14 點(diǎn)擊“啟用或關(guān)閉Windows功能”
在彈出的“Windows功能”界面中,找到“Tftp Client”,并勾選,如下圖所示:
圖 35.5.15 勾選tftp client
單擊確定后,如果出現(xiàn)“Windows需要重啟電腦才能完成安裝所請求的更改”字樣,重新啟動電腦即可。現(xiàn)在 Windows的tftp客戶端服務(wù)已啟用。
至此,本實(shí)驗(yàn)完成。
1)摘自【正點(diǎn)原子】領(lǐng)航者 ZYNQ 之嵌入式開發(fā)指南
2)實(shí)驗(yàn)平臺:正點(diǎn)原子領(lǐng)航者ZYNQ開發(fā)板
3)平臺購買地址:https://item.taobao.com/item.htm?&id=606160108761
4)全套實(shí)驗(yàn)源碼+手冊+視頻下載:http://www.openedv.com/docs/boards/fpga/zdyz_linhanz.html
5)對正點(diǎn)原子FPGA感興趣的同學(xué)可以加群討論:876744900
6)關(guān)注正點(diǎn)原子公眾號,獲取最新資料
第三十五章基于lwip的tftp server實(shí)驗(yàn)
文件傳輸是網(wǎng)絡(luò)環(huán)境中的一項(xiàng)基本應(yīng)用,其作用是將一臺電子設(shè)備中的文件傳輸?shù)搅硪慌_可能相距很遠(yuǎn)的電子設(shè)備中。TFTP作為TCP/IP協(xié)議族中的一個用來在客戶機(jī)與服務(wù)器之間進(jìn)行文件傳輸?shù)膮f(xié)議,常用于無盤工作站、路由器以及遠(yuǎn)程測控設(shè)備從主機(jī)上獲取引導(dǎo)配置文件,實(shí)現(xiàn)遠(yuǎn)程升級。由于TFTP簡單且易實(shí)現(xiàn),本實(shí)驗(yàn)我們使用lwip協(xié)議棧實(shí)現(xiàn)TFTP Server的功能。本章包括以下幾個部分:
3535.1簡介
35.2實(shí)驗(yàn)任務(wù)
35.3硬件設(shè)計(jì)
35.4軟件設(shè)計(jì)
35.5下載驗(yàn)證
35.1簡介
一、TFTP簡介(基于RFC1350版本)
簡單文件傳輸協(xié)議TFTP (Trivial File Transfer Protocol) 是TCP/IP協(xié)議族中的一個用來在客戶機(jī)與服務(wù)器之間進(jìn)行簡單文件傳輸,基于UDP實(shí)現(xiàn)的應(yīng)用層協(xié)議,提供不復(fù)雜、開銷不大的文件傳輸服務(wù),端口號為 69。為了保證文件可靠傳輸TFTP有自己的差錯改正措施。TFTP 只支持文件傳輸、不支持交互、沒有龐大的命令集,也沒有目錄列表功能,以及不能對用戶進(jìn)行身份鑒別。
與常用的文件傳送協(xié)議 FTP (File Transfer Protocol) 相比,F(xiàn)TP基于TCP協(xié)議,提供交互式的訪問,允許客戶指明文件的類型與格式、允許執(zhí)行對目錄和文件的訪問,并且可以完成特定類型的目錄操作以及需要進(jìn)行身份驗(yàn)證。
可以說FTP是完整的、面向會話、常規(guī)用途的文件傳輸協(xié)議,而TFTP相當(dāng)于用作特殊目的簡化版的FTP。
TFTP的主要優(yōu)點(diǎn)有兩個。
第一,TFTP可用于UDP環(huán)境。例如,當(dāng)需要將程序或文件同時(shí)向許多機(jī)器下載時(shí)就往往需要使用TFTP。
第二,TFTP代碼所占的內(nèi)存較小。這對較小的計(jì)算機(jī)或某些特殊用途的設(shè)備(如無盤工作站等)是很重要的。這些設(shè)備不需要硬盤,只需要固化了TFTP、UDP和IP的小容量只讀存儲器即可。當(dāng)接通電源后,設(shè)備執(zhí)行只讀存儲器中的代碼,在網(wǎng)絡(luò)上廣播一個TFTP請求。網(wǎng)絡(luò)上的TFTP服務(wù)器就發(fā)送響應(yīng),其中包括可執(zhí)行二進(jìn)制程序。設(shè)備收到此文件后將其放入內(nèi)存,然后開始運(yùn)行程序。這種方式增加了靈活性,也減少了開銷。
TFTP的主要特點(diǎn)如下:
(1)每次傳送的數(shù)據(jù)報(bào)文中有512字節(jié)的數(shù)據(jù),但最后一次可不足512字節(jié)。
(2)數(shù)據(jù)報(bào)文按序編號,從1開始。
(3)支持ASCII碼或二進(jìn)制傳送。
(4)可對文件進(jìn)行讀或?qū)憽?br>(5)使用很簡單的首部。
(6)實(shí)現(xiàn)簡單而不是高的系統(tǒng)吞吐量
二、TFTP的五種報(bào)文
TFTP的報(bào)文格式如圖 35.1.1所示,可以看到TFTP有五種報(bào)文,每種報(bào)文有不同的操作碼,這五種報(bào)文分別是:RRQ、WRQ、DATA、ACK和ERROR報(bào)文。下面我們簡單的介紹下這五種報(bào)文。
RRQ/WRQ報(bào)文
模式字段中,包含兩種字符串中的一種,"netascii"表示ASCII文件,"octet"表示二進(jìn)制文件。對于RRQ,客戶向TFTP服務(wù)器發(fā)送讀請求后,服務(wù)器返回一個塊編號為1的DATA報(bào)文。而對于WRQ,客戶向TFTP服務(wù)器發(fā)送寫請求后,服務(wù)器返回的是塊編號為1的ACK報(bào)文。總之,不管是RRQ還是WRQ,接收DATA數(shù)據(jù)的一方發(fā)送ACK確認(rèn),而發(fā)送DATA數(shù)據(jù)的一方只負(fù)責(zé)發(fā)送數(shù)據(jù)。
圖 35.1.1 TFTP報(bào)文格式
a)DATA報(bào)文
發(fā)送方用于傳送數(shù)據(jù)塊。所有的塊都用數(shù)字順序編碼,從1開始。在所有的DATA報(bào)文中,這個塊必須準(zhǔn)確地等于512Byte,但最后一個塊可以小于或等于512Byte。當(dāng)發(fā)送的DATA報(bào)文中數(shù)據(jù)部分的長度小于512Byte,表示DATA報(bào)文發(fā)送完畢,所以小于數(shù)據(jù)部分512Byte的DATA數(shù)據(jù)報(bào)可以作為文件結(jié)束的標(biāo)志。特殊的情況是,當(dāng)文件中的數(shù)據(jù)正好是512Byte的整數(shù)倍時(shí),那么發(fā)送端必須再發(fā)送一個具有數(shù)據(jù)部分為0Byte的額外的DATA數(shù)據(jù)塊以表示傳輸?shù)慕Y(jié)束。數(shù)據(jù)可以采用ASCII碼或二進(jìn)制來傳送。
b)ACK報(bào)文
塊號表示它所收到的塊號(不是下一個期待的塊號,這與TCP中的ACK序號不同)。特殊情況是,當(dāng)客戶向服務(wù)器發(fā)送一個WRQ請求后,服務(wù)器返回給客戶的是一個塊號為0的ACK報(bào)文,表示服務(wù)器已經(jīng)準(zhǔn)備好了接收來自客戶的數(shù)據(jù)報(bào)。
c)EEROR報(bào)文(差錯報(bào)文)
ERROR報(bào)文既可以由客戶發(fā)送,也可以由服務(wù)器發(fā)送,當(dāng)一條連接(如讀連接或?qū)戇B接)不能建立或在數(shù)據(jù)傳輸中出現(xiàn)問題時(shí)使用。差錯碼定義了差錯的類型,差錯信息是一個可變字節(jié),包含原文中的差錯數(shù)據(jù)。
從上面的報(bào)文格式中可以看出,TFTP報(bào)文沒有差錯檢驗(yàn)和字段,所以接收端檢驗(yàn)數(shù)據(jù)是否出現(xiàn)差錯的唯一方法是通過該TFTP數(shù)據(jù)報(bào)的UDP首部中的檢驗(yàn)和字段。
三、TFTP傳輸過程
以TFTP客戶端向 TFTP 服務(wù)器發(fā)送寫請求為例,說明整個過程。
1)服務(wù)器使用默認(rèn)端口號69被動打開連接;
2)客戶主動打開連接,向服務(wù)器進(jìn)程發(fā)送WRQ報(bào)文,報(bào)文中包含寫入文件的文件名;
3)TFTP服務(wù)器進(jìn)程選擇一個新的端口和TFTP客戶進(jìn)程進(jìn)行通信,并向TFTP客戶進(jìn)程發(fā)送塊編號為0的的ACK報(bào)文;
4)客戶端收到服務(wù)器的ACK報(bào)文后發(fā)送DATA報(bào)文,數(shù)據(jù)段為512Byte,少于512Byte表明是文件的最后的數(shù)據(jù),塊編號逐次遞增;
5)TFTP服務(wù)器校驗(yàn)收到的DATA報(bào)文的塊編號,如果校驗(yàn)正確則將數(shù)據(jù)寫入文件,并發(fā)送ACK報(bào)文表明已接收到數(shù)據(jù),ACK報(bào)文的塊編號為本次接收的DATA報(bào)文的塊編號。另外還判斷數(shù)據(jù)段長度是否小于512 Byte,小于則表明文件傳輸完成,關(guān)閉連接,如果等于512Byte,則重復(fù)步驟4-5,直到所有請求的數(shù)據(jù)發(fā)送完畢。
從上面的傳輸過程可以看出,TFTP 是一種類似于停止等待協(xié)議(不是真正的停止等待協(xié)議,在停止等待協(xié)議中,接收方發(fā)送的 ack 表示期望收到的下一個分組,而在 TFTP 的 ACK 報(bào)文中,ACK的塊號表示的是本次成功收到的數(shù)據(jù)塊,而不是下一個期望的下一個數(shù)據(jù)塊)。TFTP 客戶端只有收到服務(wù)器的確認(rèn)報(bào)文ACK后才會接著向服務(wù)器發(fā)送新的數(shù)據(jù)。
另外需要注意的是TFTP 協(xié)議中,用于讀文件的連接和用于寫文件的連接的建立方式不同:建立讀連接的時(shí)候,客戶首先向服務(wù)器發(fā)送 RRQ 讀報(bào)文,服務(wù)器收到該報(bào)文后,直接發(fā)回給該客戶 DATA 報(bào)文,并且包含第一個數(shù)據(jù)塊(塊號為 1)。而建立寫連接的時(shí)候,客戶首先先服務(wù)器發(fā)送 WRQ 寫報(bào)文,服務(wù)器收到該報(bào)文后,則發(fā)回給客戶 ACK 報(bào)文,使用的塊號為 0;當(dāng)然上面兩種情況如果遇到請求報(bào)文出錯時(shí),均會發(fā)回 ERROR 報(bào)文作為響應(yīng)。
35.2實(shí)驗(yàn)任務(wù)
本章的實(shí)驗(yàn)任務(wù)是使用LWIP協(xié)議棧搭建TFTP服務(wù)器,PC電腦上的客戶端可以從TFTP服務(wù)器讀取文件也可向TFTP服務(wù)器寫入文件,文件存放在SD卡中。
35.3硬件設(shè)計(jì)
根據(jù)實(shí)驗(yàn)任務(wù)我們可以畫出本次實(shí)驗(yàn)的系統(tǒng)框圖,如下圖所示:
圖 35.3.1 系統(tǒng)框圖
在圖 5.3.1中,UART用于打印程序相關(guān)的信息,LWIP通過以太網(wǎng)傳輸數(shù)據(jù),SD用于存放文件,包括服務(wù)器創(chuàng)建的文件和客戶端寫入的文件。
step1:創(chuàng)建Vivado工程
本次實(shí)驗(yàn)的硬件設(shè)計(jì)可以在《LWIP echo server》實(shí)驗(yàn)的基礎(chǔ)上添加SD卡。
1-1 我們先打開《LWIP echo server》實(shí)驗(yàn)的Vivado工程,打開后將工程另存為 “l(fā)wip_tftp_server”工程,然后點(diǎn)擊“OK”按鈕。
step2:使用IP Integrator創(chuàng)建Processing System
2-1 在Vivado界面左側(cè)的Flow Navigator中,點(diǎn)擊IP INTEGRATOR下的Open Block Design以打開Diagram窗口。
2-2 在打開的下圖Diagram窗口,雙擊打開ZYNQ7 Processing System重定義窗口。
圖 35.3.2 重定義ZYNQ7 Processing System
2-3 在下圖所示的重定義窗口,如同《SD卡讀寫TXT文本實(shí)驗(yàn)》那樣配置SD卡。點(diǎn)擊左側(cè)的MIO Configuration,在右側(cè)的界面中展開“I/O Peripherals”,勾選“SD 0”,在“IO”列選擇SD 0的IO為“MIO40…45”,如下圖所示。
圖 35.3.3 PS以太網(wǎng)接口配置界面
2-4 由于不需要添加其它IP,按Ctrl+S快捷鍵保存Diagram。此時(shí)我們的第二步完成,進(jìn)入第三步
step3:生成頂層HDL
在sources面板中,右鍵點(diǎn)擊Block Design設(shè)計(jì)文件“system.bd”,然后依次執(zhí)行“Generate Output Products”和“Create HDL Wrapper”。
step4:生成Bitstream文件并導(dǎo)出到SDK
由于本實(shí)驗(yàn)未用到PL部分,所以無需生成Bitstream文件,只需導(dǎo)出到SDK即可。如果使用到PL,則需要添加引腳約束以及對該系統(tǒng)進(jìn)行綜合、實(shí)現(xiàn)并生成Bitstream文件。
4-1 導(dǎo)出硬件。
在菜單欄中選擇 File > Export > Export hardware。
并在彈出的對話框中,取消勾選“Include bitstream”,直接點(diǎn)擊“OK”按鈕。
因?yàn)槭窃谇耙还こ痰幕A(chǔ)上建立的,還保留著前一工程的結(jié)果,所以會彈出“Module Already Exported”對話框,我們點(diǎn)擊“Yes”按鈕。
4-2 硬件導(dǎo)出完成后,選擇菜單File->Launch SDK,啟動SDK開發(fā)環(huán)境。
35.4軟件設(shè)計(jì)
下面步驟操作比較麻煩,實(shí)際意義也不大,可以直接使用我們提供的例程里的SDK軟件工程。
此處我們刪除《LWIP echo server》實(shí)驗(yàn)的應(yīng)用工程,保留bsp工程。下面我們開始第五步——創(chuàng)建應(yīng)用工程。下面我們開始第五步——創(chuàng)建應(yīng)用工程
step5:在SDK中創(chuàng)建應(yīng)用工程
5-1在菜單欄中選擇“File->New->Application Project”,
在彈出的界面中,輸入工程名“l(fā)wip_tftp_server”,然后選擇“Next >”,在下一界面選擇“Empty Application”,然后點(diǎn)擊“Finish”按鈕。
5-2 在Project Explorer中,鼠標(biāo)右鍵點(diǎn)擊“l(fā)wip_tftp_server _bsp”,在彈出的菜單中選擇“Board Support Package Settings”,如下圖所示:
彈出對BSP的設(shè)置界面,勾選“l(fā)wip202”和“xilffs”以啟用lwip和文件系統(tǒng),如圖 35.4.1所示。
如果沒有開啟DHCP服務(wù)可以開啟DHCP服務(wù),點(diǎn)擊standalone下的lwip202,在右側(cè)界面中到“dhcp_options”,將其下的兩個選項(xiàng)的“Value”設(shè)置為“true”,如圖 35.4.2所示。
圖 35.4.1 BSP的設(shè)置界面
圖 35.4.2 開啟DHCP
5-3 由于Xilinx提供的lwip例程里有TFTP server的源代碼,所以我們無需自己手動編寫,直接添加即可。
雙擊打開“l(fā)wip_tftp_server”目錄下的system.mss文件。在system.mss文件的底部單擊“Import Example”,如下圖所示。
圖 35.4.3 Import lwip Example
5-4 在彈出的下圖所示界面中,點(diǎn)擊下方的“Examples Directory”。
圖 35.4.4 platform_config.h文件內(nèi)容
5-5 打開例程所在文件的目錄,里面有Xilinx關(guān)于lwip的全部例程源文件。我們選擇本次實(shí)驗(yàn)需要的源文件,如圖 35.4.6所示,并單擊鼠標(biāo)右鍵選擇復(fù)制。復(fù)制完成后,在打開的圖 35.4.5界面中,點(diǎn)擊“Cancel”退出。
圖 35.4.6 例程所在文件的目錄
5-6 單擊SDK軟件的lwip_tftp_server/src目錄,按下粘貼快捷鍵“Ctrl-v”,將復(fù)制的文件粘貼到該src目錄下,如下圖所示。
圖 35.4.7 src目錄
5-7 為了方便分析,我們將剛才復(fù)制到src目錄的源文件重命名,主要是刪除不需要的前綴,其中“l(fā)wip_example_tftpserver_common.h”改為“l(fā)wip_tftp_server.h”,如下圖所示:
圖 35.4.8 刪除不相關(guān)文件后的src文件夾內(nèi)容
5-8 修復(fù)錯誤。
由于重命名了“l(fā)wip_example_tftpserver_common.h”,所以需要將lwip_tftp_server.c源文件的 #include "lwip_tftpserver_common.h"修改為#include "lwip_tftp_server.h",如下圖所示:
圖 35.4.9 修改為#include "lwip_tftp_server.h"
此處為了方便顯示,將其注釋,實(shí)際在文件內(nèi)直接修改第34行即可。
打開platform_fs.c源文件,添加BYTE work[FF_MAX_SS](第9行),修改f_mkfs函數(shù)的調(diào)用,第15行,修改后的內(nèi)容如下:
該文件在初始化平臺時(shí)由init_platform函數(shù)調(diào)用,用于掛載SD卡,掛載不成功就將SD卡格式化成FAT32,格式化成功后再嘗試掛載。
5-9 現(xiàn)在我們打開main.c文件,為了方便分析源代碼,在main.c文件中將帶有下圖箭頭所指的預(yù)編譯指令刪除。
圖 35.4.10 刪除不需要的預(yù)編譯指令
刪除不適用的預(yù)編譯指令后的main.c代碼與我們《lwip echo server實(shí)驗(yàn)》的main.c代碼基本相同,區(qū)別在于本次TFTP server實(shí)驗(yàn)沒有使用IPv6,所以沒有IPv6的預(yù)編譯指令,其他完全相同,main.c代碼講解見《lwip echo server實(shí)驗(yàn)》。
5-10本實(shí)驗(yàn)可以說是在《lwip echo server實(shí)驗(yàn)》的基礎(chǔ)上增加了文件系統(tǒng),然后將Echo server的實(shí)現(xiàn)文件echo.c文件改寫成了TFTP Server的實(shí)現(xiàn)文件。因而本實(shí)驗(yàn)的主要代碼是TFTP Server的實(shí)現(xiàn),該實(shí)現(xiàn)在lwip_tftp_server.h和lwip_tftp_server.c中,由于這兩個文件的總代碼有近500行,因此我們挑選部分代碼進(jìn)行講解。此處以客戶端寫文件為例講解lwip_tftp_server.c中的寫文件實(shí)現(xiàn)源碼。講解以函數(shù)調(diào)用順序進(jìn)行。
首先我們看main函數(shù)中調(diào)用的start_application函數(shù),該函數(shù)實(shí)現(xiàn)如下:
可以看到該函數(shù)首先通過調(diào)用tftp_create_test_file函數(shù)創(chuàng)建了測試文件,用于tftp客戶端讀取tftp服務(wù)器的文件數(shù)據(jù),測試文件名為sample#.txt,其中“#”為數(shù)字1、2、3中的任一值,其文件內(nèi)容為“----- This is a test file for TFTP server application -----”。如果不執(zhí)行客戶端的讀取文件請求,可刪除該函數(shù)的調(diào)用及其實(shí)現(xiàn)。
由于TFTP基于UDP協(xié)議,從start_application函數(shù)可以看到lwip中使用UDP協(xié)議很簡單。首先通過udp_new函數(shù)創(chuàng)建一個新的UDP PCB,然后調(diào)用udp_bind函數(shù)綁定端口號,IP_ADDR_ANY表明為任意本地地址,TFTP_PORT是在lwip_tftp_server.h宏定義的端口號,其值為69,即TFTP的默認(rèn)端口。最后調(diào)用udp_recv函數(shù)設(shè)置接收回調(diào)函數(shù)就完成了UDP服務(wù)的創(chuàng)建,服務(wù)端的功能幾TFTP協(xié)議由回調(diào)函數(shù)實(shí)現(xiàn)。回調(diào)函數(shù)代碼如下:
當(dāng)TFTP客戶端發(fā)起寫入或讀取文件的請求后,lwip協(xié)議棧調(diào)用回調(diào)函數(shù)tftp_server_recv_cb。該回調(diào)函數(shù)通過tftp_get_opcode宏獲取客戶端發(fā)送報(bào)文的操作碼,不同的操作碼執(zhí)行該函數(shù)switch分支中的不同的case,如對于寫入文件請求,則執(zhí)行“case TFTP_WRQ”分支語句,該分支語句調(diào)用TFTP處理寫文件請求函數(shù)tftp_process_write,該函數(shù)實(shí)現(xiàn)如下:
該函數(shù)首先在文件系統(tǒng)中創(chuàng)建一個文件,文件名為客戶端寫入的文件名,然后為新創(chuàng)建的UDP PCB設(shè)置接收回調(diào)函數(shù),用于處理后面接收客戶端傳入的文件,最后發(fā)送塊編號為0的ACK報(bào)文以應(yīng)答客戶端啟動傳輸。TFTP寫入請求的接收回調(diào)函數(shù)實(shí)現(xiàn)如下:
從該回調(diào)函數(shù)可以看到,TFTP服務(wù)端對客戶端發(fā)送的數(shù)據(jù)報(bào)文的塊編號進(jìn)行校驗(yàn),如果不是我們期望的塊編號就重發(fā)上一次發(fā)送的ACK報(bào)文,如果是期望的塊編號,就將數(shù)據(jù)寫入文件中,然后遞增塊編號,并發(fā)送ACK報(bào)文給客戶端以確認(rèn)收到數(shù)據(jù)。
在該函數(shù)的最后判斷接收到的數(shù)據(jù)段長度是否小于指定的字節(jié)數(shù)TFTP_DATA_PACKET_MSG_LEN,如果是,則表明已經(jīng)接收了整個文件,因此可以結(jié)束連接。TFTP_DATA_PACKET_MSG_LEN在lwip_tftp_server.h宏定義為512。
以上大概的講解了TFTP Server接收客戶端寫入文件的實(shí)現(xiàn)。下面我們進(jìn)行實(shí)際操作,看看TFTP客戶端是否能向服務(wù)器寫入文件。
35.5下載驗(yàn)證
首先我們將下載器與領(lǐng)航者底板上的JTAG接口連接,下載器另外一端與電腦連接。然后使用Mini USB連接線將USB UART接口與電腦連接,用于串口通信。使用網(wǎng)線一端連接領(lǐng)航者開發(fā)板的以太網(wǎng)接口,另一端與電腦或路由器連接。連接完成后,在開發(fā)板上插入SD 卡或者插入帶卡套(適配器)的 TF 卡(SD 卡插槽位于開發(fā)板背面)。最后連接開發(fā)板的電源,并打開電源開關(guān)。如下圖所示:
圖 35.5.1領(lǐng)航者ZYNQ開發(fā)板實(shí)物圖
現(xiàn)在進(jìn)入最后一步。
step6:板級驗(yàn)證
6-1 在SDK軟件的下方的SDK Terminal窗口中點(diǎn)擊右上角的加號連接串口。
6-2 下載程序。下載完成后,可以看到串口打印的結(jié)果如下:
圖 35.5.2 顯示打印結(jié)果
其中“File system initialization successful”表明SD卡可以正常工作。打印的最后一句表明了該實(shí)驗(yàn)如何使用。由于是TFTP服務(wù)器實(shí)驗(yàn),所以我們需要TFTP客戶端,可以從網(wǎng)上下載,也可以使用Windows系統(tǒng)的CMD命令行界面,如果開啟了TFTP客戶端,開啟方法見步驟6-6。
6-3 下面我們先創(chuàng)建一個文件用來傳輸?shù)絋FTP服務(wù)器。文件存放位置任意,文件內(nèi)容任意。
我們在Vivado工程目錄新建一個名為“test”的文件夾,里面新建一個名為testfile.txt的文件,文件內(nèi)容為“這只是一個測試文件。”,如下圖所示:
圖 35.5.3 新建一個名為test_file.txt的文件
6-4 我們打開電腦的CMD(按win+r鍵后輸入cmd),然后輸入命令“cd /D F:\ZYNQ\Embedded_System\lwip_tftp_server\test”切換到 “F:\ZYNQ\Embedded_System\lwip_tftp_server\test”目錄下,如下圖所示:
圖35.5.4 切換到上傳文件所在的目錄
然后輸入“tftp -i 192.168.1.10 PUT testfile.txt”命令,回車,會顯示傳輸成功字樣,如下圖所示:
圖 35.5.5 進(jìn)行tftp連接
此時(shí)SDK串口終端也會打印如下信息:
圖 35.5.6 串口終端打印寫入完成信息
如果回車后出現(xiàn)像下圖所示界面所示“tftp不是內(nèi)部或外部命令,也不是可運(yùn)行的程序或批處理文件”,則表明未開啟Windows的tftp客戶端功能,開啟方式見6-5。
圖 35.5.7 未啟用tftp客戶端時(shí)的界面
向服務(wù)器寫入文件剛才測試完成了,現(xiàn)在測試從服務(wù)器端讀取文件,可以讀取剛才寫入的文件,也可以讀取服務(wù)器程序創(chuàng)建的測試文件。下面我們以讀取服務(wù)器程序創(chuàng)建的測試文件為例,進(jìn)行讀取文件測試。
在CMD中輸入“tftp -i 192.168.1.10 GET sample1.txt”命令,然后回車,會顯示傳輸成功字樣,如下圖所示:
圖 35.5.8 輸入讀取文件命令
此時(shí)SDK串口終端也會打印如下信息:
圖 35.5.9 讀取成功
此時(shí)我們打開test文件夾,會看到其中新增了sample1.txt,雙擊打開,其內(nèi)容如下:
圖 35.5.10 讀取的sample1.txt文件
可以看到讀取文件測試成功。現(xiàn)在我們把SD卡插到電腦上,查看其內(nèi)容如下:
圖 35.5.11 SD卡上的文件
可以看到客戶端上傳給TFTP服務(wù)器的文件確實(shí)寫到SD卡中。
6-5 下面我們介紹一下如何開啟Windows的tftp客戶端功能。在Win10或Win7系統(tǒng)中,按“Win+r”快捷鍵后,在下圖所示界面中輸入“control”。
圖 35.5.12 打開控制面板界面
進(jìn)入下圖所示控制面板界面,將查看方式設(shè)置為“類別”,單擊“程序”下的“卸載程序”,如下圖所示:
圖 35.5.13 點(diǎn)擊進(jìn)入“程序和功能”界面
在彈出的界面中,單擊“啟用或關(guān)閉Windows功能”,如下圖所示:
圖 35.5.14 點(diǎn)擊“啟用或關(guān)閉Windows功能”
在彈出的“Windows功能”界面中,找到“Tftp Client”,并勾選,如下圖所示:
圖 35.5.15 勾選tftp client
單擊確定后,如果出現(xiàn)“Windows需要重啟電腦才能完成安裝所請求的更改”字樣,重新啟動電腦即可。現(xiàn)在 Windows的tftp客戶端服務(wù)已啟用。
至此,本實(shí)驗(yàn)完成。