[鄭文波]
4G cat1 IoT模塊廣泛應(yīng)用在物聯(lián)網(wǎng)行業(yè),如遠(yuǎn)程抄表、遠(yuǎn)程監(jiān)控、公網(wǎng)無(wú)線對(duì)講機(jī)等等。
在實(shí)際的應(yīng)用中多采用MCU+IoT模塊的方式來(lái)實(shí)現(xiàn)數(shù)據(jù)傳輸,MCU 通過(guò)與其連接的傳感器實(shí)現(xiàn)數(shù)據(jù)的采集,然后通過(guò)AT 命令控制IoT模塊實(shí)現(xiàn)數(shù)據(jù)端到端或端到云的數(shù)據(jù)傳輸。
IoT模塊一般都有完整的AT 命令集。MCU 可以通過(guò)命令集中的數(shù)據(jù)傳輸子集,實(shí)現(xiàn)數(shù)據(jù)的傳輸,包括數(shù)據(jù)的接收和發(fā)送。由于數(shù)據(jù)傳輸子集中的AT 命令多數(shù)是異步執(zhí)行的,這就帶來(lái)兩個(gè)問(wèn)題。問(wèn)題一是MCU 側(cè)的控制部分軟件編碼復(fù)雜,尤其是對(duì)很多應(yīng)用中MCU 是功能簡(jiǎn)單的單片機(jī),程序是單任務(wù)的。問(wèn)題二是無(wú)論數(shù)據(jù)的發(fā)送和接收,都是通過(guò)AT 命令一條一條的執(zhí)行,兩個(gè)AT 命令之間必須有一定的時(shí)間間隔,這樣數(shù)據(jù)的傳輸?shù)恼w效率就不高。
為了克服MCU 數(shù)據(jù)傳輸部分的編程復(fù)雜和數(shù)據(jù)傳輸?shù)恼w效率不高這兩個(gè)缺點(diǎn),同時(shí)又要保證IoT模塊的通用性。在保留原有的AT 命令集不變的情況下,增加了數(shù)據(jù)透?jìng)鞴δ?。?shù)據(jù)透?jìng)鞴δ芸梢杂行У目朔懊嫣岬降膬蓚€(gè)缺點(diǎn),因此,受到無(wú)線數(shù)據(jù)傳輸行業(yè)應(yīng)用開發(fā)者的普遍歡迎。
IoT模塊開機(jī)后默認(rèn)是AT 命令模式,在這個(gè)模式下MCU 可以通過(guò)AT 命令和IoT模塊交互。
通過(guò)專用的數(shù)據(jù)透?jìng)鰽T 命令A(yù)T+VTRANS,MCU可以命令I(lǐng)oT模塊進(jìn)入數(shù)據(jù)透?jìng)髂J健T跀?shù)據(jù)透?jìng)髂J较?,模塊將暫時(shí)不能接收AT 命令,直到模塊退出數(shù)據(jù)透?jìng)髂J健?/p>
數(shù)據(jù)傳輸分為上行(如圖1 所示)和下行(如圖2 所示),上行指MCU 發(fā)送數(shù)據(jù)給IoT模塊,通過(guò)IoT模塊發(fā)送到網(wǎng)絡(luò),下行指IoT模塊從網(wǎng)絡(luò)側(cè)接收數(shù)據(jù),然后通過(guò)AT uart 口發(fā)送給MCU。buffer A 中的數(shù)據(jù)發(fā)送完后,buffer A 和buffer B 可以快速切換,接著把buffer B 中的數(shù)據(jù)發(fā)送到網(wǎng)絡(luò)側(cè),同時(shí),如果MCU 有數(shù)據(jù)發(fā)送給IoT 時(shí),就可以緩存到buffer A 中。下行數(shù)據(jù)傳輸類似。
圖1 上行數(shù)據(jù)流
圖2 下行數(shù)據(jù)流
如果某些應(yīng)用場(chǎng)合,MCU 和IoT 之間數(shù)據(jù)傳輸?shù)臄?shù)據(jù)特點(diǎn)是:小包、頻繁。那么可以進(jìn)一步優(yōu)化buffer的設(shè)計(jì),增加buffer的數(shù)量,這些buffer 按順序輪換,同時(shí)提高了MCU 與IoT模塊之間數(shù)據(jù)傳輸和IoT模塊與網(wǎng)絡(luò)側(cè)之間數(shù)據(jù)傳輸?shù)男?,進(jìn)而提高了整體的上行數(shù)據(jù)傳輸效率。如此設(shè)計(jì)buffer,下行數(shù)據(jù)傳輸也一樣可以提高效率。
在數(shù)據(jù)傳輸時(shí),某些情況下會(huì)出現(xiàn)吞吐率A 和吞吐率B 嚴(yán)重不匹配的情況,比如上行當(dāng)AT uart 吞吐率持續(xù)大于IoT模塊發(fā)送到網(wǎng)絡(luò)的吞吐率時(shí),即使有buffer 緩存數(shù)據(jù),buffer 也存在溢出的風(fēng)險(xiǎn),數(shù)據(jù)一旦有溢出,那么就意味著數(shù)據(jù)中傳輸?shù)倪^(guò)程中發(fā)生了部分丟失,即數(shù)據(jù)傳輸變得不可靠,這在實(shí)際應(yīng)用中是不可接受的。
為了避免由于數(shù)據(jù)buffer 溢出而導(dǎo)致的數(shù)據(jù)丟失,必須進(jìn)行數(shù)據(jù)流控。當(dāng)數(shù)據(jù)buffer 中的數(shù)據(jù)量達(dá)到流控閥值上限時(shí),啟動(dòng)流控,通知數(shù)據(jù)發(fā)送方暫停數(shù)據(jù)的發(fā)送,直到buffer 中的數(shù)據(jù)量下降到流控閥值下限。
MCU 和IoT模塊之間通過(guò)AT uart 傳輸數(shù)據(jù)的速率,我們這里姑且稱為吞吐率A,與IoT模塊和網(wǎng)絡(luò)之間的數(shù)據(jù)傳輸速率,我們姑且稱為吞吐率B。理想的結(jié)果是吞吐率A 和吞吐率B 在任何情況下都是匹配的。上行發(fā)送數(shù)據(jù)時(shí),MCU 通過(guò)AT uart 丟給IoT模塊的數(shù)據(jù),IoT模塊馬上通過(guò)網(wǎng)絡(luò)發(fā)送出去。下行接收網(wǎng)絡(luò)側(cè)的數(shù)據(jù)是,IoT模塊接收到數(shù)據(jù),馬上通過(guò)AT uart 丟給MCU。
實(shí)際的情況是吞吐率A 和吞吐率B 經(jīng)常不匹配,導(dǎo)致數(shù)據(jù)傳輸時(shí)出現(xiàn)丟失數(shù)據(jù)的現(xiàn)場(chǎng)。我們采用增加數(shù)據(jù)buffer的方式來(lái)解決這個(gè)問(wèn)題,即通過(guò)適當(dāng)?shù)臄?shù)據(jù)緩存,來(lái)達(dá)到減少數(shù)據(jù)丟失的概率,增加上行和下行數(shù)據(jù)傳輸?shù)男省?/p>
為了進(jìn)一步提高數(shù)據(jù)傳輸?shù)男剩瑴p少因?yàn)閿?shù)據(jù)buffer 被占用,而導(dǎo)致數(shù)據(jù)傳輸效率受影響的情況發(fā)生,我們采用了乒乓buffer 來(lái)緩存數(shù)據(jù)。上行傳輸數(shù)據(jù)時(shí),即使buffer A 中的數(shù)據(jù)正在上傳到網(wǎng)絡(luò)側(cè),那么buffer B還可以用于接收緩存MCU 發(fā)送給IoT模塊的數(shù)據(jù)。當(dāng)
在數(shù)據(jù)透?jìng)鹘⒌倪^(guò)程中,可能會(huì)由于基站、終端受到干擾等原因,導(dǎo)致數(shù)據(jù)連接建立的過(guò)程中,出現(xiàn)異常。在數(shù)據(jù)建立連接后,在數(shù)據(jù)傳輸過(guò)程中或者在等待數(shù)據(jù)傳輸時(shí),連接也可能出現(xiàn)異常,導(dǎo)致SOCKET 關(guān)閉,數(shù)據(jù)連接斷開。
當(dāng)出現(xiàn)連接異常時(shí),要根據(jù)異常的不同情況,采取不同的處理方法,去嘗試恢復(fù)連接,目的是維持持續(xù)的數(shù)據(jù)連接。
IP 資源是有限的,運(yùn)營(yíng)商為了基于有限的IP 資源,為盡可能多的無(wú)線數(shù)據(jù)終端提供數(shù)據(jù)服務(wù),會(huì)定時(shí)清理長(zhǎng)時(shí)間處于無(wú)數(shù)據(jù)收發(fā)狀態(tài)(稱為idle 狀態(tài))的終端。
當(dāng)數(shù)據(jù)終端處于idle 狀態(tài)持續(xù)時(shí)間超過(guò)運(yùn)營(yíng)商設(shè)定的時(shí)間(電信數(shù)據(jù)服務(wù)器的這個(gè)時(shí)間參數(shù)設(shè)置為6 分鐘),運(yùn)營(yíng)商的數(shù)據(jù)服務(wù)器就會(huì)強(qiáng)制釋放連接,并收回終端占用的IP。
有些應(yīng)用中需要持續(xù)的數(shù)據(jù)連接,那么就要通過(guò)發(fā)送心跳包的方法,避免終端處于idle 狀態(tài)持續(xù)時(shí)間超過(guò)運(yùn)營(yíng)商允許的最長(zhǎng)時(shí)間。
建立數(shù)據(jù)連接的過(guò)程分為兩步,如圖3 所示,第一步是PPP 撥號(hào),第二步是創(chuàng)建SOCKET。
圖3 SOCKET 創(chuàng)建流程
本文所述的IOT模塊PPP撥號(hào)對(duì)應(yīng)的AT命令格式為:
參數(shù)說(shuō)明:
示例:AT+CGDATA=”PPP”,1
PPP 撥號(hào)成功后,接著需要為數(shù)據(jù)連接創(chuàng)建SOCKET。SOCKET 用于描述IP 地址和端口,是一個(gè)通信鏈的句柄,可以用來(lái)實(shí)現(xiàn)不同虛擬機(jī)或不同計(jì)算機(jī)之間的通信。
創(chuàng)建SOCKET 前,需要選擇協(xié)議的類型。本文所述的IoT模塊支持TCP/IP UDP 兩種協(xié)議。MCU 可以在發(fā)給IoT模塊建立數(shù)據(jù)透?jìng)鞯腁T 命令中通過(guò)參數(shù)設(shè)置在兩種協(xié)議中選擇其一。
在IoT模塊和數(shù)據(jù)接收端之間,建立一個(gè)用于數(shù)據(jù)傳輸?shù)腟OCKET,并且維持該SOCKET 持續(xù)有效。在端到端或端到云之間建立一個(gè)數(shù)據(jù)傳輸?shù)臄?shù)據(jù)通道。數(shù)據(jù)通道一旦成功創(chuàng)建,MCU 就可以直接把數(shù)據(jù)發(fā)送給IoT模塊,而不需要每次發(fā)送數(shù)據(jù)前都要發(fā)送一堆的AT 命令來(lái)判斷網(wǎng)絡(luò)狀態(tài)和創(chuàng)建數(shù)據(jù)連接。這樣就實(shí)現(xiàn)了數(shù)據(jù)的透?jìng)鞴δ堋?/p>
3.2.1 建立過(guò)程中的異常
(1)無(wú)網(wǎng)絡(luò)服務(wù)
建立數(shù)據(jù)透?jìng)髦?,先查詢一下終端有沒有注冊(cè)到網(wǎng)絡(luò),如果已經(jīng)注冊(cè)到網(wǎng)絡(luò),就繼續(xù)查詢一下是否有基站的網(wǎng)絡(luò)服務(wù),如果沒有注冊(cè)到網(wǎng)絡(luò)或者沒有網(wǎng)絡(luò)服務(wù),就上報(bào)錯(cuò)誤信息給MCU。MCU 可以一段時(shí)間后再重新嘗試連接。
(2)PPP 撥號(hào)失敗
出現(xiàn)PPP 撥號(hào)失敗時(shí),如果重新嘗試數(shù)次后還是不成功,可能的原因有:運(yùn)營(yíng)商網(wǎng)絡(luò)原因,終端的SIM 卡欠費(fèi)等。嘗試次數(shù)達(dá)到了設(shè)定的最大次數(shù),就放棄PPP 撥號(hào),同時(shí)通過(guò)AT uart 口上報(bào)給MCU。
(3)SOCKET 無(wú)法打開
PPP 撥號(hào)成功后,終端會(huì)或獲得有效的IP 地址。接著就可以嘗試打開SOCKET。如果打開失敗,可以再嘗試幾次。如果嘗試幾次后還是無(wú)法成功打開SOCKET,就要關(guān)閉PPP,重新打開PPP,然后再嘗試去打開SOCKET。如果這樣的操作循環(huán)嘗試數(shù)次后還是無(wú)法打開SOCKET,就通過(guò)AT uart 口上報(bào)給MCU。這種情況最可能的原因是目標(biāo)服務(wù)器有異常。
3.2.2 長(zhǎng)連接狀態(tài)下的異常
(1)SOCKET 異常關(guān)閉
導(dǎo)致SOCKET 異常關(guān)閉的常見原因有:目標(biāo)服務(wù)器主動(dòng)關(guān)閉、目標(biāo)服務(wù)器異常、運(yùn)營(yíng)商網(wǎng)絡(luò)異常、由于信號(hào)不好等原因?qū)е碌慕K端接收靈敏度大幅下降等。
SOCKET 異常關(guān)閉后,可以重新嘗試打開SOCKET。如果嘗試次數(shù)達(dá)到最大限制次數(shù),還是無(wú)法成功打開SOCKET,就關(guān)閉PPP,然后重新嘗試打開PPP 連接和SOCKET。如果嘗試次數(shù)達(dá)到最大限制次數(shù),還是無(wú)法打開SOCKET,就放棄建立連接,把錯(cuò)誤信息通過(guò)AT uart口上報(bào)給MCU。
(2)SOCKET 和PPP 同時(shí)斷開
如果SOCKET 和PPP 同時(shí)斷開,就按照打開PPP,打開SOCKET的順序重新建立連接,前面有闡述,就不再重復(fù)。
(3)SOCKET 未斷開,數(shù)據(jù)始終發(fā)送不成功
如果連續(xù)發(fā)生數(shù)次數(shù)據(jù)發(fā)送失敗時(shí),就說(shuō)明當(dāng)前的連接出現(xiàn)了問(wèn)題,這時(shí)候就要嘗試斷開當(dāng)前的連接,然后重新建立數(shù)據(jù)透?jìng)鳌榱吮苊饨⒌倪^(guò)程中MCU 繼續(xù)發(fā)送數(shù)據(jù)給IoT模塊,進(jìn)而導(dǎo)致因buffer 溢出而丟失數(shù)據(jù),IoT模塊發(fā)現(xiàn)有數(shù)據(jù)連續(xù)發(fā)送失敗時(shí),要把錯(cuò)誤信息通過(guò)AT uart 口上報(bào)給MCU,然后再開始嘗試重新建立連接。建立連接成功后,通過(guò)AT uart 口上報(bào)給MCU,MCU 就可以繼續(xù)發(fā)送數(shù)據(jù)給IoT模塊。
為了實(shí)現(xiàn)數(shù)據(jù)透?jìng)鞴δ埽O(shè)計(jì)了一個(gè)數(shù)據(jù)結(jié)構(gòu)體DataMngrT。
數(shù)據(jù)結(jié)構(gòu)體的解析如表1 所示。
表1 數(shù)據(jù)結(jié)構(gòu)解析
選相同型號(hào)的兩個(gè)IoT模塊,一個(gè)采用逐條AT 命令的方式,另外一個(gè)采用數(shù)據(jù)透?jìng)鞯姆绞?,在相同的網(wǎng)絡(luò)環(huán)境下做數(shù)據(jù)收發(fā)的對(duì)比測(cè)試,實(shí)測(cè)數(shù)據(jù)如表2 所示。
表2 數(shù)據(jù)收發(fā)實(shí)測(cè)
由實(shí)驗(yàn)測(cè)試數(shù)據(jù)可以看到,在持續(xù)收發(fā)數(shù)據(jù)應(yīng)用場(chǎng)景下,數(shù)據(jù)透?jìng)髂J接忻黠@的速率優(yōu)勢(shì)。
支持?jǐn)?shù)據(jù)透?jìng)髂J降腎oT 軟件版本發(fā)布后,用戶使用一段時(shí)間之后,我們收到了用戶很好的反饋??偨Y(jié)一下主要有兩點(diǎn):一是MCU 側(cè)收發(fā)數(shù)據(jù)的編程簡(jiǎn)單了;二是收發(fā)數(shù)據(jù)速率明顯提高了。
版本經(jīng)過(guò)一段時(shí)間的測(cè)試和實(shí)際產(chǎn)品使用驗(yàn)證穩(wěn)定后,我們?cè)谄渌吞?hào)的IoT模塊中也移植了該功能。此后,數(shù)據(jù)透?jìng)鞴δ艹蔀槲宜綢oT模塊的標(biāo)配功能。