2017年1月10日 星期二

nRF5x: How to Set Version Checking in the DFU Zip File

This article is to provide a security solution for DFU.

My application is based on Heart rate Service 
( s110 with dfu in Nordic SDK)

C:\..\..\..\nRF51_SDK_10.0.0\nRF51_SDK_10.0.0_dc26b5e\examples\ble_peripheral\ble_app_hrs

the firmware can check if the DFU .zip file is authorized by manifest.json 
(in.zip ,usually called INIT file in Nordic Website).

The PASSWORD could be set in the zip file parameters while packed, and you should modify the bootloader code, to consist with the parameters. 



step 0.my environment:

  • nRF51822DK xxac
  • softdevice s110 8.0.0
  • Keil_v5 
  • nrf SDK 10.0.0
  • bootloader_s110      <--will be changed by me in step 2
  • master control panel 3.10.0.8

  • Android 6.0.1
  • windows 7
  • nrf Connect (for android) <--download the latest version
  • Samsung J7 prime

step 1.set password in .zip file

There are 3 options to place my password: device version, device type and application version.



To simply my example, , I adopt the "application version" as my password column at first .

(About how to adopt device revision or device type ,see Note.3)


password :0x03734301

cd C:\Program Files (x86)\Nordic Semiconductor\Master Control Panel\3.10.0.14\nrf\
nrfutil.exe dfu genpkg --nRF51422_xxac_s110.bin --application-version 0x03734301 --dev-revision 0xFFFF --dev-type 0xFFFF --sd-req 0x4f,0x5a,0x64 app_version_password.zip


add the .zip file to smartphone

step 2.customized your bootloader

copy bootloader folder  from:
C:\\nRF51_SDK_10.0.0\nRF51_SDK_10.0.0_dc26b5e\examples\dfu\bootloader

rename it as bootloader_with_password

copy dfu_init_template.c from nRF51_SDK_10.0.0_dc26b5e\components\libraries\bootloader_dfu 

modift the project setting to depend on the dfu_init_template.c 
which be inside folder bootloader_with_password, instead of the one in components\libraries\bootloader_dfu .

In dfu_init_template.c

#include "dfu_init.h"
#include <stdint.h>
#include <string.h>
#include "dfu_types.h"
#include "nrf_error.h"
#include "crc16.h"

#define DFU_INIT_PACKET_EXT_LENGTH_MIN      2                       
#define DFU_INIT_PACKET_EXT_LENGTH_MAX      10                      

static uint8_t m_extended_packet[DFU_INIT_PACKET_EXT_LENGTH_MAX];   
static uint8_t m_extended_packet_length;                            

#define APP_VERSION_PASSWORD                  ((uint32_t)0x03734301)

