RT-Thread STM32F4 自制 BootLoader 的製作和使用(線上升級上位機篇Android)
RT-Thread STM32F4 自制 BootLoader 的製作和使用(線上升級上位機篇Android)
前言說明
前兩篇文章分別介紹了通用BootLoader的編寫和自制BootLoader的編寫,本篇文章用來介紹串列埠YModem升級的上位機實現方法。
大致介紹
在上位機實現在下位機的線上升級,最關鍵的就是實現串列埠YModem的通訊協議,由於很多嵌入式設計的多樣性的需求,不可能有完美的第三方庫滿足需求,因此我們需要在第三方庫的基礎上進行修改。
採用的第三方庫的地址為: https://github.com/ArdWang/YModemlib_Android.
思路分析
1.為什麼採用YModem協議進行串列埠傳送和接收呢?是不是有別的更好的方案?
這是我一開始就思考的問題。在慢慢的除錯和使用過程中,有了答案,串列埠通訊的協議方式有很多,甚至自己造一個都是可以的,但是採用YModem協議進行通訊,使用的人比較多,並且通訊準確可靠,帶CRC校驗,像xshell或者別的串列埠除錯工具自帶YModem協議,即使上位機的程式碼沒有寫,也可以採用串列埠除錯工具來直接除錯下位機的程式,比較方便。當然,如果也可以用來除錯上位的程式碼。
2.,如果將600多kb的檔案內容直接下發是否合適?
線上升級的檔案大小基本上都在幾百KB以上,因此如果將檔案一次性下發,是可以的,Linux系統對於輸入和輸出流的大小是有限制的,因此不僅僅Linux系統對輸出流有快取,Android系統下app 程式內部也要對發出的檔案內容進行快取,串列埠的輸出速度是固定的,因此即使app程式將資料傳送完成,資料真正到達到下位機的時間並不受APP控制。直接將幾百KB大小的檔案下發給RAM很小的微控制器是不合適的,微控制器無法快速的處理完畢這麼多資料。
除錯建議
除錯YModem協議可以採用Xshell自帶的YModem通訊功能來進行除錯,使用串列埠網路除錯都比較方便。
綜上:
因此採用一個帶CRC校驗和分批傳送資料的協議進行線上的升級是十分必要的。並且考察了RT-thread 通用BootLoader的升級方式就可以明白,RT-thread採用的是YModem-1K通訊協議。因此如果自制BootLoader,最好也採用YModem-1k協議,這樣與通用BootLoader可以保持一定的相容,也方便以後除錯和移植。並且這種通訊協議可以很方便的更換通訊硬體,如網路,藍芽等。
啟動通訊
下面的程式碼是一個簡單的資料傳送啟動示例。
private void startTransmission(){
//String md5 = MD5Util.MD5(mCurrentFilePath);
yModem = new YModem.Builder()
.with(this)
.filePath(mCurrentFilePath)
.fileName(mCurrentFileName)
.checkMd5("")
.callback(new YModemListener() {
@Override
public void onDataReady(byte[] data) { //資料傳送
if(sendData) {
if (bluetoothService.writeCharacteristic(mSendOTACharacteristic, data)) {
Log.i("==Send Data is:", bytesToHexFun(data));
}
}
}
@Override
public void onProgress(int currentSent, int total) { //傳送進度
float currentPt = (float)currentSent/total;
int a = (int)(currentPt*100);
mUpgradeBar.setProgress(currentSent); // Main Progress
mUpgradeBar.setMax(total); // Maximum Progress
if(a<=100){
mUpgradeBar.setProgressText(""+a+"%");
}else{
mUpgradeBar.setProgressText("100%");
}
}
@Override
public void onSuccess() { //傳送完畢
Toast.makeText(OTAActivity.this,"韌體升級完成",Toast.LENGTH_LONG).show();
finish();
}
@Override
public void onFailed(String reason) {//傳送失敗
Toast.makeText(OTAActivity.this,reason,Toast.LENGTH_LONG).show();
}
}).build();
yModem.start(); //啟動
}
關鍵點說明
控制一次讀取資料大小
下面的程式碼是讀取傳送檔案的方法,在FileStreamThread.java檔案中,其中
byte[] block = new byte[1024];
是控制一次讀取和傳送資料的大小的,預設是1024位元組。
private void prepareData() throws IOException {
initStream();
byte[] block = new byte[1024]; //用於修改 一次輸出的資料大小,128位元組或者1024位元組
int dataLength;
byte blockSequence = 1;//The data package of a file is actually started from 1
isDataAcknowledged.set(true);
isKeepRunning = true;
while (isKeepRunning) {
if (!isDataAcknowledged.get()) {
try {
//We need to sleep for a while as the sending 1024 bytes data from ble would take several seconds
//In my circumstances, this can be up to 3 seconds.
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
continue;
}
if ((dataLength = inputStream.read(block)) == -1) {
L.f("The file data has all been read...(檔案所有內容讀取完畢!)");
if (listener != null) {
onStop();
listener.onFinish();
}
break;
}
byte[] packige = YModemUtil.getDataPackage(block, dataLength, blockSequence);
if (listener != null) {
listener.onDataReady(packige);
}
blockSequence++;
isDataAcknowledged.set(false);
}
}
流程控制
下面的程式碼是主要用於控制整個通訊過程中的流程的,這與標準的YModem-1K的協議流程是一致的,但是具體到應用中還需要進行除錯測試,我在使用的過程中就發現在與XShell工具進行YModem通訊時是沒問題的,但是到了與微控制器進行YModem通訊時有時候會出現不響應的情況,請大家在使用時根據標準的YModem協議流程進行單步除錯,測試。適當時要具體進行修改,提高程式碼的相容性。
/**
* Method for the outer caller when received data from the terminal
*/
public void onReceiveData(byte[] respData) {
if (respData != null && respData.length > 0) {
switch (CURR_STEP) {
case STEP_HELLO:
handleHello(respData);
break;
case STEP_FILE_NAME:
handleFileName(respData);
break;
case STEP_FILE_BODY:
timerHelper.stopTimer();
handleFileBody(respData);
break;
case STEP_EOT:
timerHelper.stopTimer();
handleEOT(respData);
break;
case STEP_END:
timerHelper.stopTimer();
handleEnd(respData);
break;
default:
break;
}
} else {
L.f("The terminal do responsed something, but received nothing??");
}
}
資料傳送的YModem協議
這個YModem的協議與標準的YModem的協議有一點差異,主要是加入了檔案的Md5校驗和Hello握手資料的傳送。這是為了方便把傳送資料的主動權控制在傳送端手中。如果有必要可以根據實際的需求來修改握手和MD5校驗這部分程式碼。
/**
* THE YMODEM:
* HELLO BOOTLOADER ---------------------------------------------->* //主機傳送HELLO資料並等待從機的回應,失敗達到一定次數,則判斷失敗,從機收到後會回應ok(ox0C)
* <---------------------------------------------------------------* C //從機回覆OK
* SOH 00 FF filename0fileSizeInByte0MD5[90] ZERO[38] CRC CRC----->* //主機傳送 檔名和檔案大小資訊並附帶傳送的這段資料的CRC檢驗碼
* <---------------------------------------------------------------* ACK C //從機回覆應答,並帶ok
* STX 01 FE data[1024] CRC CRC ---------------------------------->* //主機開始傳送資料給從機 每次資料1024位元組,並帶著資料的CRC校驗值,注意程式中計算資料傳送進度的時候把CRC校驗的資料也計算了進去,導致計算出的進度比實際進度快,目前沒有修復這個問題(如果確實有必要可以考慮修改下程式碼進行修復)
* <---------------------------------------------------------------* ACK //從機回覆應該
* STX 02 FF data[1024] CRC CRC ---------------------------------->*
* <---------------------------------------------------------------* ACK
* ...
* ...
* <p>
* STX 08 F7 data[1000] CPMEOF[24] CRC CRC ----------------------->*
* <---------------------------------------------------------------* ACK
* EOT ----------------------------------------------------------->* //主機傳送EOT指令給從機,表示要結束傳輸
* <---------------------------------------------------------------* ACK //從機回覆應答
* SOH 00 FF ZERO[128] ------------------------------------------->* //傳送結束資料幀
* <---------------------------------------------------------------* ACK //從機回覆應答
* <---------------------------------------------------------------* MD5_OK //從機會MDK5檢驗ok
*/
標準YModem協議說明
基本流程
YModem分成YModem-1K與YModem-g。
YModem-1K用1024位元組資訊塊傳輸取代標準的128位元組傳輸,資料的傳送回使用CRC校驗,保證資料傳輸的正確性。它每傳輸一個資訊塊資料時,就會等待接收端回應ACK訊號,接收到回應後,才會繼續傳輸下一個資訊塊,保證資料已經全部接收。
YModem-g傳輸形式與YModem-1K差不多,但是它去掉了資料的CRC校驗碼,同時在傳送完一個資料塊資訊後,它不會等待接收端的ACK訊號,而直接傳輸下一個資料塊。正是它沒有涉及錯誤校驗,才使得它的傳輸速度比YModem-1K來得塊。
一般都會選擇YModem-1K傳輸,平時所說的YModem也是指的是YModem-1K。下面就講講它的傳輸協議。
1、起始幀的資料格式
YModem的起始幀並不直接傳輸檔案的資料,而是將檔名與檔案的大小放在資料幀中傳輸,它的幀長=3位元組資料首部+128位元組資料+2位元組CRC16校驗碼=33位元組。它的資料結構如下:
SOH 00 FF filename[ ] filezise[ ] NUL[ ] CRCH CRCL
其中SOH=0x01,表示這個資料幀中包含著128位元組的資料部分;在SOH後面的00 FF,00表示資料幀序號,因為是起始幀,所以它的幀序為00,至於FF,它是幀序的取反,YModem特地這麼做是 為了給資料是否正確提供一種判斷依據 ,通過判斷這兩個位元組是否為取反關係,就可以知道資料是否傳輸出錯;
filename[ ]就是檔名,如檔名foo.c,它在資料幀中存放格式為:66 6F 6F 2E 63 00,一定要在檔名最後跟上一個00,表示檔名結束;
filesize[ ]就是檔案大小,如上面的foo.c的大小為1KByte,即1024Byte,需要先將它轉化成16進位制,即0x400,所以它在資料幀的存放格式為:34 30 30 00,即“400”,同樣的檔案大小最後需要跟上00,表示結束;
NUL[ ]表示剩下的位元組都用00填充,資料部分大小為128位元組,除去檔名與檔案大小佔用的空間外,剩餘的位元組全部用00填充;CRCH CRCL分別表示16位CRC校驗碼的高8位與低8位。
2、資料幀的資料格式
YModem的資料幀中會預留1024位元組空間用來傳輸檔案資料,它跟起始幀接收差不多,如下:
STX 01 FE data[1024] CRCH CRCL
其中STX=0x02,表示這幀資料幀後面包含著1024位元組的資料部分;STX後面的01 FE,01表示第一幀資料幀,FE則是它的取反,當然如果是第二幀資料的話就是:01 FD;data[1024]表示存放著1024位元組的檔案資料;CRCH與CRCL是CRC16檢驗碼的高8位與低8位。
如果檔案資料的最後剩餘的資料在128~1024之前,則還是使用STX的1024位元組傳輸,但是剩餘空間全部用0x1A填充,如下結構:
STX [num] [~num] data[ ] 1A ...1A CRCH CRCL
有一種特殊的情況:如果檔案大小小於等於128位元組或者檔案資料最後剩餘的資料小於128位元組,則YModem會選擇SOH資料幀用128位元組來傳輸資料,如果資料不滿128位元組,剩餘的資料用0x1A填充這是資料正的結構就變成了:
檔案大小小於128位元組:
SOH 01 FE data[ ] 1A ...1A CRCH CRCL
檔案最後剩餘資料小於128位元組:
SOH [num] [~~num] data[ ] 1A...1A CRCH CRCL
3、結束幀資料結構
YModem的結束幀資料也採用SOH的128位元組資料幀,它的結構如下:
SOH 00 FF NUL[128] CRCH CRCL
結束幀同樣以SOH開頭,表示後面跟著128位元組大小的資料;結束幀的幀序也認為是00 FF;結束幀的128位元組的資料部分不存放任何資訊,即NUL[128]全部用00填充。
4、檔案傳輸過程
檔案的傳輸過程,以具體的例子說明。把foo.c,大小為4196Byte(16進製為0x1064)的檔案作為傳輸的物件,則它的傳輸過程如下:
下面是對標準的YModem的協議進行說明,這個協議的流程是要熟悉的,這是為了方便後續程式碼除錯。
步驟序號 | 傳送端資料 | 資料方向 | 接收端資料 |
---|---|---|---|
1 | - | <<<< | C |
2 | SOH 00 FF “foo.c” "1064’’ NUL[118] CRC CRC | >>>>> | - |
3 | - | <<<< | ACK |
4 | - | <<<< | C |
5 | STX 01 FE data[1024] CRC CRC | >>>>> | - |
6 | - | <<<< | ACK |
7 | STX 02 FD data[1024] CRC CRC | >>>> | - |
8 | - | <<<< | ACK |
9 | STX 03 FC data[1024] CRC CRC | >>>> | - |
10 | - | <<<<< | ACK |
11 | STX 04 FB data[1024] CRC CRC | >>>> | - |
12 | - | <<<< | ACK |
13 | SOH 05 FA data[100] 1A[28] CRC CRC | >>>> | - |
14 | - | <<<< | ACK |
15 | EOT | >>>>> | - |
16 | - | <<<<< | NAK |
17 | EOT | >>>>> | - |
18 | - | <<<<< | ACK |
19 | - | <<<<< | C |
20 | SOH 00 FF NUL[128] CRC CRC | >>>>> | - |
21 | - | <<<<< | ACK |
5、CRC的計算
YModem的採用的是CRC16-CCITT歐洲版本的CRC校驗,它的生成多項式為:x16+x12+x5+1,具體的CRC的計算可以檢視原始碼中內容。
關鍵點說明
YModem的傳輸過程就是上面所示。但是上面傳輸過程中存在許多通訊訊號,它們的數值與意義如下表所示:
符號 | 數值 | 含義 | 說明 |
---|---|---|---|
SOH | 0x01 | 128位元組資料包 | |
STX | 0x02 | 1024位元組資料包 | |
EOT | 0x04 | 結束傳輸 | EOT訊號由傳送端傳送 |
ACK | 0x06 | 回應 | |
NAK | 0x15 | 不回應 | |
CA | 0x18 | 傳輸中止 | CA中止傳輸訊號由傳送端傳送 |
C | 0x43 | 請求資料包 |
總結
GitHub提供的程式碼只是方便使用而已,其實線上升級的功能根據需求的不同有很多細節上的區別,關鍵是要理解了YModem協議後,根據具體的要求來修改自己的程式碼。
相關文章
- RT-Thread 的STM32 通用 Bootloaderthreadboot
- 【Mysql】傳統複製線上升級為GTID模式MySql模式
- centos7 離線升級/線上升級作業系統核心CentOS作業系統
- 小程式如何製作和代理
- 同機上升級oracle10.2.0.5到11.2.0.4Oracle
- 初級學習android的相關準備工作和學習的流程Android
- Android 面試中級篇Android面試
- 線上升級Redis紀實Redis
- 上位機和下位機之間區域網的搭建
- 動手寫一個STM8的輕量級bootloaderboot
- Android豎虛線繪製Android
- 新手如何快速製作和開發自己的小程式
- 如何進入Android系統的Bootloader和Recovery環境Androidboot
- UWB定位系統上位機原始碼原始碼
- RT-Thread Studio使用教程thread
- WPF上位機 - 使用轉換器實現TIA Wincc中的文字列表功能
- Android面試之Java中級篇Android面試Java
- rt-thread AT元件偶爾當機的問題thread元件
- Android之父即將公佈自制新手機,將在月底釋出Android
- 自制android gif動畫解析器Android動畫
- 基礎篇- 沙盒以及檔案的操作和存取
- XDMA上位機相關:一點筆記筆記
- 上位機程式設計編碼規範程式設計
- 線性dp:最長上升子序列
- Globalwebindex:兩年內Android作業系統的使用從32%上升到65%WebIndexAndroid作業系統
- 【轉】C++ map的基本操作和使用C++
- android sdk離線升級方法Android
- 分享開發者製作和推廣兒童應用的注意事項
- Android使用AChartEngine製作曲線、柱狀圖、餅形等圖表Android
- Android面試之Java中級Plus篇Android面試Java
- 瞭解Vuex方法的使用初級篇Vue
- 淺談機房接地線的製作方法
- [開源&分享]一個用於微控制器IAP自動傳送的串列埠助手,上位機,使用Python+tkinter製作串列埠Python
- android IM模組-語音-錄製篇1Android
- Creative Strategies:中國三四線城市iPhone保有量上升 Android吸引力下降iPhoneAndroid
- ReactNative打離線包-android篇ReactAndroid
- C# 簡易的串列埠監視上位機實現C#串列埠
- C# 開發的環境監測上位機應用C#