iOS藍(lán)牙空中(固件)升級(jí)實(shí)現(xiàn)

最近項(xiàng)目中有用到固件升級(jí)功能惹资,即使用手機(jī)去升級(jí)硬件設(shè)備的固件扼脐。
項(xiàng)目中硬件端使用的單片機(jī)程序是一個(gè) xxx.bin 文件纹腌,此文件從服務(wù)器下載獲取,然后通過藍(lán)牙發(fā)送至硬件端供單片機(jī)升級(jí)固件程序灸促。這里只介紹iOS端的實(shí)現(xiàn)诫欠。

一般與藍(lán)牙外設(shè)的數(shù)據(jù)交互都會(huì)自定義傳輸協(xié)議,我的項(xiàng)目中使用如下形式:

幀頭(1B) + 指令類型(1B) + 有效數(shù)據(jù)長(zhǎng)度(xxB) + 有效數(shù)據(jù)(1B) + 校驗(yàn)(1B) + 幀尾(1B)
其中有效數(shù)據(jù)長(zhǎng)度最大為:20B - 5B = 15B
此協(xié)議具體實(shí)現(xiàn)可由硬件工程師確定或者一起協(xié)商制定

下面介紹我的實(shí)現(xiàn)思路(此處使用上述協(xié)議浴栽,最大有效數(shù)據(jù)為15B):

1.從服務(wù)器端下載 xxx.bin 文件荒叼。
2.藍(lán)牙每次最多只能發(fā)送20字節(jié)數(shù)據(jù),因此需要將這個(gè) xxx.bin 文件拆分成N多個(gè)20字節(jié)的數(shù)據(jù)存于數(shù)組中典鸡。(因采用數(shù)據(jù)交互協(xié)議被廓,這里需要拆分成N多個(gè)15字節(jié),最后一個(gè)不滿15B的也需要插入?yún)f(xié)議數(shù)據(jù)幀中添加進(jìn)數(shù)組)椿每。
3.遍歷數(shù)組伊者,將拆分出來的數(shù)據(jù)挨個(gè)使用藍(lán)牙發(fā)送出去。
4.每次發(fā)送完一幀數(shù)據(jù)需要等硬件端回復(fù)確認(rèn)OK后再發(fā)送下一幀间护。
5.如果硬件端回復(fù)請(qǐng)求重發(fā)數(shù)據(jù),需要將剛剛發(fā)過去的那一幀數(shù)據(jù)重發(fā)一次挖诸。
6.直到硬件端正常接收完數(shù)據(jù)汁尺,回復(fù)數(shù)據(jù)接收完成指令,則可退出固件升級(jí)多律。

實(shí)現(xiàn)代碼:
1.處理固件包