uint32_t dfu_init_prevalidate(uint8_t * p_init_data, uint32_t init_data_len)
{
    uint32_t i = 0;
    
    
    if (init_data_len < sizeof(dfu_init_packet_t))
    {
        return NRF_ERROR_INVALID_LENGTH;
    }

    // Current template uses clear text data so they can be casted for pre-check.
    dfu_init_packet_t * p_init_packet = (dfu_init_packet_t *)p_init_data;

    m_extended_packet_length = ((uint32_t)p_init_data + init_data_len) -
                   (uint32_t)&p_init_packet->softdevice[p_init_packet->softdevice_len];
    
    if (m_extended_packet_length < DFU_INIT_PACKET_EXT_LENGTH_MIN)
    {
        return NRF_ERROR_INVALID_LENGTH;
    }

    if (((uint32_t)p_init_data + init_data_len) < 
        (uint32_t)&p_init_packet->softdevice[p_init_packet->softdevice_len])
    {
        return NRF_ERROR_INVALID_LENGTH;
    }

    memcpy(m_extended_packet,
           &p_init_packet->softdevice[p_init_packet->softdevice_len],
           m_extended_packet_length);

/** [DFU init application version] */
    // To support application versioning, this check should be updated.
    // This template allows for any application to be installed. However, 
    // customers can place a revision number at the bottom of the application 
    // to be verified by the bootloader. This can be done at a location 
    // relative to the application, for example the application start 
    // address + 0x0100.
/** [DFU init application version] */
    
    // First check to verify the image to be transfered matches the device type.
    // If no Device type is present in DFU_DEVICE_INFO then any image will be accepted.
  

    /*agatha: set application version check*/ 
    if ((p_init_packet->app_version!= APP_VERSION_PASSWORD))
    {
        return NRF_ERROR_INVALID_DATA;
    }/*app_version check*/ 
    
    //First check 
    if ((DFU_DEVICE_INFO->device_type != DFU_DEVICE_TYPE_EMPTY) &&
   (p_init_packet->device_type != DFU_DEVICE_INFO->device_type))
    {
        return NRF_ERROR_INVALID_DATA;
    }
   
    // Second check to verify the image to be transfered matches the device revision.
    
    if ((DFU_DEVICE_INFO->device_rev != DFU_DEVICE_REVISION_EMPTY) &&
        (p_init_packet->device_rev != DFU_DEVICE_INFO->device_rev))
    {
        return NRF_ERROR_INVALID_DATA;
    }

    // Third check: Check the array of supported SoftDevices by this application.
    // If the installed SoftDevice does not match any SoftDevice in the list then an
    // error is returned.
    while (i < p_init_packet->softdevice_len)
    {
        if (p_init_packet->softdevice[i] == DFU_SOFTDEVICE_ANY ||
            p_init_packet->softdevice[i++] == SOFTDEVICE_INFORMATION->firmware_id)
        {
            return NRF_SUCCESS;
        }
    }
    
    // No matching SoftDevice found - Return NRF_ERROR_INVALID_DATA.
    return NRF_ERROR_INVALID_DATA;
}


uint32_t dfu_init_postvalidate(uint8_t * p_image, uint32_t image_len)
{
    uint16_t image_crc;
    uint16_t received_crc;
    
    
    // calculate CRC from active block.
    image_crc = crc16_compute(p_image, image_len, NULL);

    // Decode the received CRC from extended data.    
    received_crc = uint16_decode((uint8_t *)&m_extended_packet[0]);

    // Compare the received and calculated CRC.
    if (image_crc != received_crc)
    {
        return NRF_ERROR_INVALID_DATA;
    }

    return NRF_SUCCESS;
}

The structure  p_init_packet  would pass the password from INIT file, in here, modify the code to check its value consisted with true password .

Rebuild bootloader.hex and application. Then use nRFgo Studio to program:
  • softdevice
  • application
  • bootloader (be changed by you)




step 3.test 


open Nordic nRF connecter app

connect your board

press the DFU button above

press "Distribution packet" and select the .zip file we made in STEP 1
start DFU
After DFU , reset the board

if you add the zip file that the parameter  --application-version is incorrect, your smartphone will soon disconnect to device .


Additional notes:


0. This implement check the number of application version to achieve "set a password to avoid unknown .zip file ".


1. In my experience,Samsung smartphone has a higher probability to DFU failed.

(whether using which smartphone app)

2. nRF connect ,the app I used , has some problem in DFU mode and connect the device after DFU. 


3. I suggest not to check dev_type and dev_rev,but use application version ,because application version isn't used in normal bootloader.


However, if you want to check device type, that is feasible :


add in bootloader
/*agatha: how to check  device type*/
#define DEV_TYPE_PASSWORD  0x1618  
  
   if ((p_init_packet->device_type != DEV_TYPE_PASSWORD))
    {
        return NRF_ERROR_INVALID_DATA;
    }
  
#if (0)
   
    if ((DFU_DEVICE_INFO->device_type != DFU_DEVICE_TYPE_EMPTY) &&
   (p_init_packet->device_type != DFU_DEVICE_INFO->device_type))
    {
        return NRF_ERROR_INVALID_DATA;
    }
