iOS藍芽開發(三):iOS中藍芽模組OTA升級(YModem協議)

iOS藍芽開發(三):iOS中藍芽模組OTA升級(YModem協議)

上一篇簡單介紹了藍芽4.0的iOS實現程式碼,詳細的東西大家可以去github上搜babyBluetooth,裡面有一些學習資料,接下來分享的是OTA升級的東西,我們假定看這篇文章的時候,關於iOS和外設間的藍芽收發資料已經掌握的很6

OTA詳解

OTA(Over-the-Air)空中傳輸,一般用於韌體升級。其實和資料傳輸一樣,很簡單,傳送指令,接受指令,傳送bin資料包,結束指令。。。只是藍芽傳輸的資料大小使得這一步驟稍顯複雜。

首先,檔案傳輸,其實也是傳輸的資料,即 NSData,和普通的 peripheral 寫入沒什麼區別。韌體升級的檔案一般是 .bin 檔案,也有 .zip 的。不過這些檔案,都是資料,所以首先將檔案轉為 NSData

需要注意的是:data 一般很長,畢竟是檔案。直接通過 writeValue:forCharacteristic:type: 寫入的話,不會有任何回撥。哪怕是錯誤的回撥,都沒有。這是因為藍芽單次傳輸的資料大小是有限制的。

我們一般使用20bytes作為標準,即將bin檔案轉為NSData,然後截成每個20bytes的包傳送;這些步驟需要和刷firmware的工程師協商,指定一個協議,接下來以公司的YModem協議舉例

YModem協議

YModem協議是由XModem協議演變而來的,是一種傳送並等待的協議,即傳送方傳送一個資料包以後,都 要等待接收方的確認。如果是 ACK 訊號,則可以傳送新的包。如果是 NAK 訊號, 則重發或者錯誤退出。

每包資料可以達到1024位元組,是一個非常高效的檔案傳輸協議

所用到的符號
#define MODEM_SOH 0x01  //資料塊起始字元
#define MODEM_STX 0x02  //1028位元組開始
#define MODEM_EOT 0x04  //檔案傳輸結束
#define MODEM_ACK 0x06  //確認應答 
#define MODEM_NAK 0x15  //出現錯誤
#define MODEM_CAN 0x18  //取消傳輸
#define MODEM_C 0x43    //大寫字母C
資料格式示意

這裡寫圖片描述

檔案傳輸過程

開啟是由接收方開啟傳輸,它發一個大寫字母 C(0x43) 開啟傳輸。然後進入 等待 SOH(0x01))狀態,如果沒有迴應,就會超時退出。

傳送方開始時處於等待過程中,等待 C。收到 C 以後,傳送(SOH)數 據包開始訊號,傳送序號(00),補碼(FF),“檔名”,“\0”“檔案大小” “除去序號外,補滿 128 位元組”,16位CRC 校驗兩個位元組,高位元組在前,低位元組在後。進入等待(ACK)狀態。
– 內容示例: SOH 00 FF Foo.bin NUL[123] CRC CRC

接收方收到以後,CRC 校驗滿足,則傳送 ACK。傳送方接收到 ACK,又 進入等待“檔案傳輸開啟”訊號,即重新進入等待“C”的狀態。

前面接收方只是收到了一個檔名,現在正式開啟檔案傳輸,Ymodem 支援 128 位元組和 1024 位元組一個資料包。128 位元組以(SOH)開始,1024 位元組以(STX)開始。接收方又發出一個“C”訊號,開始準備接收檔案。進入等待“SOH”或者“STX”狀態。

傳送接收到“C”以後,傳送第一個資料包,(SOH)(01序號)(F E補碼)(128位資料)(CRC校驗),或者(STX)(01序號)(F E補碼)(1024位資料)(CRC校驗),不滿128或者1024,用0x00補齊,等待接收方“ACK”。
– 內容示例:STX 01 FE data[1024] CRC CRC

檔案傳送完以後,傳送方發出一個“EOT”訊號,接收方也以“A CK”迴應。然後接收方會再次發出“C”開啟另一次傳輸,若接著傳送方會發出一個“全0資料包”,接收方“ACK”以後,本次通訊正式結束。

當然Ymodem相對於Xmodem改進的地方就在於傳輸再次 開啟以後,又可以傳送另外一個檔案,即一次傳輸允許傳送多個檔案,但這個 特性我還沒有用過,暫且不提。

最後CRC兩位元組:這裡需要注意,只有資料部分128或者1024參與了效CRC驗,不包括頭和編碼部分。

CRC校驗的計算方法
/**
* @brief  Update CRC16 for input byte
* @param  crc_in input value
* @param  input byte
* @retval None
*/
uint16_t UpdateCRC16(uint16_t crc_in, uint8_t byte)
{
uint32_t crc = crc_in;
uint32_t in = byte | 0x100;     
do
{
crc <<= 1;
in <<= 1;
if(in & 0x100)
crc;
if(crc & 0x10000)
crc ^= 0x1021;
}   
while(!(in & 0x10000));     
return crc & 0xffffu;
}   
/**
* @brief  Cal CRC16 for YModem Packet
* @param  data
* @param  length
* @retval None
*/
uint16_t Cccal_CRC16(const uint8_t* p_data, uint32_t size)
{
uint32_t crc = 0;
const uint8_t* dataEnd = p_data size;   
while(p_data < dataEnd)
crc = UpdateCRC16(crc, *p_data  );      
crc = UpdateCRC16(crc, 0);
crc = UpdateCRC16(crc, 0);      
return crc&0xffffu;
}

以上就是YModem協議進行OTA升級的概述

YModem協議以及OTA部分原始碼

https://github.com/jakajacky/OTA_YModem