#pragma mark - 處理固件包
- (void)dealFirmware:(NSData *)firmwareData{

    //開辟存數(shù)據(jù)的空間
    NSInteger dataLength = firmwareData.length;
    NSInteger dataPackageFrame = dataLength%Data2K? dataLength/Data2K+1 : dataLength/Data2K;
    
    NSMutableArray *dataPackageArray = [NSMutableArray arrayWithCapacity:dataPackageFrame];
    
    //將固件包按2K大小打散痴突,存于數(shù)組中
    for (NSInteger i = 0; i < dataPackageFrame; i++) {
        
        if (i < dataPackageFrame-1){
            NSData *subData = [firmwareData subdataWithRange:NSMakeRange(Data2K * i, Data2K)];
            [dataPackageArray addObject:subData];
        }
        else if (i == dataPackageFrame-1) {
            NSData *subData = [firmwareData subdataWithRange:NSMakeRange(Data2K * i, dataLength - Data2K*i)];
            [dataPackageArray addObject:subData];
        }
    }
    
    //遍歷2K固件包
    NSInteger totalDataFrame = 0;
    
    for (NSInteger full = 0; full < dataPackageArray.count; full++)
    {
        //        NSLog(@"第%ld包數(shù)據(jù)%ld字節(jié): --- > %@\n",full+1,((NSData*)dataPackageArray[full]).length,dataPackageArray[full]);
        
        //滿的2K包
        if (full < dataPackageArray.count - 1)
        {
            NSData *packageData = dataPackageArray[full];
            NSInteger fullPackageFrame = Data2K%DataFrameSize? Data2K/DataFrameSize + 1 : Data2K/DataFrameSize; //計(jì)算出需要拆分成多少幀(2K)
            totalDataFrame += fullPackageFrame;
            
            for (NSInteger fullUnit = 0; fullUnit < fullPackageFrame; fullUnit++) {
                
                if (fullUnit < fullPackageFrame-1){
                    NSData *subData = [packageData subdataWithRange:NSMakeRange(DataFrameSize * fullUnit, DataFrameSize)];
                    [_dataFrameArray addObject:subData];
                }
                else if (fullUnit == fullPackageFrame-1) {
                    NSData *subData = [packageData subdataWithRange:NSMakeRange(DataFrameSize * fullUnit, Data2K - DataFrameSize*fullUnit)];
                    [_dataFrameArray addObject:subData];
                }
            }
            
        }
        
        //余的2K包
        else if (full == dataPackageArray.count - 1)//最后一包
        {
            NSData *remainderData = dataPackageArray[full];
            NSInteger remainderDataLength = remainderData.length;
            
            NSInteger remainderPackageFrame = remainderDataLength%DataFrameSize? remainderDataLength/DataFrameSize + 1 : remainderDataLength/DataFrameSize; //計(jì)算出需要拆分成多少幀(剩余的)
            totalDataFrame += remainderPackageFrame;
            
            for (NSInteger i = 0; i < remainderPackageFrame; i++) {
                
                if (i < remainderPackageFrame-1){
                    NSData *subData = [remainderData subdataWithRange:NSMakeRange(DataFrameSize * i, DataFrameSize)];
                    [_dataFrameArray addObject:subData];
                }
                else if (i == remainderPackageFrame-1) {
                    NSData *subData = [remainderData subdataWithRange:NSMakeRange(DataFrameSize * i, remainderDataLength - DataFrameSize*i)];
                    [_dataFrameArray addObject:subData];
                }
            }
            
        }
        
    }
    
    //已計(jì)算出拆包數(shù)量
//    JCLog(@"**%@**",firmwareData);
//    JCLog(@"**totalFrame:%ld**",totalDataFrame);
//    for (NSInteger i = 0; i < _dataFrameArray.count; i++) {
//        NSLog(@"待發(fā)數(shù)據(jù): **%ld**  --- > %@\n",i,_dataFrameArray[i]);
//    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末搂蜓,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子辽装,更是在濱河造成了極大的恐慌帮碰,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拾积,死亡現(xiàn)場(chǎng)離奇詭異殉挽,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)拓巧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門斯碌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人肛度,你說我怎么就攤上這事傻唾。” “怎么了承耿?”我有些...
    開封第一講書人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵冠骄,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我加袋,道長(zhǎng)猴抹,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任锁荔,我火速辦了婚禮蟀给,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘阳堕。我一直安慰自己跋理,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開白布恬总。 她就那樣靜靜地躺著前普,像睡著了一般。 火紅的嫁衣襯著肌膚如雪壹堰。 梳的紋絲不亂的頭發(fā)上拭卿,一...
    開封第一講書人閱讀 51,754評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音贱纠,去河邊找鬼峻厚。 笑死,一個(gè)胖子當(dāng)著我的面吹牛谆焊,可吹牛的內(nèi)容都是我干的惠桃。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼辜王!你這毒婦竟也來了劈狐?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤呐馆,失蹤者是張志新(化名)和其女友劉穎肥缔,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體汹来,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡续膳,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了俗慈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片姑宽。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖闺阱,靈堂內(nèi)的尸體忽然破棺而出炮车,到底是詐尸還是另有隱情,我是刑警寧澤酣溃,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布瘦穆,位于F島的核電站,受9級(jí)特大地震影響赊豌,放射性物質(zhì)發(fā)生泄漏扛或。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一碘饼、第九天 我趴在偏房一處隱蔽的房頂上張望熙兔。 院中可真熱鬧,春花似錦艾恼、人聲如沸住涉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽舆声。三九已至,卻和暖如春柳爽,著一層夾襖步出監(jiān)牢的瞬間媳握,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工磷脯, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蛾找,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓争拐,卻偏偏與公主長(zhǎng)得像腋粥,于是被迫代替她去往敵國(guó)和親晦雨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子架曹,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,185評(píng)論 25 707
  • Guide to BluetoothSecurity原文 本出版物可免費(fèi)從以下網(wǎng)址獲得:https://doi.o...
    公子小水閱讀 8,001評(píng)論 0 6
  • 藍(lán)牙簡(jiǎn)介 藍(lán)牙( Bluetooth? ):是一種無線技術(shù)標(biāo)準(zhǔn)隘冲,可實(shí)現(xiàn)固定設(shè)備、移動(dòng)設(shè)備和樓宇個(gè)人域網(wǎng)之間的短距離...
    Chefil閱讀 2,044評(píng)論 2 19
  • 夜蕭巫峽口绑雄, 江平文峰瘦展辞。 冷眼看浮云, 腸斷誰人懂万牺?
    凡間客閱讀 121評(píng)論 0 1
  • 今天去一個(gè)拉丁舞學(xué)校罗珍。舞蹈室里只有四位學(xué)生。有一個(gè)讀高三學(xué)舞蹈的蘿莉脚粟,蘿莉18歲覆旱,瘦瘦高高,藍(lán)色寬敞的毛衣難掩身段...
    嘉浠閱讀 180評(píng)論 0 0