/**
* Copyright (c) 2013 - 2018, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/*
* Before compiling this example for NRF52, complete the following steps:
* - Download the S212 SoftDevice from thisisant.com.
* - Extract the downloaded zip file and copy the S212 SoftDevice headers to \/components/softdevice/s212/headers.
* If you are using Keil packs, copy the files into a @c headers folder in your example folder.
* - Make sure that @ref ANT_LICENSE_KEY in @c nrf_sdm.h is uncommented.
*/
#include "dfu.h"
#include "dfu_transport.h"
#include "bootloader.h"
#include "bootloader_util.h"
#include
#include
#include
#include "nordic_common.h"
#include "nrf.h"
#include "app_error.h"
#include "nrf_gpio.h"
#include "nrf_soc.h"
#include "nrf_delay.h"
#include "ant_interface.h"
#include "ant_parameters.h"
#include "ant_error.h"
#include "nrf.h"
#include "app_scheduler.h"
#include "app_timer.h"
#include "nrf_error.h"
#include "boards.h"
#include "nrf_sdh.h"
#include "nrf_sdh_ant.h"
#include "ant_boot_settings_api.h"
#include "antfs_ota.h"
#if !defined (S210_V3_STACK)
#include "nrf_mbr.h"
#endif // !S210_V3_STACK
#include "debug_pin.h"
#define ENABLE_BUTTON // include button detection
//#define ENABLE_IO_LED // include LED status on N5DK1 i/o board
#if defined (ENABLE_BUTTON)
#if defined (BOARD_N5DK1)
#define BOOTLOADER_BUTTON_PIN BUTTON_D /**< Button used to enter SW update mode. */
#else
#define BOOTLOADER_BUTTON_PIN BUTTON_1 /**< Button used to enter SW update mode. */
#endif
#endif
#if defined (ENABLE_IO_LED)
#define BOOTLOADER_ERROR_LED LED_C /**< N5DK Leds, set=led off, clr=led on */
#define BOOTLOADER_ACTIVE_LED LED_D
#endif // ENABLE_IO_LED
#define SCHED_MAX_EVENT_DATA_SIZE NRF_SDH_ANT_EVT_BUF_SIZE /**< Maximum size of scheduler events. */
#define SCHED_QUEUE_SIZE 20 /**< Maximum number of events in the scheduler queue. */
/**@brief Function for error handling, which is called when an error has occurred.
*
* @warning This handler is an example only and does not fit a final product. You need to analyze
* how your product is supposed to react in case of error.
*
* @param[in] error_code Error code supplied to the handler.
* @param[in] line_num Line number where the handler is called.
* @param[in] p_file_name Pointer to the file name.
*/
#if defined (DEBUG_DFU_BOOTLOADER)
uint32_t error_code_;
uint32_t line_num_;
const uint8_t * p_file_name_;
#endif // DEBUG_DFU_BOOTLOADER
void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info)
{
#if defined (DEBUG_DFU_BOOTLOADER)
app_error_save_and_stop(id, pc, info);
#endif // DEBUG_DFU_BOOTLOADER
#if defined (ENABLE_IO_LED)
// nrf_gpio_pin_set(BOOTLOADER_ERROR_LED);
#endif // ENABLE_IO_LED
// This call can be used for debug purposes during application development.
// On assert, the system can only recover on reset.
NVIC_SystemReset();
}
void HardFault_Handler(uint32_t ulProgramCounter, uint32_t ulLinkRegister)
{
(void)ulProgramCounter;
(void)ulLinkRegister;
NVIC_SystemReset();
}
/**@brief Callback function for asserts in the SoftDevice.
*
* @details This function will be called in case of an assert in the SoftDevice.
*
* @warning This handler is an example only and does not fit a final product. You need to analyze
* how your product is supposed to react in case of Assert.
* @warning On assert from the SoftDevice, the system can only recover on reset.
*
* @param[in] line_num Line number of the failing ASSERT call.
* @param[in] file_name File name of the failing ASSERT call.
*/
void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name)
{
app_error_handler(0xDEADBEEF, line_num, p_file_name);
}
#if defined (ENABLE_IO_LED)
/**@brief Function for initialization of LEDs.
*
* @details Initializes all LEDs used by the application.
*/
static void leds_init(void)
{
nrf_gpio_cfg_output(LED_A);
nrf_gpio_cfg_output(LED_B);
nrf_gpio_cfg_output(LED_C);
nrf_gpio_cfg_output(LED_D);
// turn on all leds
nrf_gpio_pin_clear(LED_A);
nrf_gpio_pin_clear(LED_B);
nrf_gpio_pin_clear(LED_C);
nrf_gpio_pin_clear(LED_D);
}
#endif // ENABLE_IO_LED
#if defined (ENABLE_IO_LED)
/**@brief Function for clearing the LEDs.
*
* @details Clears all LEDs used by the application.
*/
static void leds_off(void)
{
nrf_gpio_pin_set(LED_A); // unused
nrf_gpio_pin_set(LED_B); // unused
nrf_gpio_pin_set(LED_C);
nrf_gpio_pin_set(LED_D);
}
#endif // ENABLE_IO_LED
/**@brief Function for the Timer initialization.
*
* @details Initializes the timer module.
*/
static void timers_init(void)
{
ret_code_t err_code = app_timer_init();
APP_ERROR_CHECK(err_code);
}
#if defined (ENABLE_BUTTON)
/**@brief Function for initializing the button module.
*/
static void buttons_init(void)
{
nrf_gpio_cfg_sense_input(BOOTLOADER_BUTTON_PIN,
BUTTON_PULL,
NRF_GPIO_PIN_SENSE_LOW);
}
#endif // ENABLE_BUTTON
/**@brief Function for initializing the ANT stack. */
static void ant_stack_init(void)
{
ret_code_t err_code;
err_code = nrf_sdh_enable_request();
APP_ERROR_CHECK(err_code);
// Enable ANT stack.
err_code = nrf_sdh_ant_enable();
APP_ERROR_CHECK(err_code);
}
/**@brief Function for event scheduler initialization.
*/
static void scheduler_init(void)
{
APP_SCHED_INIT(SCHED_MAX_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE);
}
static uint32_t enter_boot_get (void )
{
uint32_t val = PARAM_FLAGS_ENTER_BOOT_BypassInit;
if (((*ANT_BOOT_PARAM_FLAGS & PARAM_FLAGS_PARAM_VALID_Msk) >> PARAM_FLAGS_PARAM_VALID_Pos) == PARAM_FLAGS_PARAM_VALID_True )
{
val = (*ANT_BOOT_PARAM_FLAGS & PARAM_FLAGS_ENTER_BOOT_Msk) >> PARAM_FLAGS_ENTER_BOOT_Pos;
}
return val;
}
static void enter_boot_set (uint32_t value)
{
uint32_t ant_boot_param_flags = *ANT_BOOT_PARAM_FLAGS;
uint32_t enter_boot = (ant_boot_param_flags >> PARAM_FLAGS_ENTER_BOOT_Pos) & PARAM_FLAGS_ENTER_BOOT_Msk;
if (enter_boot == value)
{
return; // no need to rewrite the same value.
}
ant_boot_param_flags &= ~PARAM_FLAGS_ENTER_BOOT_Msk;
ant_boot_param_flags |= value << PARAM_FLAGS_ENTER_BOOT_Pos;
uint32_t err_code = blocking_flash_word_write(ANT_BOOT_PARAM_FLAGS, ant_boot_param_flags);
APP_ERROR_CHECK(err_code);
}
static void enter_boot_update (void)
{
const bootloader_settings_t * p_bootloader_settings;
bootloader_util_settings_get(&p_bootloader_settings);
if (p_bootloader_settings->ap_image.st.bank == NEW_IMAGE_BANK_0 || p_bootloader_settings->ap_image.st.bank == NEW_IMAGE_BANK_1)
{
enter_boot_set(PARAM_FLAGS_ENTER_BOOT_BypassDone);
}
else
{
if (p_bootloader_settings->valid_app != BOOTLOADER_SETTINGS_INVALID_APPLICATION)
{
enter_boot_set(PARAM_FLAGS_ENTER_BOOT_BypassDone);
return;
}
enter_boot_set(PARAM_FLAGS_ENTER_BOOT_EnterBoot);
}
// If the current application has been invalidated, then application's self protection is of no use now.
// Lets clear it.
if (p_bootloader_settings->valid_app == BOOTLOADER_SETTINGS_INVALID_APPLICATION)
{
if (*ANT_BOOT_APP_SIZE != APP_SIZE_Empty)
{
uint32_t err_code = blocking_flash_word_write(ANT_BOOT_APP_SIZE, APP_SIZE_Clear);
APP_ERROR_CHECK(err_code);
}
}
}
/**@brief Function for application main entry.
*/
int main(void)
{
uint32_t err_code;
bool bootloader_is_pushed = false;
#if defined (ENABLE_IO_LED)
leds_init();
#endif // ENABLE_IO_LED
#if defined (ENABLE_BUTTON)
buttons_init();
#endif
#if defined (DEBUG_DFU_BOOTLOADER)
NRF_GPIO->DIRSET = 0x40000908; //stack debugging
DBG_PIN_DIR_INIT;
#endif //DEBUG_DFU_BOOTLOADER
#if defined (DBG_DFU_BOOTLOADER_PATH)
DEBUG_PIN_FALL(DBG_DFU_BOOTLOADER_PATH);
#endif //DBG_DFU_BOOTLOADER_PATH
// This check ensures that the defined fields in the bootloader corresponds with actual
// setting in the chip.
APP_ERROR_CHECK_BOOL(*((uint32_t *)NRF_UICR_BOOT_START_ADDRESS) == BOOTLOADER_REGION_START);
APP_ERROR_CHECK_BOOL(NRF_FICR->CODEPAGESIZE == CODE_PAGE_SIZE);
#if !defined (S210_V3_STACK)
sd_mbr_command_t com = {SD_MBR_COMMAND_INIT_SD, };
err_code = sd_mbr_command(&com);
APP_ERROR_CHECK(err_code);
err_code = sd_softdevice_vector_table_base_set(BOOTLOADER_REGION_START);
APP_ERROR_CHECK(err_code);
err_code = bootloader_dfu_sd_update_continue();
APP_ERROR_CHECK(err_code);
err_code = bootloader_dfu_bl_update_continue();
APP_ERROR_CHECK(err_code);
#endif // !S210_V3_STACK
// Initialize.
timers_init();
(void)bootloader_init();
ant_stack_init();
scheduler_init();
#if defined (ENABLE_BUTTON)
// Push button switch
bootloader_is_pushed = ((nrf_gpio_pin_read(BOOTLOADER_BUTTON_PIN) == 0) ? true: false);
if (bootloader_is_pushed)
{
enter_boot_set(PARAM_FLAGS_ENTER_BOOT_EnterBoot);
}
#endif // ENABLE_BUTTON
if ((enter_boot_get() == PARAM_FLAGS_ENTER_BOOT_EnterBoot) ||
(bootloader_is_pushed) ||
(!bootloader_app_is_valid(DFU_BANK_0_REGION_START)))
{
#if defined (DBG_DFU_BOOTLOADER_PATH)
DEBUG_PIN_FALL(DBG_DFU_BOOTLOADER_PATH);DEBUG_PIN_FALL(DBG_DFU_BOOTLOADER_PATH);
#endif //DBG_DFU_BOOTLOADER_PATH
#if defined (ENABLE_IO_LED)
leds_off();
nrf_gpio_pin_clear(BOOTLOADER_ACTIVE_LED);
#endif // ENABLE_IO_LED
// Initiate an update of the firmware.
err_code = bootloader_dfu_start();
APP_ERROR_CHECK(err_code);
enter_boot_update();
}
#if defined (ENABLE_IO_LED)
leds_off();
#endif // ENABLE_IO_LED
err_code = bootloader_dfu_ap_update_continue();
APP_ERROR_CHECK(err_code);
if (bootloader_app_is_valid(DFU_BANK_0_REGION_START))
{
#if defined (DBG_DFU_BOOTLOADER_PATH)
DEBUG_PIN_FALL(DBG_DFU_BOOTLOADER_PATH);DEBUG_PIN_FALL(DBG_DFU_BOOTLOADER_PATH);DEBUG_PIN_FALL(DBG_DFU_BOOTLOADER_PATH);
#endif //DBG_DFU_BOOTLOADER_PATH
// Select a bank region to use as application region.
// @note: Only applications running from DFU_BANK_0_REGION_START is supported.
bootloader_app_start(DFU_BANK_0_REGION_START);
}
#if defined (DBG_DFU_BOOTLOADER_PATH)
DEBUG_PIN_FALL(DBG_DFU_BOOTLOADER_PATH);DEBUG_PIN_FALL(DBG_DFU_BOOTLOADER_PATH);DEBUG_PIN_FALL(DBG_DFU_BOOTLOADER_PATH);DEBUG_PIN_FALL(DBG_DFU_BOOTLOADER_PATH);
#endif //DBG_DFU_BOOTLOADER_PATH
NVIC_SystemReset();
}