#endif   
and make the .zip file


cd C:\Program Files (x86)\Nordic Semiconductor\Master Control Panel\3.10.0.14\nrf\
nrfutil.exe dfu genpkg --nRF51422_xxac_s110.bin --application-version 0x03734301 --dev-revision 0xFFFF --dev-type 0x1618 --sd-req 0x4f,0x5a,0x64 app_version_password.zip

you could adopt device_type and/or device_revision as further checking.


3. This method above can work in SDK11 , when the chip is nRF52 with softdevice s132.
But that can not be adopted to SDK12  and s232, s332. 



2017年1月6日 星期五

nRF51822 mergeHex 三合一量產用燒錄檔案

nRF51822 用 nRFgo studio 燒寫的時候需要三個 hex檔案,
(按燒寫順序)

  1. softdevice
  2. application
  3. bootloader


此三個hex可合併為一,用於量產較為方便,本篇介紹三合一hex檔案的製作方法


  • 官方流程(優點,可自定或製作批次檔,缺點,首次進行很慢)請依照step 進行下去
  • 簡化流程(優點,單次很快缺點無法自動化)請跳到 STEP 6


環境:

  • nRF51822EK
  • nRF Tools 7.5.2
  • Master Control Panel 3.10.0.4
  • Keil version 5
  • Windows 7
  • nordic SDK 10.0.0
  • softdevice s110 8.0.0
  • bootloader : dual bank s110 bootloader


STEP 0.找到

  1. sotfdevice 默認檔名 s110_nrf51_8.0.0_softdevice.hex
  2. application 默認路徑: project\pca10028\_build 選擇 .hex


STEP 1. 編譯 bootloader

bootloader 在SDK裡面並沒有.hex 要自己編

默認路徑:
C:\..\..\..\..\nRF51_SDK_10.0.0\nRF51_SDK_10.0.0_dc26b5e\examples\dfu\bootloader
點選dual_bank_ble_s110項目檔,按下build

在 \_build 產生 .hex檔案



STEP 2.找到此三 .hex 檔案,修改檔名為:

  • s110_SD.hex
  • bootloader.hex
  • application.hex

此動作是為了防止下一步搞錯,可自定名稱



STEP 3.將三個檔案複製到

C:\Program Files (x86)\Nordic Semiconductor\nrf5x\bin

確認該資料夾中有另三個檔案:


  • app_valid_setting_apply.hex
  • mergehex.exe
  • nrfproj.exe


如果沒有或不在資料夾內,請集中到此資料夾,或是重新安裝 nRF Tools


STEP 4. 開啟 command line 輸入


1
2
cd C:\Program Files (x86)\Nordic Semiconductor\nrf5x\bin  
mergehex -m s110_SD.hex bootloader.hex -o SD_BL.hex -m SD_BL.hex application.hex -o SD_BL_APP.hex -m SD_BL_APP.hex app_valid_setting_apply.hex -o SD_BL_APP_Settings.hex

資料夾中產生:

SD_BL_APP_Setting.hex 

是為三合一檔案


STEP 5 驗證三合一檔案是否正常運行

再次打開 command line 
(同時確認連上nRF51822與 JLink)

輸入:

1
2
cd  C:\Program Files (x86)\Nordic Semiconductor\nrf5x\bin
nrfjprog.exe --eraseall  --program SD_BL_APP_Settings.hex --pinreset

執行完畢後將蕊片重新上電,並確認各服務是否正常運行

_____________________________________________________________________________


STEP 6 快速方法: NRF_ISP

請點選下載 訊聯電子 NRF_ISP 軟件後安裝


  1. 按下browse 分別選擇 appliacation / softdevice/bootloader 檔案 
  2. 點選 merge
  3. 勾選 on/off  按下 configure
  4. 勾選 Downloader1 
  5. 按下 program


以上動作相當於取代nRFGO 分別燒寫的功能,
然後此時到\NRF_ISP 資料夾內,

