nRF芯片設(shè)備DFU升級

前言

  • 這里主要參考這個項目:iOS-nRF-Toolbox(這個是Swift版的),它是Nordic公司開發(fā)的測試工程铆遭,包含一整套nRF設(shè)備的測試解決方案

  • OC版的可以參考這個項目:nRF-Toolbox-master 密碼: w7kd

nRF-Toolbox項目包含BGM屉来,HRM走越,HTM浩淘,DFU等多個模塊痘绎,我們只用到了其中的DFU升級模塊泉哈。打開項目蛉幸,在對應(yīng)的NORDFUViewController.swift中我們能夠看到有三個引用庫:
import UIKit,import CoreBluetooth,import iOSDFULibrary,這里的iOSDFULibrary就是DFU升級的庫丛晦,也是解決DFU升級最重要的組件奕纫。我們只要把這個庫集成到我們的項目中,就能夠完成nRF設(shè)備的DFU升級了烫沙。

下面是對于OC引用DFU升級的操作步驟和我遇到的問題(使用的是藍牙連接升級)匹层。

集成iOSDFULibrary

我這里使用的是直接把庫導(dǎo)入到項目里面。(最好還是用cocoaPod導(dǎo)入锌蓄,不過好像會出現(xiàn)很多問題升筏,我這里還沒試過)

編譯出framework然后把庫導(dǎo)入項目
  • 這一步是最關(guān)鍵也是最容易出問題的,這個庫也是由Swift寫成的瘸爽,直接打開項目您访,然后選擇iOSDFULibrary進行編譯
編譯iOSDFULibrary.png

最后生成兩個framework:

  • iOSDFULibrary.framework
  • Zip.framework

編譯完成后,這兩個文件在項目下面:pod-->products文件夾剪决,右鍵在find里就可找到灵汪,直接放到你項目里面去就OK了。

導(dǎo)入到項目里面去了之后柑潦,更改一下項目配置:

在設(shè)置里面導(dǎo)入庫文件.png
Swift標準.png

把RunPath這里設(shè)置加一項:@executable_path/Frameworks


runpath.png

這時候在項目里面用頭文件就可以使用庫了:

#import <iOSDFULibrary/iOSDFULibrary-Swift.h>

運行程序享言,如果報錯如下:

dyld: Library not loaded: @rpath/libswiftCore.dylib
Referenced from: /private/var/containers/Bundle/Application/02516D79-BB30-4278-81B8-3F86BF2AE2A7/XingtelBLE.app/Frameworks/iOSDFULibrary.framework/iOSDFULibrary
Reason: image not found 

[dyld: Library not loaded: @rpath/libswiftCore.dylib報錯解決]

embed

這個默認設(shè)置是NO,設(shè)置為YES就可以了!!!

還有一種錯誤就是運行的時候,一直崩在這個地方

//這里一直崩潰妒茬,Message from debugger: Terminated due to signal 9
//如果出現(xiàn)這種錯誤担锤,你用他們demo跑的時候,有可能也會出現(xiàn)這個問題
//這里報錯就是編譯的庫有問題乍钻,重新?lián)Q庫肛循,使用carthage可以打包的庫可以解決這個問題
DFUFirmware *selectedFirmware = [[DFUFirmware alloc] initWithUrlToZipFile:url];

那一般情況是你編譯的包有問題。下面提供2種重新打包的方法银择,可以嘗試一下:

  • 1 直接是用作者提供的解決方法

1多糠、On your mac please install carthage (instructions)
2、Create a file named cartfile anywhere on your computer
3浩考、add the following content to the file:

github "NordicSemiconductor/IOS-Pods-DFU-Library" ~> 2.1.2
github "marmelroy/Zip" ~> 0.6

1夹孔、Open a new terminal and cd to the directory where the file is
2、Enter the command carthage update --platform iOS
3、Carthage will now take care of building your frameworks, the produced .framework files will be found in a newly created directory called Carthage/Build/iOS,copy over iOSDFULibrary.framework and Zip.framework to your project and you are good to go.

注意

a. carthage是一種和cocoapods相似的的類庫管理工具搭伤,如果不會使用的話可以參照carthage的使用只怎,將framework文件導(dǎo)入到自己的項目。

