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)
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
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 .#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; }
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
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.