點選 \_build 資料夾 內有一個最後產生的 hex檔案
即為三合一 hex

(更多資訊請洽訊聯電子,此軟件非nordic官方發布)


2017年1月5日 星期四

nRF51822 空中升級 .zip壓縮/製作

nRF51822 支援固件空中升級(下稱OTA)服務,本篇說明如何製作升級用 .zip 檔案

(關於什麼是DFU服務、如何添加,請參考以下)

第一次實作,請按照step慢慢做完
加速方法,請直接跳到 Step 5

環境:

  • 蕊片:nRF51822EK
  • bootloader: dual bank s110 bootloader
  • softdevice: s110
  • windows 7
  • IDE: Keil version 5
  • Master control panel (for PC) 3.10.0.14
  • nRF Tools 7.5.2
Step 0.被升級的裝置,必須燒寫與softdevice相同版本的 bootloader
如本次我使用的是 S110 

Step 1.在IDE裡面 build application,之後  \_build 會產生 .axf檔案
默認名稱: nrf51422_xxac_s110.axf 
(此名稱可在 project>options 裡面修改)

Step 2.將此 .axf檔案複製到 Keil_v5\ARM\ARMCC\bin資料夾
確認這個資料夾裡面有一個fromelf.exe

(如果是使用 Keil_v4 相同的執行檔是 hex2bin.exe)

Step 3. 打開Command line,輸入:

1
2
cd C:\Keil_v5\ARM\ARMCC\bin\      ::進入資料夾
fromelf.exe nRF51422_xxac_s110.axf --output nRF51422_xxac_s110.bin --bin --output nRF51422_xxac_s110.bin --bin

nRF51422_xxac_s110.axf 即 .axf 檔的名稱
nRF51422_xxac_s110.bin 可替換成其他自訂名稱

隨後資料夾內會產生 nRF51422_xxac_s110.bin檔案
複製此檔案到
C:\Program Files (x86)\Nordic Semiconductor\Master Control Panel\3.10.0.14\nrf\

step 4.此資料夾內有 nrfutil.exe,如果沒有,請重新安裝Master Control Panel 最新版本 
打開Command line, 輸入:

1
2
3
cd C:\Program Files (x86)\Nordic Semiconductor\Master Control Panel\3.10.0.14\nrf\

nrfutil.exe dfu genpkg --nRF51422_xxac_s110.bin --application-version 0xFFFFFFFF --dev-revision 0xFFFF --dev-type 0xFFFF --sd-req 0x4f,0x5a,0x64 nRF51422_xxac_s110.zip


(命令行中的參數,與 .zip內的 INIT file有關,可參閱)

Step 5.製作批次檔加速此流程

請先找到
  • nrf51422_xxac_s110.axf
  • fromelf.exe
  • nrfutil.exe
相對位置
Step 6.建立空白txt檔案

輸入:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
::分別可改為自定的檔案名稱
:: " "內輸入相對位置
SET zipName=nrf51422_xxac_s110
SET binName=nrf51422_xxac_s110

"C:\Keil_v5\ARM\ARMCC\bin\fromelf.exe" ..\pca10028\s110\arm5\_build\nrf51422_xxac_s110.axf  --output %binName%.bin --bin --output %binName%.bin --bin
"C:\Program Files (x86)\Nordic Semiconductor\Master Control Panel\3.10.0.14\nrf\nrfutil.exe" dfu genpkg --application %binName%.bin --application-version 0xFFFFFFFF --dev-revision 0xFFFF --dev-type 0xFFFF --sd-req 0x4f,0x5a,0x64 %zipName%.zip

SET zipName=
SET binName=
::歸零

Step 7.將txt的副檔名 改為.bat


Step 8. 將.zip 檔案放入DFU主機
(這邊介紹的是用Android市場  nrf Connect 應用程式升級,
另外MacBook 有支援用 Master Control Panel (for Mac) 進行空中升級,此不作討論)

點選 DFU 選項
Select File > .zip file> 選擇檔案