b. 用這個方法導(dǎo)出的庫怜俐,在你的電腦上跑是正確的身堡,在你同事的電腦上跑可能就不行了~~~

  • 2在使用我上面的用Demo代碼編譯的方法的時候,做一些針對性的改變拍鲤。
調(diào)整打包設(shè)置.png

附加一些另外的解決方法:

  • 把target -- > General -- > 下面的Linked Frameworks and Libraries下面的IOSDFULibrary和Zip兩個庫的右邊的status改成options試試贴谎。
  • 把RunPath里面的@executable_path/Frameworks刪了再重新添加的試試

打包上架時報ERROR IT MS-90087等問題

ERROR ITMS-90087: "Unsupported Architectures. The executable for ***.app/Frameworks/SDK.framework contains unsupported architectures '[x86_64, i386]'."
ERROR ITMS-90362: "Invalid Info.plist value. The value for the key 'MinimumOSVersion' in bundle ***.app/Frameworks/SDK.framework is invalid. The minimum value is 8.0"
ERROR ITMS-90209: "Invalid Segment Alignment. The app binary at '***.app/Frameworks/SDK.framework/SDK' does not have proper segment alignment. Try rebuilding the app with the latest Xcode version."
ERROR ITMS-90125: "The binary is invalid. The encryption info in the LC_ENCRYPTION_INFO load command is either missing or invalid, or the binary is already encrypted. This binary does not seem to have been built with Apple's linker."

解決方法,添加Run Script Phase


上架報錯.png

Shell腳本內(nèi)容填寫如下內(nèi)容季稳,再次編譯即可

 APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"

# This script loops through the frameworks embedded in the application and
# removes unused architectures.
find "$APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK
do
FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
    FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
echo "Executable is $FRAMEWORK_EXECUTABLE_PATH"

EXTRACTED_ARCHS=()

for ARCH in $ARCHS
do
echo "Extracting $ARCH from   $FRAMEWORK_EXECUTABLE_NAME"
lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH"
EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH")
done

echo "Merging extracted architectures: ${ARCHS}"
lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[@]}"
rm "${EXTRACTED_ARCHS[@]}"

echo "Replacing original executable with thinned version"
rm "$FRAMEWORK_EXECUTABLE_PATH"
mv "$FRAMEWORK_EXECUTABLE_PATH-merged"   "$FRAMEWORK_EXECUTABLE_PATH"

done
上面的是集成IOSDFULibrary時遇到的一些問題擅这,解決這些問題后就可以正常進行固件升級了。

下面了解一下使用這個庫來進行固件升級景鼠。

步驟:

  • 一仲翎、連接藍牙,發(fā)送指令對藍牙設(shè)備進行控制
  • 二铛漓、發(fā)送指令查詢固件版本
  • 三谭确、收到藍牙發(fā)回來的應(yīng)答,判斷是否進行版本升級
  • 四票渠、發(fā)送藍牙升級指令(此時藍牙會進入Dfu模式,此時藍牙名稱會改變芬迄,設(shè)備會斷開藍牙連接问顷,需要重新連接藍牙)
  • 五、重新連接改名后的藍牙禀梳,下載固件版本到本地
  • 六杜窄、使用IOSDFULibrary發(fā)送估計到藍牙進行升級
  • 七、發(fā)送成功算途,固件升級成功~~~
  • 八塞耕、估計升級完成之后,藍牙會回到正常模式嘴瓤,名稱改成之前的名稱扫外,設(shè)備會斷開藍牙,重新掃描藍牙連接即可
  • 九廓脆、大功告成

下面是對IOSDFULibrary的使用:

導(dǎo)入三個delegate:LoggerDelegate筛谚、DFUServiceDelegateDFUProgressDelegate,它們的作用分別為打印狀態(tài)日志停忿,DFU升級及藍牙連接狀態(tài),驾讲,監(jiān)視DFU升級進度。

//DFU
@property (strong, nonatomic) DFUServiceController *dfuService;
@property (strong, nonatomic) DFUFirmware *selectedFirmware;


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions     {
    // Override point for customization after application launch.

    //在AppDelegate里面要設(shè)置這些默認的屬性,否則文件傳輸會失敗吮铭,直接報operation not  permitted或者Sending firwmare failed
    //注意這里的 [NSNumber numberWithInt:12]时迫,如果是iPhone8或以上,如果設(shè)置為12以上就會崩潰谓晌,最大為6
    NSDictionary* defaults = [NSDictionary dictionaryWithObjects:@[@"2.3", [NSNumber numberWithInt:12], @NO] forKeys:@[@"key_diameter", @"dfu_number_of_packets", @"dfu_force_dfu"]];
    [[NSUserDefaults standardUserDefaults] registerDefaults:defaults];

    return YES;
}

- (void)performDFU
{
    // To start the DFU operation the DFUServiceInitiator must be used
    DFUServiceInitiator *initiator = [[DFUServiceInitiator alloc] initWithCentralManager: self.manager target:_val_peripheral];
    //注意這里要在AppDelegate里面設(shè)置
    initiator.forceDfu = [[[NSUserDefaults standardUserDefaults] valueForKey:@"dfu_force_dfu"] boolValue];
    //注意這里要在AppDelegate里面設(shè)置
    initiator.packetReceiptNotificationParameter = [[[NSUserDefaults standardUserDefaults] valueForKey:@"dfu_number_of_packets"] intValue];
    initiator.enableUnsafeExperimentalButtonlessServiceInSecureDfu = YES;
    initiator.logger = self;
    initiator.delegate = self;
    initiator.progressDelegate = self;
    //下載網(wǎng)絡(luò)文件升級
    NSString *firmwaresPath = [[verManager getFirmwaresPath] stringByAppendingPathComponent:@"firmWareVersion.zip"];
    NSURL *url = [NSURL fileURLWithPath:firmwaresPath];
    _selectedFirmware = [[DFUFirmware alloc] initWithUrlToZipFile:url];
    //本地zip文件升級
    //NSURL *filePath = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"app_only.zip" ofType:nil]];
    //_selectedFirmware = [[DFUFirmware alloc] initWithUrlToZipFile:filePath];
    //開始發(fā)送文件  如果這里沒有文件會報錯:Firmare  not  specified
    _dfuService = [[initiator withFirmware:_selectedFirmware] start];     
}


#pragma mark - LoggerDelegate
-(void)logWith:(enum LogLevel)level message:(NSString *)message
{
    NSLog(@"%ld: %@", (long) level, message);
}


#pragma mark - DFUServiceDelegate
//監(jiān)聽狀態(tài)
- (void)dfuStateDidChangeTo:(enum DFUState)state
{
    switch (state) {
        case DFUStateConnecting:
             NSLog(@"Connecting...");
             break;
        case DFUStateStarting:
             NSLog(@"Starting...");
             break;
        case DFUStateEnablingDfuMode:
             NSLog(@"EnablingDfuMode...");
             break;
        case DFUStateUploading:
             NSLog(@"Uploading...");
             break;
        case DFUStateValidating:
             NSLog(@"Validating...");
             break;
        case DFUStateDisconnecting:
             NSLog(@"Disconnecting...");
             break;
        case DFUStateCompleted:
        {
            //升級成功   Upload complete
            //重新連接藍牙
            self.manager = nil;
            //初始化并設(shè)置委托和線程隊列
            //重新給藍牙連接Manager賦值掠拳,不然有可能升級后連接不上藍牙
            self.manager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue() options:@{CBCentralManagerOptionShowPowerAlertKey:[NSNumber numberWithBool:NO]}];
            break;
        }
        case DFUStateAborted:
            NSLog(@"Aborted...");
            break;
        default:
            break;
    }
}

- (void)dfuError:(enum DFUError)error didOccurWithMessage:(NSString * _Nonnull)message
{
    NSLog(@"Error %ld: %@", (long) error, message);
}



#pragma mark - DFUProgressDelegate
//進度
- (void)dfuProgressDidChangeFor:(NSInteger)part outOf:(NSInteger)totalParts to:(NSInteger)progresscurrentSpeedBytesPerSecond:(double)currentSpeedBytesPerSecond avgSpeedBytesPerSecond:(double)avgSpeedBytesPerSecond;
{
    [SVProgressHUD showProgress:(float) progress / 100.0f status:[NSString stringWithFormat:@"升級固件中%ld%%",(long)progress]];
//    progress.progress = (float) percentage / 100.0f;
//    progressLabel.text = [NSString stringWithFormat:@"%ld%% (%ld/%ld)", (long) percentage, (long) part, (long) totalParts];
}

補充:

后面在測試的時候發(fā)現(xiàn):1. 第一次運行程序,升級的時候會出現(xiàn)崩潰扎谎。崩潰的位置:

第一次運行升級崩潰在庫里.png

解決方案:
崩潰的原因是firmwareRanges是nil碳想,在前面添加代碼進行判斷就行了:

if firmwareRanges == nil {
    // Split firmware into smaller object of at most maxLen bytes, if firmware is bigger than maxLen
    return
}
解決崩潰.png

注意

改代碼的時候,不能直接改項目里面崩潰的那個位置的代碼毁靶,那里改了沒用胧奔,要改在編譯成庫的地方的代碼,然后重新編譯预吆,導(dǎo)出庫文件龙填,把庫文件重新加到項目里面。如果用的是carthage拐叉,使用流程如下:


打開項目
導(dǎo)出庫文件流程.png

重新導(dǎo)入包之后要更新一下項目配置岩遗,在Build Phases里面的Embed Frameworks里面把IOSDFULibrary庫加進了。這里不需要重新更換Zip庫凤瘦,只用更改IOSDFULibrary庫就OK~

注意:有朋友反映升級的時候會斷開連接宿礁,解決方法:
在APPDelegate文件里加上:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions     {
    // Override point for customization after application launch.

    //在AppDelegate里面要設(shè)置這些默認的屬性,否則文件傳輸會失敗蔬芥,直接報operation not  permitted或者Sending firwmare failed
    NSDictionary* defaults = [NSDictionary dictionaryWithObjects:@[@"2.3", [NSNumber numberWithInt:12], @NO] forKeys:@[@"key_diameter", @"dfu_number_of_packets", @"dfu_force_dfu"]];
    [[NSUserDefaults standardUserDefaults] registerDefaults:defaults];

    return YES;
}

有朋友@可樂超反映梆靖,寫了上面的代碼,在升級的時候還是會崩潰笔诵,斷開連接返吻。
原因是設(shè)置的packetReceiptNotificationParameter這個參數(shù)的值太大的原因。感謝@可樂超乎婿。
謝謝~

慢慢來测僵,一步一個巴掌印。谢翎。捍靠。。岳服。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末剂公,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子吊宋,更是在濱河造成了極大的恐慌纲辽,老刑警劉巖颜武,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異拖吼,居然都是意外死亡鳞上,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門吊档,熙熙樓的掌柜王于貴愁眉苦臉地迎上來篙议,“玉大人,你說我怎么就攤上這事怠硼」砑” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵香璃,是天一觀的道長这难。 經(jīng)常有香客問我,道長葡秒,這世上最難降的妖魔是什么姻乓? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮眯牧,結(jié)果婚禮上蹋岩,老公的妹妹穿的比我還像新娘。我一直安慰自己学少,他們只是感情好剪个,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著版确,像睡著了一般禁偎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上阀坏,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機與錄音笆檀,去河邊找鬼忌堂。 笑死,一個胖子當著我的面吹牛酗洒,可吹牛的內(nèi)容都是我干的士修。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼樱衷,長吁一口氣:“原來是場噩夢啊……” “哼棋嘲!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起矩桂,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤沸移,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體雹锣,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡网沾,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蕊爵。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片辉哥。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖攒射,靈堂內(nèi)的尸體忽然破棺而出醋旦,到底是詐尸還是另有隱情,我是刑警寧澤会放,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布饲齐,位于F島的核電站,受9級特大地震影響鸦概,放射性物質(zhì)發(fā)生泄漏箩张。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一窗市、第九天 我趴在偏房一處隱蔽的房頂上張望先慷。 院中可真熱鬧,春花似錦咨察、人聲如沸论熙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽脓诡。三九已至,卻和暖如春媒役,著一層夾襖步出監(jiān)牢的瞬間祝谚,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工酣衷, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留事期,地道東北人开呐。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓壳嚎,卻偏偏與公主長得像框舔,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子啊片,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345

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