├── CMakeLists.txt ├── README.md ├── app_common ├── app_button.c ├── app_uart.c ├── hci_slip.c └── hci_transport.c ├── app_timer.c ├── app_timer.h ├── app_timer_appsh.c ├── app_timer_appsh.h ├── bootloader.c ├── bootloader.sct ├── bootloader_settings_arm.c ├── dfu_ble_svc.c ├── dfu_dual_bank.c ├── dfu_transport_ble.c ├── include ├── bootloader_settings.h └── pstorage_platform.h ├── main.c └── startup └── arm_startup_nrf51.s /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # 2 | # CMake configuration 3 | # 4 | # Please refer to http://www.cmake.org/cmake/help/documentation.html 5 | # You may also refer to http://www.cmake.org/cmake/help/syntax.html for a quick 6 | # introduction to CMake's syntax. 7 | 8 | cmake_minimum_required (VERSION 2.8) 9 | 10 | # The name of our project is "BLE_BOOTLOADER". CMakeLists files in this project can 11 | # refer to the root source directory of the project as ${BLE_BOOTLOADER_SOURCE_DIR} 12 | # and to the root binary directory of the project as ${BLE_BOOTLOADER_BINARY_DIR}. 13 | project (BLE_BOOTLOADER) 14 | 15 | # define some more paths to projects we depend on 16 | set(MBED_SRC_PATH ${BLE_BOOTLOADER_SOURCE_DIR}/mbed/libraries/mbed/ 17 | CACHE DIRECTORY "MBED SDK path") 18 | set(BLE_API_SRC_PATH ${BLE_BOOTLOADER_SOURCE_DIR}/BLE_API/ 19 | CACHE DIRECTORY "BLE API path") 20 | set(NRF51822_SRC_PATH ${BLE_BOOTLOADER_SOURCE_DIR}/nRF51822/ 21 | CACHE DIRECTORY "nRF51822 API path") 22 | set(APP_PATH ${BLE_BOOTLOADER_SOURCE_DIR}/DefaultApp.hex 23 | CACHE FILE "Default application to bundle with the bootloader") 24 | 25 | set(SOFT_DEVICE ${MBED_SRC_PATH}/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/Lib/s130_nrf51822_1_0_0/s130_nrf51_1.0.0_softdevice.hex) 26 | set(PLATFORM HRM1017 27 | CACHE DIRECTORY "Target platform (NRF51822, ARCH_BLE, HRM1017...)") 28 | set(BOARD ${PLATFORM} 29 | CACHE DIRECTORY "Target board (NRF51822_MKIT, ARCH_BLE, HRM1017...)") 30 | 31 | set(TOOLCHAIN_SYSROOT /usr/local/ 32 | CACHE DIRECTORY "Path to an ARM toolchain") # potential setting for TOOLCHAIN_SYSROOT: ~/ext/arm-toolchains/rvct/ARMCompiler_5.03_117_Linux 33 | 34 | # It's best to hide all the details of setting up the variable SRCS in a CMake 35 | # macro. The macro can then be called in all the project CMake list files to add 36 | # sources. 37 | # 38 | # The macro first computes the path of the source file relative to the project 39 | # root for each argument. If the macro is invoked from inside a project sub 40 | # directory the new value of the variable SRCS needs to be propagated to the 41 | # parent folder by using the PARENT_SCOPE option. 42 | # 43 | # Source: http://stackoverflow.com/questions/7046956/populating-srcs-from-cmakelists-txt-in-subdirectories 44 | macro (add_sources) 45 | file (RELATIVE_PATH _relPath "${CMAKE_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}") 46 | foreach (_src ${ARGN}) 47 | if (_relPath) 48 | list (APPEND SRCS "${_relPath}/${_src}") 49 | else() 50 | list (APPEND SRCS "${_src}") 51 | endif() 52 | endforeach() 53 | if (_relPath) 54 | # propagate to parent directory 55 | set (SRCS ${SRCS} PARENT_SCOPE) 56 | endif() 57 | endmacro() 58 | 59 | # decide about the actual compilers to be used ... 60 | set(CMAKE_CXX_COMPILER ${TOOLCHAIN_SYSROOT}/bin/armcc) 61 | set(CMAKE_C_COMPILER ${TOOLCHAIN_SYSROOT}/bin/armcc) 62 | set(LINKER ${TOOLCHAIN_SYSROOT}/bin/armlink) 63 | set(SIZE_COMMAND size) 64 | set(MAIN_TARGET ${PROJECT_NAME}.elf) 65 | set(HEX_TARGET ${PROJECT_NAME}.hex) 66 | set(COMBINED_SD "combined.hex" 67 | CACHE FILE "Output name for the bundled bootloader+softdevice") 68 | set(COMBINED_SD_APP "combined_app.hex" 69 | CACHE FILE "Output name for the bundled bootloader+softdevice+app") 70 | 71 | set(CMAKE_LINK_FLAGS "--libpath=${TOOLCHAIN_SYSROOT}/lib --info=totals --list=.link_totals.txt --scatter ${BLE_BOOTLOADER_SOURCE_DIR}/bootloader.sct") 72 | 73 | set(CMAKE_CXX_LINK_EXECUTABLE 74 | "${LINKER} ${CMAKE_LINK_FLAGS} -o --map --feedback=.feedback --feedback_type=unused,iw") 75 | set(CMAKE_C_LINK_EXECUTABLE 76 | "${LINKER} ${CMAKE_LINK_FLAGS} -o --map --feedback=.feedback --feedback_type=unused,iw") 77 | enable_language(ASM) 78 | 79 | message(STATUS "C compiler : ${CMAKE_C_COMPILER}") 80 | message(STATUS "C++ compiler: ${CMAKE_CXX_COMPILER}") 81 | message(STATUS "Size command: ${SIZE_COMMAND}") 82 | message(STATUS "Main target : ${MAIN_TARGET}") 83 | message(STATUS "HEX target : ${HEX_TARGET}") 84 | message(STATUS "Combined : ${COMBINED_SD}") 85 | message(STATUS "Combined+app: ${COMBINED_SD_APP}") 86 | message(STATUS "Platform : ${PLATFORM}") 87 | message(STATUS "Board : ${BOARD}") 88 | 89 | ############################################################################ 90 | # Build type should be clear from here so we 91 | # can continue with selecting include directors, defines 92 | # and other compiler/linker flags ... 93 | ############################################################################ 94 | # include directories 95 | include_directories( 96 | ${BLE_BOOTLOADER_SOURCE_DIR} 97 | ${BLE_BOOTLOADER_SOURCE_DIR}/include 98 | ${MBED_SRC_PATH}/ 99 | ${MBED_SRC_PATH}/api 100 | ${MBED_SRC_PATH}/common 101 | ${MBED_SRC_PATH}/hal 102 | ${MBED_SRC_PATH}/targets 103 | ${MBED_SRC_PATH}/targets/cmsis 104 | ${MBED_SRC_PATH}/targets/cmsis/TARGET_NORDIC 105 | ${MBED_SRC_PATH}/targets/cmsis/TARGET_NORDIC/TARGET_MCU_NRF51822 106 | ${MBED_SRC_PATH}/targets/cmsis/TARGET_NORDIC/TARGET_MCU_NRF51822/TOOLCHAIN_ARM_STD 107 | ${MBED_SRC_PATH}/targets/hal 108 | ${MBED_SRC_PATH}/targets/hal/TARGET_NORDIC 109 | ${MBED_SRC_PATH}/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822 110 | ${MBED_SRC_PATH}/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/Lib 111 | ${MBED_SRC_PATH}/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/Lib/nordic_sdk/components/libraries/crc16 112 | ${MBED_SRC_PATH}/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/Lib/nordic_sdk/components/libraries/scheduler 113 | ${MBED_SRC_PATH}/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/Lib/nordic_sdk/components/libraries/util 114 | ${MBED_SRC_PATH}/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/TARGET_${BOARD} 115 | 116 | ${BLE_API_SRC_PATH} 117 | ${BLE_API_SRC_PATH}/ble 118 | ${BLE_API_SRC_PATH}/ble/services 119 | 120 | ${NRF51822_SRC_PATH}/source 121 | ${NRF51822_SRC_PATH}/source/btle 122 | ${NRF51822_SRC_PATH}/source/btle/custom 123 | ${NRF51822_SRC_PATH}/source/common 124 | ${NRF51822_SRC_PATH}/source/nordic 125 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/ 126 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/ble 127 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/ble/ble_services/ble_dfu 128 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/ble/ble_radio_notification 129 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/ble/common 130 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/ble/device_manager 131 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/ble/device_manager/config 132 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/drivers_nrf 133 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/drivers_nrf/ble_flash 134 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/drivers_nrf/hal 135 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/drivers_nrf/pstorage 136 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/drivers_nrf/pstorage/config 137 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/libraries 138 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/libraries/bootloader_dfu 139 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/libraries/bootloader_dfu/hci_transport 140 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/libraries/crc16 141 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/libraries/gpiote 142 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/libraries/hci 143 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/libraries/scheduler 144 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/libraries/util 145 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/softdevice 146 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/softdevice/common 147 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/softdevice/common/softdevice_handler 148 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/softdevice/s130 149 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/softdevice/s130/include 150 | ) 151 | 152 | # Generic compiler flags 153 | add_definitions( 154 | --cpu=Cortex-M0 155 | --apcs=interwork 156 | --enum_is_int 157 | -DNRF51 158 | -DDEBUG_NRF_USER 159 | -DBOARD_NRF6310 160 | -DBOOTLOADER_BANKED 161 | # -DBLE_STACK_SUPPORT_REQD 162 | -DUSE_APP_TIMER 163 | -O3 164 | --md 165 | -DTARGET_NRF51822 166 | -DTARGET_${PLATFORM} 167 | -DTARGET_${BOARD} 168 | -DTARGET_M0 169 | -DTARGET_NORDIC 170 | -DTOOLCHAIN_ARM_STD 171 | -DTOOLCHAIN_ARM 172 | -D__CC_ARM 173 | -D__CORTEX_M0 174 | -DARM_MATH_CM0 175 | -D__MBED__=1 176 | -DNEED_PSTORAGE 177 | -DNEED_APP_GPIOTE 178 | --feedback=.feedback 179 | ) 180 | 181 | # Language specifc compiler flags. 182 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --cpp --no_rtti") 183 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --c99") 184 | 185 | # A macro to collect local sources into ${SRCS}. 186 | # This variable gets propagated to the parent scope and is ultimately used in 187 | # the top-level CMakeLists.txt to define the dependencies for the build target. 188 | # 189 | # Please note that files within this list are relative to the current folder. 190 | # Please also note that this macro must be used at all CMakeLists.txt files at 191 | # intermediate levels even if the list is empty--this is due to the Cmake magic 192 | # involved in propagating variables to only the parent scope. 193 | add_sources( 194 | main.c 195 | dfu_dual_bank.c 196 | bootloader.c 197 | bootloader_settings_arm.c 198 | dfu_transport_ble.c 199 | dfu_ble_svc.c 200 | app_timer.c 201 | app_timer_appsh.c 202 | ) 203 | 204 | add_sources(${BLE_BOOTLOADER_SOURCE_DIR}/startup/arm_startup_nrf51.s) 205 | add_sources(${MBED_SRC_PATH}/targets/cmsis/TARGET_NORDIC/TARGET_MCU_NRF51822/system_nrf51.c) 206 | 207 | file(GLOB NRF51822_SOURCES 208 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/ble/ble_services/ble_dfu/*.c 209 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/ble/common/*.c 210 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/ble/common/*.cpp 211 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/ble/device_manager/*.c 212 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/drivers_nrf/hal/*.c 213 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/drivers_nrf/pstorage/*.c 214 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/libraries/bootloader_dfu/*.c 215 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/libraries/bootloader_dfu/experimental/*.c 216 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/libraries/crc16/*.c 217 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/libraries/hci/*.c 218 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/libraries/scheduler/*.c 219 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/libraries/util/*.c 220 | ${NRF51822_SRC_PATH}/source/nordic-sdk/components/softdevice/common/softdevice_handler/*.c 221 | ) 222 | add_sources(${NRF51822_SOURCES}) 223 | 224 | ############################################################################ 225 | # By now, we've traversed all subdirectories and have collected everything that 226 | # needs to be built. We can define the build targets. 227 | ############################################################################ 228 | # add MbedTest as a build target depending on all the sources 229 | add_executable(${MAIN_TARGET} ${SRCS}) 230 | 231 | # Add a post-build dependency like printing size of the 232 | # resulting binary and copying to the target. 233 | add_custom_command( 234 | # Show ELF size 235 | TARGET ${MAIN_TARGET} 236 | COMMAND ${SIZE_COMMAND} ${MAIN_TARGET} 237 | ) 238 | 239 | add_custom_target(${HEX_TARGET} ALL 240 | DEPENDS ${MAIN_TARGET} 241 | COMMAND ${TOOLCHAIN_SYSROOT}/bin/fromelf --i32combined -o ${PROJECT_NAME}.hex ${MAIN_TARGET} 242 | COMMAND srec_cat ${PROJECT_NAME}.hex -intel 243 | # Change bootloader settings: BANK0 now contains a valid application 244 | -exclude 0x3FC00 0x3FC20 245 | -generate 0x3FC00 0x3FC04 -l-e-constant 0x01 4 246 | -generate 0x3FC04 0x3FC08 -l-e-constant 0x00 4 247 | -generate 0x3FC08 0x3FC0C -l-e-constant 0xFE 4 248 | -generate 0x3FC0C 0x3FC20 -constant 0x00 249 | -o ${PROJECT_NAME}.hex -intel 250 | ) 251 | 252 | add_custom_target(${COMBINED_SD} ALL 253 | COMMENT "Add a SoftDevice to the HEX package" 254 | DEPENDS ${HEX_TARGET} 255 | COMMAND srec_cat ${SOFT_DEVICE} -intel 256 | ${HEX_TARGET} -intel 257 | -o ${COMBINED_SD} -intel -obs=16 258 | COMMAND srec_info ${COMBINED_SD} -intel 259 | ) 260 | 261 | # The following is optional. Enable it if you wish to combine with a default app. 262 | # add_custom_target(${COMBINED_SD_APP} ALL 263 | # COMMENT "Add an application to the HEX package" 264 | # DEPENDS ${COMBINED_SD} 265 | # COMMAND srec_cat ${COMBINED_SD} -intel 266 | # ${APP_PATH} -intel 267 | # -o ${COMBINED_SD_APP} -intel -obs=16 268 | # COMMAND srec_info ${COMBINED_SD_APP} -intel 269 | # # follow this by copying the resulting combined.hex onto the target (possibly over USB) 270 | # ) 271 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Deprecation note! 2 | 3 | **Please note: This repository is deprecated and it is no longer actively maintained**. 4 | -------------------------------------------------------------------------------- /app_common/app_button.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved. 2 | * 3 | * The information contained herein is property of Nordic Semiconductor ASA. 4 | * Terms and conditions of usage are described in detail in NORDIC 5 | * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. 6 | * 7 | * Licensees are granted free, non-transferable use of the information. NO 8 | * WARRANTY of ANY KIND is provided. This heading must NOT be removed from 9 | * the file. 10 | * 11 | */ 12 | 13 | #include "app_button.h" 14 | #include 15 | #include "nordic_common.h" 16 | #include "app_util.h" 17 | #include "app_gpiote.h" 18 | #include "app_timer.h" 19 | #include "app_error.h" 20 | 21 | 22 | static app_button_cfg_t * mp_buttons = NULL; /**< Button configuration. */ 23 | static uint8_t m_button_count; /**< Number of configured buttons. */ 24 | static uint32_t m_detection_delay; /**< Delay before a button is reported as pushed. */ 25 | static app_button_evt_schedule_func_t m_evt_schedule_func; /**< Pointer to function for propagating button events to the scheduler. */ 26 | static app_gpiote_user_id_t m_gpiote_user_id; /**< GPIOTE user id for buttons module. */ 27 | static app_timer_id_t m_detection_delay_timer_id; /**< Polling timer id. */ 28 | static pin_transition_t m_pin_transition; /**< pin transaction direction. */ 29 | 30 | 31 | /**@brief Function for executing the application button handler for specified button. 32 | * 33 | * @param[in] p_btn Button that has been pushed. 34 | */ 35 | static void button_handler_execute(app_button_cfg_t * p_btn, uint32_t transition) 36 | { 37 | if (m_evt_schedule_func != NULL) 38 | { 39 | uint32_t err_code = m_evt_schedule_func(p_btn->button_handler, p_btn->pin_no,transition); 40 | APP_ERROR_CHECK(err_code); 41 | } 42 | else 43 | { 44 | if(transition == APP_BUTTON_PUSH) 45 | { 46 | p_btn->button_handler(p_btn->pin_no, APP_BUTTON_PUSH); 47 | } 48 | else if(transition == APP_BUTTON_RELEASE) 49 | { 50 | p_btn->button_handler(p_btn->pin_no, APP_BUTTON_RELEASE); 51 | } 52 | } 53 | } 54 | 55 | 56 | /**@brief Function for handling the timeout that delays reporting buttons as pushed. 57 | * 58 | * @details The detection_delay_timeout_handler(...) is a call-back issued from the app_timer 59 | * module. It is called with the p_context parameter. The p_context parameter is 60 | * provided to the app_timer module when a timer is started, using the call 61 | * @ref app_timer_start. On @ref app_timer_start the p_context will be holding the 62 | * currently pressed buttons. 63 | * 64 | * @param[in] p_context Pointer used for passing information app_start_timer() was called. 65 | * In the app_button module the p_context holds information on pressed 66 | * buttons. 67 | */ 68 | static void detection_delay_timeout_handler(void * p_context) 69 | { 70 | uint32_t err_code; 71 | uint32_t current_state_pins; 72 | 73 | // Get current state of pins. 74 | err_code = app_gpiote_pins_state_get(m_gpiote_user_id, ¤t_state_pins); 75 | 76 | if (err_code != NRF_SUCCESS) 77 | { 78 | return; 79 | } 80 | 81 | uint8_t i; 82 | 83 | // Pushed button(s) detected, execute button handler(s). 84 | for (i = 0; i < m_button_count; i++) 85 | { 86 | app_button_cfg_t * p_btn = &mp_buttons[i]; 87 | 88 | if (((m_pin_transition.high_to_low & (1 << p_btn->pin_no)) != 0) && (p_btn->button_handler != NULL)) 89 | { 90 | //If it's active high then going from high to low was a release of the button. 91 | if(p_btn->active_state == APP_BUTTON_ACTIVE_HIGH) 92 | { 93 | button_handler_execute(p_btn, APP_BUTTON_RELEASE); 94 | } 95 | //If it's active low then going from high to low was a push of the button. 96 | else 97 | { 98 | button_handler_execute(p_btn, APP_BUTTON_PUSH); 99 | } 100 | } 101 | else if (((m_pin_transition.low_to_high & (1 << p_btn->pin_no)) != 0) && (p_btn->button_handler != NULL)) 102 | { 103 | //If it's active high then going from low to high was a push of the button. 104 | if(p_btn->active_state == APP_BUTTON_ACTIVE_HIGH) 105 | { 106 | button_handler_execute(p_btn,APP_BUTTON_PUSH); 107 | } 108 | //If it's active low then going from low to high was a release of the button. 109 | else 110 | { 111 | button_handler_execute(p_btn,APP_BUTTON_RELEASE); 112 | } 113 | } 114 | } 115 | } 116 | 117 | 118 | /**@brief Function for handling the GPIOTE event. 119 | * 120 | * @details Saves the current status of the button pins, and starts a timer. If the timer is already 121 | * running, it will be restarted. 122 | * 123 | * @param[in] event_pins_low_to_high Mask telling which pin(s) had a low to high transition. 124 | * @param[in] event_pins_high_to_low Mask telling which pin(s) had a high to low transition. 125 | */ 126 | static void gpiote_event_handler(uint32_t event_pins_low_to_high, uint32_t event_pins_high_to_low) 127 | { 128 | uint32_t err_code; 129 | 130 | // Start detection timer. If timer is already running, the detection period is restarted. 131 | // NOTE: Using the p_context parameter of app_timer_start() to transfer the pin states to the 132 | // timeout handler (by casting event_pins_mask into the equally sized void * p_context 133 | // parameter). 134 | STATIC_ASSERT(sizeof(void *) == sizeof(uint32_t)); 135 | 136 | err_code = app_timer_stop(m_detection_delay_timer_id); 137 | if (err_code != NRF_SUCCESS) 138 | { 139 | // The impact in app_button of the app_timer queue running full is losing a button press. 140 | // The current implementation ensures that the system will continue working as normal. 141 | return; 142 | } 143 | 144 | m_pin_transition.low_to_high = event_pins_low_to_high; 145 | m_pin_transition.high_to_low = event_pins_high_to_low; 146 | 147 | err_code = app_timer_start(m_detection_delay_timer_id, 148 | m_detection_delay, 149 | (void *)(event_pins_low_to_high | event_pins_high_to_low)); 150 | if (err_code != NRF_SUCCESS) 151 | { 152 | // The impact in app_button of the app_timer queue running full is losing a button press. 153 | // The current implementation ensures that the system will continue working as normal. 154 | } 155 | } 156 | 157 | 158 | uint32_t app_button_init(app_button_cfg_t * p_buttons, 159 | uint8_t button_count, 160 | uint32_t detection_delay, 161 | app_button_evt_schedule_func_t evt_schedule_func) 162 | { 163 | uint32_t err_code; 164 | 165 | if (detection_delay < APP_TIMER_MIN_TIMEOUT_TICKS) 166 | { 167 | return NRF_ERROR_INVALID_PARAM; 168 | } 169 | 170 | // Save configuration. 171 | mp_buttons = p_buttons; 172 | m_button_count = button_count; 173 | m_detection_delay = detection_delay; 174 | m_evt_schedule_func = evt_schedule_func; 175 | 176 | // Configure pins. 177 | uint32_t pins_transition_mask = 0; 178 | 179 | while (button_count--) 180 | { 181 | app_button_cfg_t * p_btn = &p_buttons[button_count]; 182 | 183 | // Configure pin. 184 | nrf_gpio_cfg_input(p_btn->pin_no, p_btn->pull_cfg); 185 | 186 | // Build GPIOTE user registration masks. 187 | pins_transition_mask |= (1 << p_btn->pin_no); 188 | } 189 | 190 | // Register button module as a GPIOTE user. 191 | err_code = app_gpiote_user_register(&m_gpiote_user_id, 192 | pins_transition_mask, 193 | pins_transition_mask, 194 | gpiote_event_handler); 195 | if (err_code != NRF_SUCCESS) 196 | { 197 | return err_code; 198 | } 199 | 200 | // Create polling timer. 201 | return app_timer_create(&m_detection_delay_timer_id, 202 | APP_TIMER_MODE_SINGLE_SHOT, 203 | detection_delay_timeout_handler); 204 | } 205 | 206 | 207 | uint32_t app_button_enable(void) 208 | { 209 | if (mp_buttons == NULL) 210 | { 211 | return NRF_ERROR_INVALID_STATE; 212 | } 213 | 214 | return app_gpiote_user_enable(m_gpiote_user_id); 215 | } 216 | 217 | 218 | uint32_t app_button_disable(void) 219 | { 220 | uint32_t err_code; 221 | 222 | if (mp_buttons == NULL) 223 | { 224 | return NRF_ERROR_INVALID_STATE; 225 | } 226 | 227 | err_code = app_gpiote_user_disable(m_gpiote_user_id); 228 | 229 | if (err_code != NRF_SUCCESS) 230 | { 231 | return err_code; 232 | } 233 | 234 | // Make sure polling timer is not running. 235 | return app_timer_stop(m_detection_delay_timer_id); 236 | } 237 | 238 | 239 | uint32_t app_button_is_pushed(uint8_t button_id, bool * p_is_pushed) 240 | { 241 | uint32_t err_code; 242 | uint32_t active_pins; 243 | 244 | if (button_id > m_button_count) 245 | { 246 | return NRF_ERROR_INVALID_PARAM; 247 | } 248 | app_button_cfg_t * p_btn = &mp_buttons[button_id]; 249 | 250 | if (mp_buttons == NULL) 251 | { 252 | return NRF_ERROR_INVALID_STATE; 253 | } 254 | 255 | err_code = app_gpiote_pins_state_get(m_gpiote_user_id, &active_pins); 256 | 257 | if (err_code != NRF_SUCCESS) 258 | { 259 | return err_code; 260 | } 261 | 262 | if(p_btn->active_state == APP_BUTTON_ACTIVE_LOW) 263 | { 264 | // If the pin is active low, then the pin being high means it is not pushed. 265 | if(((active_pins >> p_btn->pin_no) & 0x01)) 266 | { 267 | *p_is_pushed = false; 268 | } 269 | else 270 | { 271 | *p_is_pushed = true; 272 | } 273 | } 274 | else if(p_btn->active_state == APP_BUTTON_ACTIVE_HIGH) 275 | { 276 | // If the pin is active high, then the pin being high means it is pushed. 277 | if(((active_pins >> p_btn->pin_no) & 0x01)) 278 | { 279 | *p_is_pushed = true; 280 | } 281 | else 282 | { 283 | *p_is_pushed = false; 284 | } 285 | } 286 | 287 | return NRF_SUCCESS; 288 | } 289 | -------------------------------------------------------------------------------- /app_common/app_uart.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013 Nordic Semiconductor. All Rights Reserved. 2 | * 3 | * The information contained herein is property of Nordic Semiconductor ASA. 4 | * Terms and conditions of usage are described in detail in NORDIC 5 | * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. 6 | * 7 | * Licensees are granted free, non-transferable use of the information. NO 8 | * WARRANTY of ANY KIND is provided. This heading must NOT be removed from 9 | * the file. 10 | * 11 | */ 12 | 13 | #include "app_uart.h" 14 | #include "nrf.h" 15 | #include "nrf_gpio.h" 16 | #include "app_error.h" 17 | #include "app_util.h" 18 | #include "app_gpiote.h" 19 | #include "boards.h" 20 | 21 | #define FIFO_LENGTH(F) (F.write_pos - F.read_pos) /**< Macro to calculate length of a FIFO. */ 22 | #define UART_INSTANCE_GPIOTE_BASE 0x00FF /**< Define the base for UART instance ID when flow control is used. The userid from GPIOTE will be used with padded 0xFF at LSB for easy converting the instance id to GPIOTE id. */ 23 | #define UART_INSTANCE_ID_INVALID 0x0000 /**< Value 0x0000 is used to indicate an invalid instance id. When 0 is provided as instance id upon initialization, the module will provide a valid id to the caller. */ 24 | #define BYTE_INVALID 0xFFFF /**< Value 0xFFFF is used to mark the byte in the receive buffer as invalid. */ 25 | 26 | /** @brief States for the app_uart state machine. */ 27 | typedef enum 28 | { 29 | UART_OFF, /**< app_uart state OFF, indicating CTS is low. */ 30 | UART_READY, /**< app_uart state ON, indicating CTS is high. */ 31 | UART_ON, /**< app_uart state TX, indicating UART is ongoing transmitting data. */ 32 | UART_WAIT_CLOSE, /**< app_uart state WAIT CLOSE, indicating that CTS is low, but a byte is currently being transmitted on the line. */ 33 | } app_uart_states_t; 34 | 35 | /** @brief State transition events for the app_uart state machine. */ 36 | typedef enum 37 | { 38 | ON_CTS_HIGH, /**< Event: CTS gone high. */ 39 | ON_CTS_LOW, /**< Event: CTS gone low. */ 40 | ON_UART_PUT, /**< Event: Application wants to transmit data. */ 41 | ON_TX_READY, /**< Event: Data has been transmitted on the uart and line is available. */ 42 | ON_UART_CLOSE, /**< Event: The UART module are being stopped. */ 43 | } app_uart_state_events_t; 44 | 45 | static uint8_t m_tx_byte; /**< TX Byte placeholder for next byte to transmit. */ 46 | static uint16_t m_rx_byte = BYTE_INVALID; /**< RX Byte placeholder for last received byte. */ 47 | 48 | 49 | static uint8_t m_instance_counter = 1; /**< Instance counter for each caller using the UART module. The GPIOTE user id is mapped directly for callers using HW Flow Control. */ 50 | static app_gpiote_user_id_t m_gpiote_uid; /**< GPIOTE id for currently active caller to the UART module. */ 51 | static uint32_t m_pin_cts_mask; /**< CTS pin mask for UART module. */ 52 | static app_uart_event_handler_t m_event_handler; /**< Event handler function. */ 53 | static volatile app_uart_states_t m_current_state = UART_OFF; /**< State of the state machine. */ 54 | 55 | /**@brief Function for disabling the UART when entering the UART_OFF state. 56 | */ 57 | static void action_uart_deactivate(void) 58 | { 59 | m_current_state = UART_OFF; 60 | NRF_UART0->TASKS_STOPTX = 1; 61 | NRF_UART0->TASKS_STOPRX = 1; 62 | NRF_UART0->ENABLE = (UART_ENABLE_ENABLE_Disabled << UART_ENABLE_ENABLE_Pos); 63 | } 64 | 65 | 66 | void action_tx_stop() 67 | { 68 | app_uart_evt_t app_uart_event; 69 | 70 | // No more bytes in FIFO, terminate transmission. 71 | NRF_UART0->TASKS_STOPTX = 1; 72 | m_current_state = UART_READY; 73 | // Last byte from FIFO transmitted, notify the application. 74 | // Notify that new data is available if this was first byte put in the buffer. 75 | app_uart_event.evt_type = APP_UART_TX_EMPTY; 76 | m_event_handler(&app_uart_event); 77 | } 78 | 79 | 80 | /**@brief Function for sending the next byte in the TX buffer. Called when (re-)entering the UART_ON state. 81 | * If no more data is available in the TX buffer, the state machine will enter UART_READY state. 82 | */ 83 | static void action_tx_send() 84 | { 85 | if (m_current_state != UART_ON) 86 | { 87 | // Start the UART. 88 | NRF_UART0->TASKS_STARTTX = 1; 89 | } 90 | 91 | NRF_UART0->TXD = m_tx_byte; 92 | m_current_state = UART_ON; 93 | } 94 | 95 | 96 | static void action_tx_ready() 97 | { 98 | action_tx_stop(); 99 | } 100 | 101 | 102 | /**@brief Function for the handling of the ON_CTS_HIGH event. 103 | */ 104 | static void on_cts_high(void) 105 | { 106 | switch (m_current_state) 107 | { 108 | case UART_READY: 109 | action_uart_deactivate(); 110 | break; 111 | 112 | case UART_ON: 113 | m_current_state = UART_WAIT_CLOSE; 114 | break; 115 | 116 | default: 117 | // Nothing to do. 118 | break; 119 | } 120 | } 121 | 122 | 123 | /**@brief Function for the handling of the ON_CTS_LOW event. 124 | */ 125 | static void on_cts_low(void) 126 | { 127 | switch (m_current_state) 128 | { 129 | case UART_OFF: 130 | NRF_UART0->ENABLE = (UART_ENABLE_ENABLE_Enabled << UART_ENABLE_ENABLE_Pos); 131 | NRF_UART0->TASKS_STARTRX = 1; 132 | 133 | m_current_state = UART_READY; 134 | break; 135 | 136 | case UART_WAIT_CLOSE: 137 | m_current_state = UART_ON; 138 | break; 139 | 140 | default: 141 | // Nothing to do. 142 | break; 143 | } 144 | } 145 | 146 | 147 | /**@brief Function for the handling of the ON_TX_READY event. 148 | */ 149 | static void on_tx_ready(void) 150 | { 151 | switch (m_current_state) 152 | { 153 | case UART_WAIT_CLOSE: 154 | action_uart_deactivate(); 155 | break; 156 | 157 | case UART_ON: 158 | case UART_READY: 159 | action_tx_ready(); 160 | break; 161 | 162 | default: 163 | // Nothing to do. 164 | break; 165 | } 166 | } 167 | 168 | 169 | /**@brief Function for the handling of the ON_UART_PUT event when application has put data in the TX buffer. 170 | */ 171 | static void on_uart_put(void) 172 | { 173 | if (m_current_state == UART_READY) 174 | { 175 | action_tx_send(); 176 | } 177 | } 178 | 179 | 180 | /**@brief Function for the handling of the ON_UART_CLOSE event when application is closing the UART module. 181 | */ 182 | static void on_uart_close(void) 183 | { 184 | action_uart_deactivate(); 185 | } 186 | 187 | 188 | /**@brief Function for handling the state machine main event. 189 | * 190 | * @param[in] event Event that has occurred. 191 | */ 192 | static void on_uart_event(app_uart_state_events_t event) 193 | { 194 | switch (event) 195 | { 196 | case ON_CTS_HIGH: 197 | on_cts_high(); 198 | break; 199 | 200 | case ON_CTS_LOW: 201 | on_cts_low(); 202 | break; 203 | 204 | case ON_TX_READY: 205 | on_tx_ready(); 206 | break; 207 | 208 | case ON_UART_PUT: 209 | on_uart_put(); 210 | break; 211 | 212 | case ON_UART_CLOSE: 213 | on_uart_close(); 214 | break; 215 | 216 | default: 217 | // All valid events are handled above. 218 | break; 219 | } 220 | } 221 | 222 | 223 | /**@brief Function for handling the GPIOTE event. 224 | * 225 | * @param[in] event_pins_low_to_high Mask telling which pin(s) generated an event from low->high. 226 | * @param[in] event_pins_high_to_low Mask telling which pin(s) generated an event from high->low. 227 | */ 228 | static void gpiote_uart_event_handler(uint32_t event_pins_low_to_high, 229 | uint32_t event_pins_high_to_low) 230 | { 231 | if ((event_pins_high_to_low & event_pins_low_to_high & m_pin_cts_mask) != 0) 232 | { 233 | // We have an indication from GPIOTE that the CTS pin has toggled high->low and low->high. 234 | // If this occurs, we must read the active pins in the GPIOTE module ourself. 235 | uint32_t active_pins; 236 | uint32_t err_code; 237 | 238 | err_code = app_gpiote_pins_state_get(m_gpiote_uid, &active_pins); 239 | 240 | if (err_code != NRF_SUCCESS) 241 | { 242 | // Pin reading was not possible, even though an event from GPIOTE was received that the 243 | // CTS pin toggled. If pin double toggled but status cannot be fetched we silently 244 | // return and keep the current UART status as-is. 245 | return; 246 | } 247 | event_pins_low_to_high &= active_pins; 248 | event_pins_high_to_low &= ~active_pins; 249 | } 250 | 251 | if ((event_pins_high_to_low & m_pin_cts_mask) != 0) 252 | { 253 | on_uart_event(ON_CTS_LOW); 254 | } 255 | else if ((event_pins_low_to_high & m_pin_cts_mask) != 0) 256 | { 257 | on_uart_event(ON_CTS_HIGH); 258 | } 259 | else 260 | { 261 | // Do nothing, as the CTS pin didn't toggle. 262 | } 263 | } 264 | 265 | 266 | /**@brief Function for handling the UART Interrupt. 267 | * 268 | * @details UART interrupt handler to process TX Ready when TXD is available, RX Ready when a byte 269 | * is received, or in case of error when receiving a byte. 270 | */ 271 | void UART0_IRQHandler(void) 272 | { 273 | // Handle reception 274 | if ((NRF_UART0->EVENTS_RXDRDY != 0) && (NRF_UART0->INTENSET & UART_INTENSET_RXDRDY_Msk)) 275 | { 276 | app_uart_evt_t app_uart_event; 277 | 278 | // Clear UART RX event flag 279 | NRF_UART0->EVENTS_RXDRDY = 0; 280 | m_rx_byte = (uint8_t)NRF_UART0->RXD; 281 | app_uart_event.evt_type = APP_UART_DATA; 282 | app_uart_event.data.value = m_rx_byte; 283 | m_event_handler(&app_uart_event); 284 | } 285 | 286 | // Handle transmission. 287 | if ((NRF_UART0->EVENTS_TXDRDY != 0) && (NRF_UART0->INTENSET & UART_INTENSET_TXDRDY_Msk)) 288 | { 289 | // Clear UART TX event flag. 290 | NRF_UART0->EVENTS_TXDRDY = 0; 291 | on_uart_event(ON_TX_READY); 292 | } 293 | 294 | // Handle errors. 295 | if ((NRF_UART0->EVENTS_ERROR != 0) && (NRF_UART0->INTENSET & UART_INTENSET_ERROR_Msk)) 296 | { 297 | uint32_t error_source; 298 | app_uart_evt_t app_uart_event; 299 | 300 | // Clear UART ERROR event flag. 301 | NRF_UART0->EVENTS_ERROR = 0; 302 | 303 | // Clear error source. 304 | error_source = NRF_UART0->ERRORSRC; 305 | NRF_UART0->ERRORSRC = error_source; 306 | 307 | app_uart_event.evt_type = APP_UART_COMMUNICATION_ERROR; 308 | app_uart_event.data.error_communication = error_source; 309 | 310 | m_event_handler(&app_uart_event); 311 | } 312 | } 313 | 314 | 315 | /**@brief Function for initialization of UART when flow control is disabled. 316 | */ 317 | static void uart_no_flow_control_init(void) 318 | { 319 | NRF_UART0->ENABLE = (UART_ENABLE_ENABLE_Enabled << UART_ENABLE_ENABLE_Pos); 320 | NRF_UART0->EVENTS_RXDRDY = 0; 321 | NRF_UART0->EVENTS_TXDRDY = 0; 322 | 323 | NRF_UART0->CONFIG &= ~(UART_CONFIG_HWFC_Enabled << UART_CONFIG_HWFC_Pos); 324 | 325 | NRF_UART0->PSELRTS = UART_PIN_DISCONNECTED; 326 | NRF_UART0->PSELCTS = UART_PIN_DISCONNECTED; 327 | 328 | NRF_UART0->TASKS_STARTTX = 1; 329 | NRF_UART0->TASKS_STARTRX = 1; 330 | } 331 | 332 | 333 | /**@brief Function for initialization of UART when standard flow control is enabled. 334 | */ 335 | static void uart_standard_flow_control_init(const app_uart_comm_params_t * p_comm_params) 336 | { 337 | NRF_UART0->ENABLE = (UART_ENABLE_ENABLE_Enabled << UART_ENABLE_ENABLE_Pos); 338 | NRF_UART0->EVENTS_RXDRDY = 0; 339 | NRF_UART0->EVENTS_TXDRDY = 0; 340 | 341 | NRF_UART0->CONFIG |= (UART_CONFIG_HWFC_Enabled << UART_CONFIG_HWFC_Pos); 342 | 343 | NRF_UART0->PSELCTS = p_comm_params->cts_pin_no; 344 | NRF_UART0->PSELRTS = p_comm_params->rts_pin_no; 345 | 346 | NRF_UART0->TASKS_STARTTX = 1; 347 | NRF_UART0->TASKS_STARTRX = 1; 348 | } 349 | 350 | 351 | uint32_t app_uart_init(const app_uart_comm_params_t * p_comm_params, 352 | app_uart_buffers_t * p_buffers, 353 | app_uart_event_handler_t event_handler, 354 | app_irq_priority_t irq_priority, 355 | uint16_t * p_app_uart_uid) 356 | { 357 | uint32_t err_code; 358 | uint32_t gpiote_high_pins; 359 | uint32_t gpiote_pin_low_high_mask = 0; 360 | uint32_t gpiote_pin_high_low_mask = 0; 361 | 362 | m_current_state = UART_OFF; 363 | m_event_handler = event_handler; 364 | m_rx_byte = BYTE_INVALID; 365 | 366 | 367 | // Configure RX and TX pins. 368 | nrf_gpio_pin_set(p_comm_params->tx_pin_no); 369 | nrf_gpio_cfg_output(p_comm_params->tx_pin_no); 370 | nrf_gpio_cfg_input(p_comm_params->rx_pin_no, NRF_GPIO_PIN_PULLUP); 371 | 372 | 373 | NRF_UART0->PSELTXD = p_comm_params->tx_pin_no; 374 | NRF_UART0->PSELRXD = p_comm_params->rx_pin_no; 375 | 376 | // Configure baud rate and parity. 377 | NRF_UART0->BAUDRATE = (p_comm_params->baud_rate << UART_BAUDRATE_BAUDRATE_Pos); 378 | 379 | if (p_comm_params->use_parity) 380 | { 381 | NRF_UART0->CONFIG = (UART_CONFIG_PARITY_Included << UART_CONFIG_PARITY_Pos); 382 | } 383 | else 384 | { 385 | NRF_UART0->CONFIG = (UART_CONFIG_PARITY_Excluded << UART_CONFIG_PARITY_Pos); 386 | } 387 | 388 | if (p_comm_params->flow_control == APP_UART_FLOW_CONTROL_LOW_POWER) 389 | { 390 | // Configure hardware flow control. 391 | nrf_gpio_cfg_output(p_comm_params->rts_pin_no); 392 | NRF_GPIO->OUT = 1 << p_comm_params->rts_pin_no; 393 | 394 | NRF_UART0->PSELCTS = UART_PIN_DISCONNECTED; 395 | NRF_UART0->PSELRTS = p_comm_params->rts_pin_no; 396 | NRF_UART0->CONFIG |= (UART_CONFIG_HWFC_Enabled << UART_CONFIG_HWFC_Pos); 397 | 398 | // Setup the gpiote to handle pin events on cts-pin. 399 | // For the UART we want to detect both low->high and high->low transitions in order to 400 | // know when to activate/de-activate the TX/RX in the UART. 401 | // Configure pin. 402 | m_pin_cts_mask = (1 << p_comm_params->cts_pin_no); 403 | nrf_gpio_cfg_sense_input(p_comm_params->cts_pin_no, 404 | NRF_GPIO_PIN_PULLUP, 405 | NRF_GPIO_PIN_SENSE_LOW); 406 | 407 | gpiote_pin_low_high_mask = (1 << p_comm_params->cts_pin_no); 408 | gpiote_pin_high_low_mask = (1 << p_comm_params->cts_pin_no); 409 | 410 | if (*p_app_uart_uid == UART_INSTANCE_ID_INVALID) 411 | { 412 | err_code = app_gpiote_user_register(&m_gpiote_uid, 413 | gpiote_pin_low_high_mask, 414 | gpiote_pin_high_low_mask, 415 | gpiote_uart_event_handler); 416 | 417 | if (err_code != NRF_SUCCESS) 418 | { 419 | return err_code; 420 | } 421 | *p_app_uart_uid = (m_gpiote_uid << 8) | UART_INSTANCE_GPIOTE_BASE; 422 | } 423 | else if (*p_app_uart_uid < UART_INSTANCE_GPIOTE_BASE) 424 | { 425 | return NRF_ERROR_INVALID_PARAM; 426 | } 427 | else 428 | { 429 | m_gpiote_uid = ((*p_app_uart_uid) >> 8) & UART_INSTANCE_GPIOTE_BASE; 430 | } 431 | 432 | err_code = app_gpiote_pins_state_get(m_gpiote_uid, &gpiote_high_pins); 433 | 434 | if (err_code != NRF_SUCCESS) 435 | { 436 | return err_code; 437 | } 438 | 439 | err_code = app_gpiote_user_enable(m_gpiote_uid); 440 | 441 | if (err_code != NRF_SUCCESS) 442 | { 443 | return err_code; 444 | } 445 | 446 | // UART CTS pin is active when low. 447 | if ((gpiote_high_pins & (1 << p_comm_params->cts_pin_no)) == 0) 448 | { 449 | on_uart_event(ON_CTS_LOW); 450 | } 451 | else 452 | { 453 | on_uart_event(ON_CTS_HIGH); 454 | } 455 | } 456 | else if (p_comm_params->flow_control == APP_UART_FLOW_CONTROL_ENABLED) 457 | { 458 | if (*p_app_uart_uid == UART_INSTANCE_ID_INVALID) 459 | { 460 | *p_app_uart_uid = m_instance_counter++; 461 | } 462 | 463 | uart_standard_flow_control_init(p_comm_params); 464 | m_current_state = UART_READY; 465 | } 466 | else 467 | { 468 | if (*p_app_uart_uid == UART_INSTANCE_ID_INVALID) 469 | { 470 | *p_app_uart_uid = m_instance_counter++; 471 | } 472 | 473 | uart_no_flow_control_init(); 474 | m_current_state = UART_READY; 475 | } 476 | 477 | // Enable UART interrupt 478 | NRF_UART0->INTENCLR = 0xffffffffUL; 479 | NRF_UART0->INTENSET = (UART_INTENSET_RXDRDY_Set << UART_INTENSET_RXDRDY_Pos) | 480 | (UART_INTENSET_TXDRDY_Set << UART_INTENSET_TXDRDY_Pos) | 481 | (UART_INTENSET_ERROR_Set << UART_INTENSET_ERROR_Pos); 482 | 483 | NVIC_ClearPendingIRQ(UART0_IRQn); 484 | NVIC_SetPriority(UART0_IRQn, irq_priority); 485 | NVIC_EnableIRQ(UART0_IRQn); 486 | 487 | return NRF_SUCCESS; 488 | } 489 | 490 | 491 | uint32_t app_uart_get(uint8_t * p_byte) 492 | { 493 | uint32_t err_code = NRF_SUCCESS; 494 | 495 | if (m_rx_byte == BYTE_INVALID) 496 | { 497 | err_code = NRF_ERROR_NOT_FOUND; 498 | } 499 | else 500 | { 501 | *p_byte = m_rx_byte; 502 | m_rx_byte = BYTE_INVALID; 503 | } 504 | 505 | return err_code; 506 | } 507 | 508 | 509 | uint32_t app_uart_put(uint8_t byte) 510 | { 511 | uint32_t err_code = NRF_SUCCESS; 512 | 513 | if (m_current_state != UART_READY) 514 | { 515 | err_code = NRF_ERROR_NO_MEM; 516 | } 517 | else 518 | { 519 | m_tx_byte = byte; 520 | on_uart_event(ON_UART_PUT); 521 | } 522 | 523 | return err_code; 524 | } 525 | 526 | 527 | uint32_t app_uart_flush(void) 528 | { 529 | return NRF_SUCCESS; 530 | } 531 | 532 | 533 | uint32_t app_uart_get_connection_state(app_uart_connection_state_t * p_conn_state) 534 | { 535 | *p_conn_state = ((m_current_state == UART_OFF) ? APP_UART_DISCONNECTED : APP_UART_CONNECTED); 536 | 537 | return NRF_SUCCESS; 538 | } 539 | 540 | 541 | uint32_t app_uart_close(uint16_t app_uart_uid) 542 | { 543 | uint16_t gpiote_uid; 544 | 545 | if (app_uart_uid < UART_INSTANCE_GPIOTE_BASE) 546 | { 547 | on_uart_event(ON_UART_CLOSE); 548 | return NRF_SUCCESS; 549 | } 550 | 551 | gpiote_uid = (app_uart_uid >> 8) & UART_INSTANCE_GPIOTE_BASE; 552 | 553 | if (gpiote_uid != m_gpiote_uid) 554 | { 555 | return NRF_ERROR_INVALID_PARAM; 556 | } 557 | 558 | on_uart_event(ON_UART_CLOSE); 559 | 560 | return app_gpiote_user_disable(m_gpiote_uid); 561 | } 562 | 563 | -------------------------------------------------------------------------------- /app_common/hci_slip.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013 Nordic Semiconductor. All Rights Reserved. 2 | * 3 | * The information contained herein is property of Nordic Semiconductor ASA. 4 | * Terms and conditions of usage are described in detail in NORDIC 5 | * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. 6 | * 7 | * Licensees are granted free, non-transferable use of the information. NO 8 | * WARRANTY of ANY KIND is provided. This heading must NOT be removed from 9 | * the file. 10 | * 11 | */ 12 | 13 | #include "hci_slip.h" 14 | #include 15 | #include "hci_transport_config.h" 16 | #include "app_uart.h" 17 | #include "nrf51_bitfields.h" 18 | 19 | #define APP_SLIP_END 0xC0 /**< SLIP code for identifying the beginning and end of a packet frame.. */ 20 | #define APP_SLIP_ESC 0xDB /**< SLIP escape code. This code is used to specify that the following character is specially encoded. */ 21 | #define APP_SLIP_ESC_END 0xDC /**< SLIP special code. When this code follows 0xDB, this character is interpreted as payload data 0xC0.. */ 22 | #define APP_SLIP_ESC_ESC 0xDD /**< SLIP special code. When this code follows 0xDB, this character is interpreted as payload data 0xDB. */ 23 | 24 | /** @brief States for the SLIP state machine. */ 25 | typedef enum 26 | { 27 | SLIP_OFF, /**< SLIP state OFF. */ 28 | SLIP_READY, /**< SLIP state ON. */ 29 | SLIP_TRANSMITTING, /**< SLIP state is transmitting indicating write() has been called but data transmission has not completed. */ 30 | } slip_states_t; 31 | 32 | static uint16_t m_uart_id; /** UART id returned from the UART module when calling app_uart_init, this id is kept, as it must be provided to the UART module when calling app_uart_close. */ 33 | static slip_states_t m_current_state = SLIP_OFF; /** Current state for the SLIP TX state machine. */ 34 | 35 | static hci_slip_event_handler_t m_slip_event_handler; /** Event callback function for handling of SLIP events, @ref hci_slip_evt_type_t . */ 36 | 37 | static const uint8_t * mp_tx_buffer; /** Pointer to the current TX buffer that is in transmission. */ 38 | static uint32_t m_tx_buffer_length; /** Length of the current TX buffer that is in transmission. */ 39 | static volatile uint32_t m_tx_buffer_index; /** Current index for next byte to transmit in the mp_tx_buffer. */ 40 | 41 | static uint8_t * mp_rx_buffer; /** Pointer to the current RX buffer where the next SLIP decoded packet will be stored. */ 42 | static uint32_t m_rx_buffer_length; /** Length of the current RX buffer. */ 43 | static uint32_t m_rx_received_count; /** Number of SLIP decoded bytes received and stored in mp_rx_buffer. */ 44 | 45 | 46 | /**@brief Function for parsing bytes received on the UART until a SLIP escape byte is received. 47 | * 48 | * @param[in] byte Byte received in UART module. 49 | */ 50 | static void handle_rx_byte_default(uint8_t byte); 51 | 52 | /**@brief Function for parsing bytes received on the UART until SLIP end byte is received. 53 | * 54 | * @param[in] byte Byte received in UART module. 55 | */ 56 | static void handle_rx_byte_wait_start(uint8_t byte); 57 | 58 | /**@brief Function for decoding a received SLIP escape byte. 59 | * It will ensure correct decoding of the byte following the SLIP escape byte. 60 | * 61 | * @param[in] byte Byte received in UART module. 62 | */ 63 | static void handle_rx_byte_esc(uint8_t byte); 64 | 65 | /**@brief Function pointer for parsing and decoding SLIP bytes from the UART module. 66 | * 67 | * @param[in] byte Byte received in UART module. 68 | */ 69 | static void (*handle_rx_byte) (uint8_t byte) = handle_rx_byte_wait_start; 70 | 71 | /**@brief Function pointer for sending a byte through the UART module. 72 | */ 73 | static uint32_t send_tx_byte_default(void); 74 | 75 | /**@brief Function for transferring a SLIP escape byte (0xDB) when special bytes are transferred, 76 | * that is 0xC0 and 0xDB. 77 | */ 78 | static uint32_t send_tx_byte_esc(void); 79 | 80 | /**@brief Function for transferring a byte when it collides with SLIP commands and follows the SLIP 81 | * escape byte, that is 0xC0 => 0xDC and 0xDB => 0xDD. 82 | */ 83 | static uint32_t send_tx_byte_encoded(void); 84 | 85 | /**@brief Function for transferring the SLIP end frame byte, 0xC0. 86 | */ 87 | static uint32_t send_tx_byte_end(void); 88 | 89 | /**@brief Function pointer for sending a byte through the UART module. 90 | */ 91 | uint32_t (*send_tx_byte) (void) = send_tx_byte_default; 92 | 93 | 94 | static uint32_t send_tx_byte_end(void) 95 | { 96 | uint32_t err_code = app_uart_put(APP_SLIP_END); 97 | 98 | if ((err_code == NRF_SUCCESS) && (m_tx_buffer_index == 0)) 99 | { 100 | // Packet transmission started. 101 | send_tx_byte = send_tx_byte_default; 102 | } 103 | 104 | return err_code; 105 | } 106 | 107 | 108 | static uint32_t send_tx_byte_default(void) 109 | { 110 | uint32_t err_code = app_uart_put(mp_tx_buffer[m_tx_buffer_index]); 111 | 112 | if (err_code == NRF_SUCCESS) 113 | { 114 | m_tx_buffer_index++; 115 | } 116 | 117 | return err_code; 118 | } 119 | 120 | 121 | static uint32_t send_tx_byte_encoded(void) 122 | { 123 | uint32_t err_code; 124 | 125 | switch(mp_tx_buffer[m_tx_buffer_index]) 126 | { 127 | case APP_SLIP_END: 128 | err_code = app_uart_put(APP_SLIP_ESC_END); 129 | break; 130 | 131 | case APP_SLIP_ESC: 132 | err_code = app_uart_put(APP_SLIP_ESC_ESC); 133 | break; 134 | 135 | default: 136 | err_code = NRF_ERROR_NO_MEM; 137 | break; 138 | } 139 | 140 | if (err_code == NRF_SUCCESS) 141 | { 142 | m_tx_buffer_index++; 143 | send_tx_byte = send_tx_byte_default; 144 | } 145 | 146 | return err_code; 147 | } 148 | 149 | 150 | static uint32_t send_tx_byte_esc(void) 151 | { 152 | uint32_t err_code = app_uart_put(APP_SLIP_ESC); 153 | 154 | if (err_code == NRF_SUCCESS) 155 | { 156 | send_tx_byte = send_tx_byte_encoded; 157 | } 158 | 159 | return err_code; 160 | } 161 | 162 | 163 | /** @brief Function for transferring the content of the mp_tx_buffer to the UART. 164 | * It continues to transfer bytes until the UART buffer is full or the complete buffer is 165 | * transferred. 166 | */ 167 | static void transmit_buffer(void) 168 | { 169 | uint32_t err_code = NRF_SUCCESS; 170 | 171 | while (m_tx_buffer_index < m_tx_buffer_length) 172 | { 173 | if ((mp_tx_buffer[m_tx_buffer_index] == APP_SLIP_END || 174 | mp_tx_buffer[m_tx_buffer_index] == APP_SLIP_ESC) && 175 | send_tx_byte == send_tx_byte_default) 176 | { 177 | send_tx_byte = send_tx_byte_esc; 178 | } 179 | 180 | err_code = send_tx_byte(); 181 | 182 | if (err_code == NRF_ERROR_NO_MEM) 183 | { 184 | // No memory left in UART TX buffer. Abort and wait for APP_UART_TX_EMPTY to continue. 185 | return; 186 | } 187 | } 188 | 189 | send_tx_byte = send_tx_byte_end; 190 | 191 | err_code = send_tx_byte(); 192 | 193 | if (err_code == NRF_SUCCESS) 194 | { 195 | // Packet transmission ended. Notify higher level. 196 | m_current_state = SLIP_READY; 197 | 198 | if (m_slip_event_handler != NULL) 199 | { 200 | hci_slip_evt_t event = {HCI_SLIP_TX_DONE, mp_tx_buffer, m_tx_buffer_index}; 201 | 202 | m_slip_event_handler(event); 203 | } 204 | } 205 | } 206 | 207 | 208 | /** @brief Function for handling the reception of a SLIP end byte. 209 | * If the number of bytes received is greater than zero it will call m_slip_event_handler 210 | * with number of bytes received and invalidate the mp_rx_buffer to protect against data 211 | * corruption. 212 | * No new bytes can be received until a new RX buffer is supplied. 213 | */ 214 | static void handle_slip_end(void) 215 | { 216 | if (m_rx_received_count > 0) 217 | { 218 | // Full packet received, push it up. 219 | if (m_slip_event_handler != NULL) 220 | { 221 | hci_slip_evt_t event = {HCI_SLIP_RX_RDY, mp_rx_buffer, m_rx_received_count}; 222 | 223 | m_rx_received_count = 0; 224 | mp_rx_buffer = NULL; 225 | 226 | m_slip_event_handler(event); 227 | } 228 | } 229 | } 230 | 231 | 232 | static void handle_rx_byte_esc(uint8_t byte) 233 | { 234 | switch (byte) 235 | { 236 | case APP_SLIP_END: 237 | handle_slip_end(); 238 | break; 239 | 240 | case APP_SLIP_ESC_END: 241 | mp_rx_buffer[m_rx_received_count++] = APP_SLIP_END; 242 | break; 243 | 244 | case APP_SLIP_ESC_ESC: 245 | mp_rx_buffer[m_rx_received_count++] = APP_SLIP_ESC; 246 | break; 247 | 248 | default: 249 | mp_rx_buffer[m_rx_received_count++] = byte; 250 | break; 251 | } 252 | 253 | handle_rx_byte = handle_rx_byte_default; 254 | } 255 | 256 | 257 | static void handle_rx_byte_default(uint8_t byte) 258 | { 259 | switch (byte) 260 | { 261 | case APP_SLIP_END: 262 | handle_slip_end(); 263 | break; 264 | 265 | case APP_SLIP_ESC: 266 | handle_rx_byte = handle_rx_byte_esc; 267 | break; 268 | 269 | default: 270 | mp_rx_buffer[m_rx_received_count++] = byte; 271 | break; 272 | } 273 | } 274 | 275 | 276 | static void handle_rx_byte_wait_start(uint8_t byte) 277 | { 278 | if (byte == APP_SLIP_END) 279 | { 280 | handle_rx_byte = handle_rx_byte_default; 281 | } 282 | } 283 | 284 | 285 | /** @brief Function for checking the current index and length of the RX buffer to determine if the 286 | * buffer is full. If an event handler has been registered, the callback function will 287 | * be executed.. 288 | * 289 | * @retval true If RX buffer has overflowed. 290 | * @retval false otherwise. 291 | * 292 | */ 293 | static bool rx_buffer_overflowed(void) 294 | { 295 | if (mp_rx_buffer == NULL || m_rx_received_count >= m_rx_buffer_length) 296 | { 297 | if (m_slip_event_handler != NULL) 298 | { 299 | hci_slip_evt_t event = {HCI_SLIP_RX_OVERFLOW, mp_rx_buffer, m_rx_received_count}; 300 | m_slip_event_handler(event); 301 | } 302 | 303 | return true; 304 | } 305 | 306 | return false; 307 | } 308 | 309 | 310 | /** @brief Function for handling the UART module event. It parses events from the UART when 311 | * bytes are received/transmitted. 312 | * 313 | * @param[in] uart_event Event received from app_uart module. 314 | */ 315 | static void slip_uart_eventhandler(app_uart_evt_t * uart_event) 316 | { 317 | if (uart_event->evt_type == APP_UART_TX_EMPTY && m_current_state == SLIP_TRANSMITTING) 318 | { 319 | transmit_buffer(); 320 | } 321 | 322 | if ((uart_event->evt_type == APP_UART_DATA) && (!rx_buffer_overflowed())) 323 | { 324 | handle_rx_byte(uart_event->data.value); 325 | } 326 | } 327 | 328 | 329 | /** @brief Function for enabling the UART module when the SLIP layer is opened. 330 | */ 331 | static uint32_t slip_uart_open(void) 332 | { 333 | uint32_t err_code; 334 | 335 | app_uart_comm_params_t comm_params = 336 | { 337 | HCI_SLIP_UART_RX_PIN_NUMBER, 338 | HCI_SLIP_UART_TX_PIN_NUMBER, 339 | HCI_SLIP_UART_RTS_PIN_NUMBER, 340 | HCI_SLIP_UART_CTS_PIN_NUMBER, 341 | HCI_SLIP_UART_MODE, 342 | false, 343 | HCI_SLIP_UART_BAUDRATE 344 | }; 345 | 346 | err_code = app_uart_init(&comm_params, 347 | NULL, 348 | slip_uart_eventhandler, 349 | APP_IRQ_PRIORITY_LOW, 350 | &m_uart_id); 351 | 352 | if (err_code == NRF_SUCCESS) 353 | { 354 | m_current_state = SLIP_READY; 355 | } 356 | 357 | return err_code; 358 | } 359 | 360 | 361 | uint32_t hci_slip_evt_handler_register(hci_slip_event_handler_t event_handler) 362 | { 363 | m_slip_event_handler = event_handler; 364 | 365 | return NRF_SUCCESS; 366 | } 367 | 368 | 369 | uint32_t hci_slip_open() 370 | { 371 | switch (m_current_state) 372 | { 373 | case SLIP_OFF: 374 | return slip_uart_open(); 375 | 376 | default: 377 | // Do nothing. 378 | break; 379 | } 380 | 381 | return NRF_SUCCESS; 382 | } 383 | 384 | 385 | uint32_t hci_slip_close() 386 | { 387 | m_current_state = SLIP_OFF; 388 | uint32_t err_code = app_uart_close(m_uart_id); 389 | 390 | return err_code; 391 | } 392 | 393 | 394 | uint32_t hci_slip_write(const uint8_t * p_buffer, uint32_t length) 395 | { 396 | if (p_buffer == NULL) 397 | { 398 | return NRF_ERROR_INVALID_ADDR; 399 | } 400 | 401 | switch (m_current_state) 402 | { 403 | case SLIP_READY: 404 | m_tx_buffer_index = 0; 405 | m_tx_buffer_length = length; 406 | mp_tx_buffer = p_buffer; 407 | m_current_state = SLIP_TRANSMITTING; 408 | send_tx_byte = send_tx_byte_end; 409 | 410 | transmit_buffer(); 411 | return NRF_SUCCESS; 412 | 413 | case SLIP_TRANSMITTING: 414 | return NRF_ERROR_NO_MEM; 415 | 416 | case SLIP_OFF: 417 | default: 418 | return NRF_ERROR_INVALID_STATE; 419 | } 420 | } 421 | 422 | 423 | uint32_t hci_slip_rx_buffer_register(uint8_t * p_buffer, uint32_t length) 424 | { 425 | mp_rx_buffer = p_buffer; 426 | m_rx_buffer_length = length; 427 | m_rx_received_count = 0; 428 | handle_rx_byte = handle_rx_byte_wait_start; 429 | return NRF_SUCCESS; 430 | } 431 | -------------------------------------------------------------------------------- /app_common/hci_transport.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013 Nordic Semiconductor. All Rights Reserved. 2 | * 3 | * The information contained herein is property of Nordic Semiconductor ASA. 4 | * Terms and conditions of usage are described in detail in NORDIC 5 | * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. 6 | * 7 | * Licensees are granted free, non-transferable use of the information. NO 8 | * WARRANTY of ANY KIND is provided. This heading must NOT be removed from 9 | * the file. 10 | * 11 | */ 12 | 13 | #include "hal_transport.h" 14 | #include "hci_transport_config.h" 15 | #include "hci_slip.h" 16 | #include "crc16.h" 17 | #include "hci_mem_pool.h" 18 | #include "hci_mem_pool_internal.h" 19 | #include "nordic_common.h" 20 | #include "compiler_abstraction.h" 21 | #include "app_util.h" 22 | #include "app_timer.h" 23 | #include "app_error.h" 24 | #include 25 | #include 26 | 27 | #define PKT_HDR_SIZE 4u /**< Packet header size in number of bytes. */ 28 | #define PKT_CRC_SIZE 2u /**< Packet CRC size in number of bytes. */ 29 | #define PKT_TYPE_VENDOR_SPECIFIC 14u /**< Packet type vendor specific. */ 30 | #define PKT_TYPE_ACK 0 /**< Packet type acknowledgement. */ 31 | #define DATA_INTEGRITY_MASK (1u << 6u) /**< Mask for data integrity bit in the packet header. */ 32 | #define RELIABLE_PKT_MASK (1u << 7u) /**< Mask for reliable packet bit in the packet header. */ 33 | #define INITIAL_ACK_NUMBER_EXPECTED 1u /**< Initial acknowledge number expected. */ 34 | #define INITIAL_ACK_NUMBER_TX INITIAL_ACK_NUMBER_EXPECTED /**< Initial acknowledge number transmitted. */ 35 | #define INVALID_PKT_TYPE 0xFFFFFFFFu /**< Internal invalid packet type value. */ 36 | #define MAX_TRANSMISSION_TIME (ROUNDED_DIV((MAX_PACKET_SIZE_IN_BITS * 1000u), USED_BAUD_RATE)) /**< Max transmission time of a single application packet over UART in units of mseconds. */ 37 | #define RETRANSMISSION_TIMEOUT_IN_MS (3u * MAX_TRANSMISSION_TIME) /**< Retransmission timeout for application packet in units of mseconds. */ 38 | #define APP_TIMER_PRESCALER 0 /**< Value of the RTC1 PRESCALER register. */ 39 | #define RETRANSMISSION_TIMEOUT_IN_TICKS APP_TIMER_TICKS(RETRANSMISSION_TIMEOUT_IN_MS, APP_TIMER_PRESCALER) /**< Retransmission timeout for application packet in units of timer ticks. */ 40 | #define MAX_RETRY_COUNT 5u /**< Max retransmission retry count for application packets. */ 41 | #define ACK_BUF_SIZE 5u /**< Length of module internal RX buffer which is big enough to hold an acknowledgement packet. */ 42 | 43 | /**@brief States of the TX state machine. */ 44 | typedef enum 45 | { 46 | TX_STATE_IDLE, /**< State for: no application transmission packet processing in progress. */ 47 | TX_STATE_PENDING, /**< State for: TX in progress in slip layer and TX-done event is waited for to signal the end of transmission. */ 48 | TX_STATE_ACTIVE /**< State for: application packet has been delivered to slip for transmission and peer transport entity acknowledgement packet is waited for. */ 49 | } tx_state_t; 50 | 51 | /**@brief TX state machine events. */ 52 | typedef enum 53 | { 54 | TX_EVENT_STATE_ENTRY, /**< Event for: state entry use case. */ 55 | TX_EVENT_SLIP_TX_DONE, /**< Event for: HCI_SLIP_TX_DONE event use case. */ 56 | TX_EVENT_TIMEOUT, /**< Event for: retransmission timeout use case. */ 57 | TX_EVENT_VALID_RX_ACK /**< Event for: valid acknowledgement received for TX packet use case. */ 58 | } tx_event_t; 59 | 60 | static void tx_sm_state_change(tx_state_t new_state); 61 | 62 | static tx_state_t m_tx_state; /**< Current TX state. */ 63 | static hci_transport_tx_done_handler_t m_transport_tx_done_handle; /**< TX done event callback function. */ 64 | static hci_transport_event_handler_t m_transport_event_handle; /**< Event handler callback function. */ 65 | static uint8_t * mp_slip_used_rx_buffer; /**< Reference to RX buffer used by the slip layer. */ 66 | static uint32_t m_packet_expected_seq_number; /**< Sequence number counter of the packet expected to be received . */ 67 | static uint32_t m_packet_transmit_seq_number; /**< Sequence number counter of the transmitted packet for which acknowledgement packet is waited for. */ 68 | static uint8_t * mp_tx_buffer; /**< Pointer to TX application buffer to be transmitted. */ 69 | static uint32_t m_tx_buffer_length; /**< Length of application TX packet data to be transmitted in bytes. */ 70 | static bool m_is_slip_decode_ready; /**< Boolean to determine has slip decode been completed or not. */ 71 | static app_timer_id_t m_app_timer_id; /**< Application timer id. */ 72 | static uint32_t m_tx_retry_counter; /**< Application packet retransmission counter. */ 73 | static hci_transport_tx_done_result_t m_tx_done_result_code; /**< TX done event callback function result code. */ 74 | static uint8_t m_rx_ack_buffer[ACK_BUF_SIZE];/**< RX buffer big enough to hold an acknowledgement packet and which is taken in use upon receiving HCI_SLIP_RX_OVERFLOW event. */ 75 | 76 | 77 | /**@brief Function for validating a received packet. 78 | * 79 | * @param[in] p_buffer Pointer to the packet data. 80 | * @param[in] length Length of packet data in bytes. 81 | * 82 | * @return true if received packet is valid, false in other case. 83 | */ 84 | static bool is_rx_pkt_valid(const uint8_t * p_buffer, uint32_t length) 85 | { 86 | // Executed packet filtering algorithm order: 87 | // - verify packet overall length 88 | // - verify data integrity bit set 89 | // - verify reliable packet bit set 90 | // - verify supported packet type 91 | // - verify header checksum 92 | // - verify payload length field 93 | // - verify CRC 94 | if (length <= PKT_HDR_SIZE) 95 | { 96 | return false; 97 | } 98 | 99 | if (!(p_buffer[0] & DATA_INTEGRITY_MASK)) 100 | { 101 | return false; 102 | } 103 | 104 | if (!(p_buffer[0] & RELIABLE_PKT_MASK)) 105 | { 106 | return false; 107 | } 108 | 109 | if ((p_buffer[1] & 0x0Fu) != PKT_TYPE_VENDOR_SPECIFIC) 110 | { 111 | return false; 112 | } 113 | 114 | const uint32_t expected_checksum = 115 | ((p_buffer[0] + p_buffer[1] + p_buffer[2] + p_buffer[3])) & 0xFFu; 116 | if (expected_checksum != 0) 117 | { 118 | return false; 119 | } 120 | 121 | const uint16_t crc_calculated = crc16_compute(p_buffer, (length - PKT_CRC_SIZE), NULL); 122 | const uint16_t crc_received = uint16_decode(&p_buffer[length - PKT_CRC_SIZE]); 123 | if (crc_calculated != crc_received) 124 | { 125 | return false; 126 | } 127 | 128 | return true; 129 | } 130 | 131 | 132 | /**@brief Function for getting the sequence number of the next reliable packet expected. 133 | * 134 | * @return sequence number of the next reliable packet expected. 135 | */ 136 | static __INLINE uint8_t packet_number_expected_get(void) 137 | { 138 | return (uint8_t) m_packet_expected_seq_number; 139 | } 140 | 141 | 142 | /**@brief Function for calculating a packet header checksum. 143 | * 144 | * @param[in] p_hdr Pointer to the packet header. 145 | * 146 | * @return Calculated checksum. 147 | */ 148 | static uint8_t header_checksum_calculate(const uint8_t * p_hdr) 149 | { 150 | // @note: no pointer validation check needed as already checked by calling function. 151 | uint32_t checksum; 152 | 153 | checksum = p_hdr[0]; 154 | checksum += p_hdr[1]; 155 | checksum += p_hdr[2]; 156 | checksum &= 0xFFu; 157 | checksum = (~checksum + 1u); 158 | 159 | return (uint8_t)checksum; 160 | } 161 | 162 | 163 | /**@brief Function for writing an acknowledgment packet for transmission. 164 | */ 165 | static void ack_transmit(void) 166 | { 167 | static uint8_t ack_packet[PKT_HDR_SIZE]; 168 | 169 | // TX ACK packet format: 170 | // - Unreliable Packet type 171 | // - Payload Length set to 0 172 | // - Sequence Number set to 0 173 | // - Header checksum calculated 174 | // - Acknowledge Number set correctly 175 | ack_packet[0] = (packet_number_expected_get() << 3u); 176 | ack_packet[1] = 0; 177 | ack_packet[2] = 0; 178 | ack_packet[3] = header_checksum_calculate(ack_packet); 179 | 180 | // @note: no return value check needed for hci_slip_write(...) call as acknowledgement packets 181 | // are considered to be from system design point of view unreliable packets.Use case where 182 | // underlying slip layer does not accept a packet for transmission is managed either by: 183 | // - acknowledged by possible future application packet as acknowledgement number header field 184 | // is included 185 | // - protocol peer entity will retransmit the packet 186 | UNUSED_VARIABLE(hci_slip_write(ack_packet, sizeof(ack_packet))); 187 | } 188 | 189 | 190 | /**@brief Function for validating a received packet. 191 | * 192 | * @param[in] p_buffer Pointer to the packet data. 193 | * 194 | * @return sequence number field of the packet header with unrelated data masked out. 195 | */ 196 | static __INLINE uint8_t packet_seq_nmbr_extract(const uint8_t * p_buffer) 197 | { 198 | return (p_buffer[0] & 0x07u); 199 | } 200 | 201 | 202 | /**@brief Function for incrementing the sequence number counter for next reliable packet expected. 203 | */ 204 | static __INLINE void packet_number_expected_inc(void) 205 | { 206 | ++m_packet_expected_seq_number; 207 | m_packet_expected_seq_number &= 0x07u; 208 | } 209 | 210 | 211 | /**@brief Function for decoding a packet type field. 212 | * 213 | * @param[in] p_buffer Pointer to the packet data. 214 | * @param[in] length Length of packet data in bytes. 215 | * 216 | * @return Packet type field or INVALID_PKT_TYPE in case of decode error. 217 | */ 218 | static __INLINE uint32_t packet_type_decode(const uint8_t * p_buffer, uint32_t length) 219 | { 220 | // @note: no pointer validation check needed as allready checked by calling function. 221 | uint32_t return_value; 222 | 223 | if (length >= PKT_HDR_SIZE) 224 | { 225 | return_value = (p_buffer[1] & 0x0Fu); 226 | } 227 | else 228 | { 229 | return_value = INVALID_PKT_TYPE; 230 | } 231 | 232 | return return_value; 233 | } 234 | 235 | 236 | /**@brief Function for processing a received vendor specific packet. 237 | * 238 | * @param[in] p_buffer Pointer to the packet data. 239 | * @param[in] length Length of packet data in bytes. 240 | */ 241 | static void rx_vendor_specific_pkt_type_handle(const uint8_t * p_buffer, uint32_t length) 242 | { 243 | // @note: no pointer validation check needed as allready checked by calling function. 244 | uint32_t err_code; 245 | 246 | if (is_rx_pkt_valid(p_buffer, length)) 247 | { 248 | // RX packet is valid: validate sequence number. 249 | const uint8_t rx_seq_number = packet_seq_nmbr_extract(p_buffer); 250 | if (packet_number_expected_get() == rx_seq_number) 251 | { 252 | // Sequence number is valid: transmit acknowledgement. 253 | packet_number_expected_inc(); 254 | ack_transmit(); 255 | 256 | m_is_slip_decode_ready = true; 257 | 258 | err_code = hci_mem_pool_rx_data_size_set(length); 259 | APP_ERROR_CHECK(err_code); 260 | 261 | err_code = hci_mem_pool_rx_produce(RX_BUF_SIZE, (void **)&mp_slip_used_rx_buffer); 262 | APP_ERROR_CHECK_BOOL((err_code == NRF_SUCCESS) || (err_code == NRF_ERROR_NO_MEM)); 263 | 264 | // If memory pool RX buffer produce succeeded we register that buffer to slip layer 265 | // otherwise we register the internal acknowledgement buffer. 266 | err_code = hci_slip_rx_buffer_register( 267 | (err_code == NRF_SUCCESS) ? mp_slip_used_rx_buffer : m_rx_ack_buffer, 268 | (err_code == NRF_SUCCESS) ? RX_BUF_SIZE : ACK_BUF_SIZE); 269 | 270 | APP_ERROR_CHECK(err_code); 271 | 272 | if (m_transport_event_handle != NULL) 273 | { 274 | // Send application event of RX packet reception. 275 | const hci_transport_evt_t evt = {HCI_TRANSPORT_RX_RDY}; 276 | m_transport_event_handle(evt); 277 | } 278 | } 279 | else 280 | { 281 | // RX packet discarded: sequence number not valid, set the same buffer to slip layer in 282 | // order to avoid buffer overrun. 283 | err_code = hci_slip_rx_buffer_register(mp_slip_used_rx_buffer, RX_BUF_SIZE); 284 | APP_ERROR_CHECK(err_code); 285 | 286 | // As packet did not have expected sequence number: send acknowledgement with the 287 | // current expected sequence number. 288 | ack_transmit(); 289 | } 290 | } 291 | else 292 | { 293 | // RX packet discarded: reset the same buffer to slip layer in order to avoid buffer 294 | // overrun. 295 | err_code = hci_slip_rx_buffer_register(mp_slip_used_rx_buffer, RX_BUF_SIZE); 296 | APP_ERROR_CHECK(err_code); 297 | } 298 | } 299 | 300 | 301 | /**@brief Function for getting the sequence number of a reliable TX packet for which peer protocol 302 | * entity acknowledgment is pending. 303 | * 304 | * @return sequence number of a reliable TX packet for which peer protocol entity acknowledgement 305 | * is pending. 306 | */ 307 | static __INLINE uint8_t packet_number_to_transmit_get(void) 308 | { 309 | return m_packet_transmit_seq_number; 310 | } 311 | 312 | 313 | /**@brief Function for getting the expected acknowledgement number. 314 | * 315 | * @return expected acknowledgement number. 316 | */ 317 | static __INLINE uint8_t expected_ack_number_get(void) 318 | { 319 | uint8_t seq_nmbr = packet_number_to_transmit_get(); 320 | ++seq_nmbr; 321 | seq_nmbr &= 0x07u; 322 | 323 | return seq_nmbr; 324 | } 325 | 326 | 327 | /**@brief Function for processing a received acknowledgement packet. 328 | * 329 | * Verifies does the received acknowledgement packet has the expected acknowledgement number and 330 | * that the header checksum is correct. 331 | * 332 | * @param[in] p_buffer Pointer to the packet data. 333 | * 334 | * @return true if valid acknowledgement packet received. 335 | */ 336 | static __INLINE bool rx_ack_pkt_type_handle(const uint8_t * p_buffer) 337 | { 338 | // @note: no pointer validation check needed as allready checked by calling function. 339 | 340 | // Verify header checksum. 341 | const uint32_t expected_checksum = 342 | ((p_buffer[0] + p_buffer[1] + p_buffer[2] + p_buffer[3])) & 0xFFu; 343 | if (expected_checksum != 0) 344 | { 345 | return false; 346 | } 347 | 348 | const uint8_t ack_number = (p_buffer[0] >> 3u) & 0x07u; 349 | 350 | // Verify expected acknowledgment number. 351 | return (ack_number == expected_ack_number_get()); 352 | } 353 | 354 | 355 | /**@brief Function for incrementing the sequence number counter of the TX packet. 356 | */ 357 | static __INLINE void packet_number_tx_inc(void) 358 | { 359 | ++m_packet_transmit_seq_number; 360 | m_packet_transmit_seq_number &= 0x07u; 361 | } 362 | 363 | 364 | /**@brief Function for TX state machine event processing in a state centric manner. 365 | * 366 | * @param[in] event Type of event occurred. 367 | */ 368 | static void tx_sm_event_handle(tx_event_t event) 369 | { 370 | uint32_t err_code; 371 | 372 | switch (m_tx_state) 373 | { 374 | case TX_STATE_IDLE: 375 | if (event == TX_EVENT_STATE_ENTRY) 376 | { 377 | err_code = app_timer_stop(m_app_timer_id); 378 | APP_ERROR_CHECK(err_code); 379 | 380 | // Send TX-done event if registered handler exists. 381 | if (m_transport_tx_done_handle != NULL) 382 | { 383 | m_transport_tx_done_handle(m_tx_done_result_code); 384 | } 385 | } 386 | break; 387 | 388 | case TX_STATE_PENDING: 389 | if (event == TX_EVENT_SLIP_TX_DONE) 390 | { 391 | // @note: this call should always succeed as called from HCI_SLIP_TX_DONE context 392 | // and error cases are managed by dedicated error event from the slip layer. 393 | err_code = hci_slip_write(mp_tx_buffer, 394 | (m_tx_buffer_length + PKT_HDR_SIZE + PKT_CRC_SIZE)); 395 | APP_ERROR_CHECK(err_code); 396 | tx_sm_state_change(TX_STATE_ACTIVE); 397 | } 398 | break; 399 | 400 | case TX_STATE_ACTIVE: 401 | switch (event) 402 | { 403 | case TX_EVENT_VALID_RX_ACK: 404 | // Tx sequence number counter incremented as packet transmission 405 | // acknowledged by peer transport entity. 406 | packet_number_tx_inc(); 407 | tx_sm_state_change(TX_STATE_IDLE); 408 | break; 409 | 410 | case TX_EVENT_STATE_ENTRY: 411 | m_tx_retry_counter = 0; 412 | err_code = app_timer_start(m_app_timer_id, 413 | RETRANSMISSION_TIMEOUT_IN_TICKS, 414 | NULL); 415 | APP_ERROR_CHECK(err_code); 416 | break; 417 | 418 | case TX_EVENT_TIMEOUT: 419 | if (m_tx_retry_counter != MAX_RETRY_COUNT) 420 | { 421 | ++m_tx_retry_counter; 422 | // @note: no return value check done for hci_slip_write(...) call as current 423 | // system design allows use case where retransmission is not accepted by the 424 | // slip layer due to existing acknowledgement packet transmission in the 425 | // slip layer. 426 | UNUSED_VARIABLE(hci_slip_write(mp_tx_buffer, 427 | (m_tx_buffer_length + 428 | PKT_HDR_SIZE + 429 | PKT_CRC_SIZE))); 430 | } 431 | else 432 | { 433 | // Application packet retransmission count reached: 434 | // - set correct TX done event callback function result code 435 | // - execute state change 436 | // @note: m_tx_retry_counter is reset in TX_STATE_ACTIVE state entry. 437 | m_tx_done_result_code = HCI_TRANSPORT_TX_DONE_FAILURE; 438 | tx_sm_state_change(TX_STATE_IDLE); 439 | } 440 | break; 441 | 442 | default: 443 | // No implementation needed. 444 | break; 445 | } 446 | break; 447 | 448 | default: 449 | // No implementation needed. 450 | break; 451 | } 452 | } 453 | 454 | 455 | /**@brief Function for changing the state of the TX state machine. 456 | * 457 | * @param[in] new_state State TX state machine transits to. 458 | */ 459 | static void tx_sm_state_change(tx_state_t new_state) 460 | { 461 | m_tx_state = new_state; 462 | tx_sm_event_handle(TX_EVENT_STATE_ENTRY); 463 | } 464 | 465 | 466 | /**@brief Function for handling slip events. 467 | * 468 | * @param[in] event The event structure. 469 | */ 470 | void slip_event_handle(hci_slip_evt_t event) 471 | { 472 | uint32_t return_code; 473 | uint32_t err_code; 474 | 475 | switch (event.evt_type) 476 | { 477 | case HCI_SLIP_TX_DONE: 478 | tx_sm_event_handle(TX_EVENT_SLIP_TX_DONE); 479 | break; 480 | 481 | case HCI_SLIP_RX_RDY: 482 | return_code = packet_type_decode(event.packet, event.packet_length); 483 | 484 | switch (return_code) 485 | { 486 | case PKT_TYPE_VENDOR_SPECIFIC: 487 | rx_vendor_specific_pkt_type_handle(event.packet, event.packet_length); 488 | break; 489 | 490 | case PKT_TYPE_ACK: 491 | if (rx_ack_pkt_type_handle(event.packet)) 492 | { 493 | // Valid expected acknowledgement packet received: set correct TX done event 494 | // callback function result code and execute state change. 495 | m_tx_done_result_code = HCI_TRANSPORT_TX_DONE_SUCCESS; 496 | tx_sm_event_handle(TX_EVENT_VALID_RX_ACK); 497 | } 498 | 499 | /* fall-through */ 500 | default: 501 | // RX packet dropped: reset memory buffer to slip in order to avoid RX buffer 502 | // overflow. 503 | // If existing mem pool produced RX buffer exists reuse that one. If existing 504 | // mem pool produced RX buffer does not exist try to produce new one. If 505 | // producing fails use the internal acknowledgement buffer. 506 | if (mp_slip_used_rx_buffer != NULL) 507 | { 508 | err_code = hci_slip_rx_buffer_register(mp_slip_used_rx_buffer, RX_BUF_SIZE); 509 | APP_ERROR_CHECK(err_code); 510 | } 511 | else 512 | { 513 | err_code = hci_mem_pool_rx_produce(RX_BUF_SIZE, 514 | (void **)&mp_slip_used_rx_buffer); 515 | APP_ERROR_CHECK_BOOL((err_code == NRF_SUCCESS) || 516 | (err_code == NRF_ERROR_NO_MEM)); 517 | 518 | err_code = hci_slip_rx_buffer_register( 519 | (err_code == NRF_SUCCESS) ? mp_slip_used_rx_buffer : m_rx_ack_buffer, 520 | (err_code == NRF_SUCCESS) ? RX_BUF_SIZE : ACK_BUF_SIZE); 521 | APP_ERROR_CHECK(err_code); 522 | } 523 | break; 524 | } 525 | break; 526 | 527 | case HCI_SLIP_RX_OVERFLOW: 528 | err_code = hci_slip_rx_buffer_register(m_rx_ack_buffer, ACK_BUF_SIZE); 529 | APP_ERROR_CHECK(err_code); 530 | break; 531 | 532 | case HCI_SLIP_ERROR: 533 | APP_ERROR_HANDLER(event.evt_type); 534 | break; 535 | 536 | default: 537 | APP_ERROR_HANDLER(event.evt_type); 538 | break; 539 | } 540 | } 541 | 542 | 543 | uint32_t hci_transport_evt_handler_reg(hci_transport_event_handler_t event_handler) 544 | { 545 | uint32_t err_code; 546 | 547 | m_transport_event_handle = event_handler; 548 | err_code = hci_slip_evt_handler_register(slip_event_handle); 549 | APP_ERROR_CHECK(err_code); 550 | 551 | return (event_handler != NULL) ? NRF_SUCCESS : NRF_ERROR_NULL; 552 | } 553 | 554 | 555 | uint32_t hci_transport_tx_done_register(hci_transport_tx_done_handler_t event_handler) 556 | { 557 | uint32_t err_code; 558 | 559 | m_transport_tx_done_handle = event_handler; 560 | err_code = hci_slip_evt_handler_register(slip_event_handle); 561 | APP_ERROR_CHECK(err_code); 562 | 563 | return (event_handler != NULL) ? NRF_SUCCESS : NRF_ERROR_NULL; 564 | } 565 | 566 | 567 | /**@brief Function for handling the application packet retransmission timeout. 568 | * 569 | * This function is registered in the @ref app_timer module when a timer is created on 570 | * @ref hci_transport_open. 571 | * 572 | * @note This function must be executed in APP-LO context otherwise retransmission behaviour is 573 | * undefined, see @ref nrf51_system_integration_serialization. 574 | * 575 | * @param[in] p_context The timeout context. 576 | */ 577 | void hci_transport_timeout_handle(void * p_context) 578 | { 579 | tx_sm_event_handle(TX_EVENT_TIMEOUT); 580 | } 581 | 582 | 583 | uint32_t hci_transport_open(void) 584 | { 585 | mp_tx_buffer = NULL; 586 | m_tx_buffer_length = 0; 587 | m_tx_retry_counter = 0; 588 | m_is_slip_decode_ready = false; 589 | m_tx_state = TX_STATE_IDLE; 590 | m_packet_expected_seq_number = INITIAL_ACK_NUMBER_EXPECTED; 591 | m_packet_transmit_seq_number = INITIAL_ACK_NUMBER_TX; 592 | m_tx_done_result_code = HCI_TRANSPORT_TX_DONE_FAILURE; 593 | 594 | uint32_t err_code = app_timer_create(&m_app_timer_id, 595 | APP_TIMER_MODE_REPEATED, 596 | hci_transport_timeout_handle); 597 | if (err_code != NRF_SUCCESS) 598 | { 599 | // @note: conduct required interface adjustment. 600 | return NRF_ERROR_INTERNAL; 601 | } 602 | 603 | err_code = hci_mem_pool_open(); 604 | if (err_code != NRF_SUCCESS) 605 | { 606 | return err_code; 607 | } 608 | 609 | err_code = hci_slip_open(); 610 | if (err_code != NRF_SUCCESS) 611 | { 612 | return err_code; 613 | } 614 | 615 | err_code = hci_mem_pool_rx_produce(RX_BUF_SIZE, (void **)&mp_slip_used_rx_buffer); 616 | if (err_code != NRF_SUCCESS) 617 | { 618 | // @note: conduct required interface adjustment. 619 | return NRF_ERROR_INTERNAL; 620 | } 621 | 622 | err_code = hci_slip_rx_buffer_register(mp_slip_used_rx_buffer, RX_BUF_SIZE); 623 | 624 | return err_code; 625 | } 626 | 627 | 628 | uint32_t hci_transport_close(void) 629 | { 630 | uint32_t err_code; 631 | 632 | m_transport_tx_done_handle = NULL; 633 | m_transport_event_handle = NULL; 634 | 635 | err_code = hci_mem_pool_close(); 636 | APP_ERROR_CHECK(err_code); 637 | err_code = hci_slip_close(); 638 | APP_ERROR_CHECK(err_code); 639 | 640 | // @note: NRF_ERROR_NO_MEM is the only return value which should never be returned. 641 | err_code = app_timer_stop(m_app_timer_id); 642 | APP_ERROR_CHECK_BOOL(err_code != NRF_ERROR_NO_MEM); 643 | 644 | return NRF_SUCCESS; 645 | } 646 | 647 | 648 | uint32_t hci_transport_tx_alloc(uint8_t ** pp_memory) 649 | { 650 | const uint32_t err_code = hci_mem_pool_tx_alloc((void **)pp_memory); 651 | if (err_code == NRF_SUCCESS) 652 | { 653 | // @note: no need to validate pp_memory against null as validation has already been done 654 | // by hci_mem_pool_tx_alloc(...) and visible to us from the method return code. 655 | //lint -e(413) "Likely use of null pointer" 656 | *pp_memory += PKT_HDR_SIZE; 657 | } 658 | 659 | return err_code; 660 | } 661 | 662 | 663 | uint32_t hci_transport_tx_free(void) 664 | { 665 | return hci_mem_pool_tx_free(); 666 | } 667 | 668 | 669 | /**@brief Function for constructing 1st byte of the packet header of the packet to be transmitted. 670 | * 671 | * @return 1st byte of the packet header of the packet to be transmitted 672 | */ 673 | static __INLINE uint8_t tx_packet_byte_zero_construct(void) 674 | { 675 | const uint32_t value = DATA_INTEGRITY_MASK | 676 | RELIABLE_PKT_MASK | 677 | (packet_number_expected_get() << 3u) | 678 | packet_number_to_transmit_get(); 679 | 680 | return (uint8_t) value; 681 | } 682 | 683 | 684 | /**@brief Function for handling the application packet write request in tx-idle state. 685 | */ 686 | static uint32_t pkt_write_handle(void) 687 | { 688 | uint32_t err_code; 689 | 690 | // Set packet header fields. 691 | 692 | mp_tx_buffer -= PKT_HDR_SIZE; 693 | mp_tx_buffer[0] = tx_packet_byte_zero_construct(); 694 | 695 | const uint16_t type_and_length_fields = ((m_tx_buffer_length << 4u) | PKT_TYPE_VENDOR_SPECIFIC); 696 | // @note: no use case for uint16_encode(...) return value. 697 | UNUSED_VARIABLE(uint16_encode(type_and_length_fields, &(mp_tx_buffer[1]))); 698 | mp_tx_buffer[3] = header_checksum_calculate(mp_tx_buffer); 699 | 700 | // Calculate, append CRC to the packet and write it. 701 | 702 | const uint16_t crc = crc16_compute(mp_tx_buffer, (PKT_HDR_SIZE + m_tx_buffer_length), NULL); 703 | // @note: no use case for uint16_encode(...) return value. 704 | UNUSED_VARIABLE(uint16_encode(crc, &(mp_tx_buffer[PKT_HDR_SIZE + m_tx_buffer_length]))); 705 | err_code = hci_slip_write(mp_tx_buffer, (m_tx_buffer_length + PKT_HDR_SIZE + PKT_CRC_SIZE)); 706 | switch (err_code) 707 | { 708 | case NRF_SUCCESS: 709 | tx_sm_state_change(TX_STATE_ACTIVE); 710 | break; 711 | 712 | case NRF_ERROR_NO_MEM: 713 | tx_sm_state_change(TX_STATE_PENDING); 714 | err_code = NRF_SUCCESS; 715 | break; 716 | 717 | default: 718 | // No implementation needed. 719 | break; 720 | } 721 | 722 | return err_code; 723 | } 724 | 725 | 726 | uint32_t hci_transport_pkt_write(const uint8_t * p_buffer, uint16_t length) 727 | { 728 | uint32_t err_code; 729 | 730 | if (p_buffer) 731 | { 732 | switch (m_tx_state) 733 | { 734 | case TX_STATE_IDLE: 735 | mp_tx_buffer = (uint8_t *)p_buffer; 736 | m_tx_buffer_length = length; 737 | err_code = pkt_write_handle(); 738 | break; 739 | 740 | default: 741 | err_code = NRF_ERROR_NO_MEM; 742 | break; 743 | } 744 | } 745 | else 746 | { 747 | err_code = NRF_ERROR_NULL; 748 | } 749 | 750 | return err_code; 751 | } 752 | 753 | 754 | uint32_t hci_transport_rx_pkt_extract(uint8_t ** pp_buffer, uint16_t * p_length) 755 | { 756 | uint32_t err_code; 757 | 758 | if (pp_buffer != NULL && p_length != NULL) 759 | { 760 | uint32_t length = 0; 761 | 762 | if (m_is_slip_decode_ready) 763 | { 764 | m_is_slip_decode_ready = false; 765 | err_code = hci_mem_pool_rx_extract(pp_buffer, &length); 766 | length -= (PKT_HDR_SIZE + PKT_CRC_SIZE); 767 | 768 | *p_length = (uint16_t)length; 769 | *pp_buffer += PKT_HDR_SIZE; 770 | } 771 | else 772 | { 773 | err_code = NRF_ERROR_NO_MEM; 774 | } 775 | } 776 | else 777 | { 778 | err_code = NRF_ERROR_NULL; 779 | } 780 | 781 | return err_code; 782 | } 783 | 784 | 785 | uint32_t hci_transport_rx_pkt_consume(uint8_t * p_buffer) 786 | { 787 | return (hci_mem_pool_rx_consume(p_buffer - PKT_HDR_SIZE)); 788 | } 789 | -------------------------------------------------------------------------------- /app_timer.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2012 Nordic Semiconductor. All Rights Reserved. 2 | * 3 | * The information contained herein is property of Nordic Semiconductor ASA. 4 | * Terms and conditions of usage are described in detail in NORDIC 5 | * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. 6 | * 7 | * Licensees are granted free, non-transferable use of the information. NO 8 | * WARRANTY of ANY KIND is provided. This heading must NOT be removed from 9 | * the file. 10 | * 11 | */ 12 | 13 | /** @file 14 | * 15 | * @defgroup app_timer Application Timer 16 | * @{ 17 | * @ingroup app_common 18 | * 19 | * @brief Application timer functionality. 20 | * 21 | * @details It enables the application to create multiple timer instances based on the RTC1 22 | * peripheral. Checking for timeouts and invokation of user timeout handlers is performed 23 | * in the RTC1 interrupt handler. List handling is done using a software interrupt (SWI0). 24 | * Both interrupt handlers are running in APP_LOW priority level. 25 | * 26 | * @note When calling app_timer_start() or app_timer_stop(), the timer operation is just queued, 27 | * and the software interrupt is triggered. The actual timer start/stop operation is 28 | * executed by the SWI0 interrupt handler. Since the SWI0 interrupt is running in APP_LOW, 29 | * if the application code calling the timer function is running in APP_LOW or APP_HIGH, 30 | * the timer operation will not be performed until the application handler has returned. 31 | * This will be the case e.g. when stopping a timer from a timeout handler when not using 32 | * the scheduler. 33 | * 34 | * @details Use the USE_SCHEDULER parameter of the APP_TIMER_INIT() macro to select if the 35 | * @ref app_scheduler is to be used or not. 36 | * 37 | * @note Even if the scheduler is not used, app_timer.h will include app_scheduler.h, so when 38 | * compiling, app_scheduler.h must be available in one of the compiler include paths. 39 | */ 40 | 41 | #ifndef APP_TIMER_H__ 42 | #define APP_TIMER_H__ 43 | 44 | #include 45 | #include 46 | #include 47 | #include "app_error.h" 48 | #include "app_util.h" 49 | #include "compiler_abstraction.h" 50 | 51 | #ifdef __cplusplus 52 | extern "C" { 53 | #endif 54 | 55 | #define APP_TIMER_CLOCK_FREQ 32768 /**< Clock frequency of the RTC timer used to implement the app timer module. */ 56 | #define APP_TIMER_MIN_TIMEOUT_TICKS 5 /**< Minimum value of the timeout_ticks parameter of app_timer_start(). */ 57 | 58 | #define APP_TIMER_NODE_SIZE 40 /**< Size of app_timer.timer_node_t (only for use inside APP_TIMER_BUF_SIZE()). */ 59 | #define APP_TIMER_USER_OP_SIZE 24 /**< Size of app_timer.timer_user_op_t (only for use inside APP_TIMER_BUF_SIZE()). */ 60 | #define APP_TIMER_USER_SIZE 8 /**< Size of app_timer.timer_user_t (only for use inside APP_TIMER_BUF_SIZE()). */ 61 | #define APP_TIMER_INT_LEVELS 3 /**< Number of interrupt levels from where timer operations may be initiated (only for use inside APP_TIMER_BUF_SIZE()). */ 62 | 63 | /**@brief Compute number of bytes required to hold the application timer data structures. 64 | * 65 | * @param[in] MAX_TIMERS Maximum number of timers that can be created at any given time. 66 | * @param[in] OP_QUEUE_SIZE Size of queues holding timer operations that are pending execution. 67 | * NOTE: Due to the queue implementation, this size must be one more 68 | * than the size that is actually needed. 69 | * 70 | * @return Required application timer buffer size (in bytes). 71 | */ 72 | #define APP_TIMER_BUF_SIZE(MAX_TIMERS, OP_QUEUE_SIZE) \ 73 | ( \ 74 | ((MAX_TIMERS) * APP_TIMER_NODE_SIZE) \ 75 | + \ 76 | ( \ 77 | APP_TIMER_INT_LEVELS \ 78 | * \ 79 | (APP_TIMER_USER_SIZE + ((OP_QUEUE_SIZE) + 1) * APP_TIMER_USER_OP_SIZE) \ 80 | ) \ 81 | ) 82 | 83 | /**@brief Convert milliseconds to timer ticks. 84 | * 85 | * @note This macro uses 64 bit integer arithmetic, but as long as the macro parameters are 86 | * constants (i.e. defines), the computation will be done by the preprocessor. 87 | * 88 | * @param[in] MS Milliseconds. 89 | * @param[in] PRESCALER Value of the RTC1 PRESCALER register (must be the same value that was 90 | * passed to APP_TIMER_INIT()). 91 | * 92 | * @note When using this macro, it is the responsibility of the developer to ensure that the 93 | * values provided as input result in an output value that is supported by the 94 | * @ref app_timer_start function. For example, when the ticks for 1 ms is needed, the 95 | * maximum possible value of PRESCALER must be 6, when @ref APP_TIMER_CLOCK_FREQ is 32768. 96 | * This will result in a ticks value as 5. Any higher value for PRESCALER will result in a 97 | * ticks value that is not supported by this module. 98 | * 99 | * @return Number of timer ticks. 100 | */ 101 | #define APP_TIMER_TICKS(MS, PRESCALER)\ 102 | ((uint32_t)ROUNDED_DIV((MS) * (uint64_t)APP_TIMER_CLOCK_FREQ, ((PRESCALER) + 1) * 1000)) 103 | 104 | /**@brief Timer id type. */ 105 | typedef uint32_t app_timer_id_t; 106 | 107 | /**@brief Application timeout handler type. */ 108 | typedef void (*app_timer_timeout_handler_t)(void * p_context); 109 | 110 | /**@brief Type of function for passing events from the timer module to the scheduler. */ 111 | typedef uint32_t (*app_timer_evt_schedule_func_t) (app_timer_timeout_handler_t timeout_handler, 112 | void * p_context); 113 | 114 | /**@brief Timer modes. */ 115 | typedef enum 116 | { 117 | APP_TIMER_MODE_SINGLE_SHOT, /**< The timer will expire only once. */ 118 | APP_TIMER_MODE_REPEATED /**< The timer will restart each time it expires. */ 119 | } app_timer_mode_t; 120 | 121 | /**@brief Macro for initializing the application timer module. 122 | * 123 | * @details It will handle dimensioning and allocation of the memory buffer required by the timer, 124 | * making sure that the buffer is correctly aligned. It will also connect the timer module 125 | * to the scheduler (if specified). 126 | * 127 | * @note This module assumes that the LFCLK is already running. If it isn't, the module will 128 | * be non-functional, since the RTC will not run. If you don't use a softdevice, you'll 129 | * have to start the LFCLK manually. See the rtc_example's lfclk_config() function 130 | * for an example of how to do this. If you use a softdevice, the LFCLK is started on 131 | * softdevice init. 132 | * 133 | * 134 | * @param[in] PRESCALER Value of the RTC1 PRESCALER register. This will decide the 135 | * timer tick rate. Set to 0 for no prescaling. 136 | * @param[in] MAX_TIMERS Maximum number of timers that can be created at any given time. 137 | * @param[in] OP_QUEUES_SIZE Size of queues holding timer operations that are pending execution. 138 | * @param[in] SCHEDULER_FUNC Pointer to scheduler event handler 139 | * 140 | * @note Since this macro allocates a buffer, it must only be called once (it is OK to call it 141 | * several times as long as it is from the same location, e.g. to do a reinitialization). 142 | */ 143 | /*lint -emacro(506, APP_TIMER_INIT) */ /* Suppress "Constant value Boolean */ 144 | #define APP_TIMER_INIT(PRESCALER, MAX_TIMERS, OP_QUEUES_SIZE, SCHEDULER_FUNC) \ 145 | do \ 146 | { \ 147 | static uint32_t APP_TIMER_BUF[CEIL_DIV(APP_TIMER_BUF_SIZE((MAX_TIMERS), \ 148 | (OP_QUEUES_SIZE) + 1), \ 149 | sizeof(uint32_t))]; \ 150 | uint32_t ERR_CODE = app_timer_init((PRESCALER), \ 151 | (MAX_TIMERS), \ 152 | (OP_QUEUES_SIZE) + 1, \ 153 | APP_TIMER_BUF, \ 154 | SCHEDULER_FUNC); \ 155 | APP_ERROR_CHECK(ERR_CODE); \ 156 | } while (0) 157 | 158 | /**@brief Function for initializing the timer module. 159 | * 160 | * @note Normally initialization should be done using the APP_TIMER_INIT() macro, as that will both 161 | * allocate the buffers needed by the timer module (including aligning the buffers correctly, 162 | * and also take care of connecting the timer module to the scheduler (if specified). 163 | * 164 | * @param[in] prescaler Value of the RTC1 PRESCALER register. Set to 0 for no prescaling. 165 | * @param[in] max_timers Maximum number of timers that can be created at any given time. 166 | * @param[in] op_queues_size Size of queues holding timer operations that are pending 167 | * execution. NOTE: Due to the queue implementation, this size must 168 | * be one more than the size that is actually needed. 169 | * @param[in] p_buffer Pointer to memory buffer for internal use in the app_timer 170 | * module. The size of the buffer can be computed using the 171 | * APP_TIMER_BUF_SIZE() macro. The buffer must be aligned to a 172 | * 4 byte boundary. 173 | * @param[in] evt_schedule_func Function for passing timeout events to the scheduler. Point to 174 | * app_timer_evt_schedule() to connect to the scheduler. Set to NULL 175 | * to make the timer module call the timeout handler directly from 176 | * the timer interrupt handler. 177 | * 178 | * @retval NRF_SUCCESS Successful initialization. 179 | * @retval NRF_ERROR_INVALID_PARAM Invalid parameter (buffer not aligned to a 4 byte 180 | * boundary or NULL). 181 | */ 182 | uint32_t app_timer_init(uint32_t prescaler, 183 | uint8_t max_timers, 184 | uint8_t op_queues_size, 185 | void * p_buffer, 186 | app_timer_evt_schedule_func_t evt_schedule_func); 187 | 188 | /**@brief Function for creating a timer instance. 189 | * 190 | * @param[out] p_timer_id Id of the newly created timer. 191 | * @param[in] mode Timer mode. 192 | * @param[in] timeout_handler Function to be executed when the timer expires. 193 | * 194 | * @retval NRF_SUCCESS Timer was successfully created. 195 | * @retval NRF_ERROR_INVALID_PARAM Invalid parameter. 196 | * @retval NRF_ERROR_INVALID_STATE Application timer module has not been initialized. 197 | * @retval NRF_ERROR_NO_MEM Maximum number of timers has already been reached. 198 | * 199 | * @note This function does the timer allocation in the caller's context. It is also not protected 200 | * by a critical region. Therefore care must be taken not to call it from several interrupt 201 | * levels simultaneously. 202 | */ 203 | uint32_t app_timer_create(app_timer_id_t * p_timer_id, 204 | app_timer_mode_t mode, 205 | app_timer_timeout_handler_t timeout_handler); 206 | 207 | /**@brief Function for starting a timer. 208 | * 209 | * @param[in] timer_id Id of timer to start. 210 | * @param[in] timeout_ticks Number of ticks (of RTC1, including prescaling) to timeout event 211 | * (minimum 5 ticks). 212 | * @param[in] p_context General purpose pointer. Will be passed to the timeout handler when 213 | * the timer expires. 214 | * 215 | * @retval NRF_SUCCESS Timer was successfully started. 216 | * @retval NRF_ERROR_INVALID_PARAM Invalid parameter. 217 | * @retval NRF_ERROR_INVALID_STATE Application timer module has not been initialized, or timer 218 | * has not been created. 219 | * @retval NRF_ERROR_NO_MEM Timer operations queue was full. 220 | * 221 | * @note The minimum timeout_ticks value is 5. 222 | * @note For multiple active timers, timeouts occurring in close proximity to each other (in the 223 | * range of 1 to 3 ticks) will have a positive jitter of maximum 3 ticks. 224 | * @note When calling this method on a timer which is already running, the second start operation 225 | * will be ignored. 226 | */ 227 | uint32_t app_timer_start(app_timer_id_t timer_id, uint32_t timeout_ticks, void * p_context); 228 | 229 | /**@brief Function for stopping the specified timer. 230 | * 231 | * @param[in] timer_id Id of timer to stop. 232 | * 233 | * @retval NRF_SUCCESS Timer was successfully stopped. 234 | * @retval NRF_ERROR_INVALID_PARAM Invalid parameter. 235 | * @retval NRF_ERROR_INVALID_STATE Application timer module has not been initialized, or timer 236 | * has not been created. 237 | * @retval NRF_ERROR_NO_MEM Timer operations queue was full. 238 | */ 239 | uint32_t app_timer_stop(app_timer_id_t timer_id); 240 | 241 | /**@brief Function for stopping all running timers. 242 | * 243 | * @retval NRF_SUCCESS All timers were successfully stopped. 244 | * @retval NRF_ERROR_INVALID_STATE Application timer module has not been initialized. 245 | * @retval NRF_ERROR_NO_MEM Timer operations queue was full. 246 | */ 247 | uint32_t app_timer_stop_all(void); 248 | 249 | /**@brief Function for returning the current value of the RTC1 counter. 250 | * 251 | * @param[out] p_ticks Current value of the RTC1 counter. 252 | * 253 | * @retval NRF_SUCCESS Counter was successfully read. 254 | */ 255 | uint32_t app_timer_cnt_get(uint32_t * p_ticks); 256 | 257 | /**@brief Function for computing the difference between two RTC1 counter values. 258 | * 259 | * @param[in] ticks_to Value returned by app_timer_cnt_get(). 260 | * @param[in] ticks_from Value returned by app_timer_cnt_get(). 261 | * @param[out] p_ticks_diff Number of ticks from ticks_from to ticks_to. 262 | * 263 | * @retval NRF_SUCCESS Counter difference was successfully computed. 264 | */ 265 | uint32_t app_timer_cnt_diff_compute(uint32_t ticks_to, 266 | uint32_t ticks_from, 267 | uint32_t * p_ticks_diff); 268 | 269 | #ifdef __cplusplus 270 | } 271 | #endif 272 | 273 | #endif // APP_TIMER_H__ 274 | 275 | /** @} */ 276 | -------------------------------------------------------------------------------- /app_timer_appsh.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2014 Nordic Semiconductor. All Rights Reserved. 2 | * 3 | * The information contained herein is property of Nordic Semiconductor ASA. 4 | * Terms and conditions of usage are described in detail in NORDIC 5 | * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. 6 | * 7 | * Licensees are granted free, non-transferable use of the information. NO 8 | * WARRANTY of ANY KIND is provided. This heading must NOT be removed from 9 | * the file. 10 | * 11 | */ 12 | 13 | #include "app_timer_appsh.h" 14 | #include "app_scheduler.h" 15 | 16 | static void app_timer_evt_get(void * p_event_data, uint16_t event_size) 17 | { 18 | app_timer_event_t * p_timer_event = (app_timer_event_t *)p_event_data; 19 | 20 | APP_ERROR_CHECK_BOOL(event_size == sizeof(app_timer_event_t)); 21 | p_timer_event->timeout_handler(p_timer_event->p_context); 22 | } 23 | 24 | uint32_t app_timer_evt_schedule(app_timer_timeout_handler_t timeout_handler, 25 | void * p_context) 26 | { 27 | app_timer_event_t timer_event; 28 | 29 | timer_event.timeout_handler = timeout_handler; 30 | timer_event.p_context = p_context; 31 | 32 | return app_sched_event_put(&timer_event, sizeof(timer_event), app_timer_evt_get); 33 | } 34 | 35 | -------------------------------------------------------------------------------- /app_timer_appsh.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2014 Nordic Semiconductor. All Rights Reserved. 2 | * 3 | * The information contained herein is property of Nordic Semiconductor ASA. 4 | * Terms and conditions of usage are described in detail in NORDIC 5 | * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. 6 | * 7 | * Licensees are granted free, non-transferable use of the information. NO 8 | * WARRANTY of ANY KIND is provided. This heading must NOT be removed from 9 | * the file. 10 | * 11 | */ 12 | 13 | #ifndef APP_TIMER_APPSH_H 14 | #define APP_TIMER_APPSH_H 15 | 16 | #include "app_timer.h" 17 | 18 | #define APP_TIMER_SCHED_EVT_SIZE sizeof(app_timer_event_t) /**< Size of button events being passed through the scheduler (is to be used for computing the maximum size of scheduler events). */ 19 | 20 | /**@brief Macro for initializing the application timer module to use with app_scheduler. 21 | * 22 | * @param[in] PRESCALER Value of the RTC1 PRESCALER register. This will decide the 23 | * timer tick rate. Set to 0 for no prescaling. 24 | * @param[in] MAX_TIMERS Maximum number of timers that can be created at any given time. 25 | * @param[in] OP_QUEUES_SIZE Size of queues holding timer operations that are pending execution. 26 | * @param[in] USE_SCHEDULER TRUE if the application is using the app_scheduler, 27 | * FALSE otherwise. 28 | * 29 | * @note Since this macro allocates a buffer, it must only be called once (it is OK to call it 30 | * several times as long as it is from the same location, e.g. to do a reinitialization). 31 | */ 32 | #define APP_TIMER_APPSH_INIT(PRESCALER, MAX_TIMERS, OP_QUEUES_SIZE, USE_SCHEDULER) \ 33 | APP_TIMER_INIT(PRESCALER, MAX_TIMERS, OP_QUEUES_SIZE, \ 34 | (USE_SCHEDULER) ? app_timer_evt_schedule : NULL) 35 | 36 | typedef struct 37 | { 38 | app_timer_timeout_handler_t timeout_handler; 39 | void * p_context; 40 | } app_timer_event_t; 41 | 42 | uint32_t app_timer_evt_schedule(app_timer_timeout_handler_t timeout_handler, 43 | void * p_context); 44 | #endif // APP_TIMER_APPSH_H 45 | 46 | -------------------------------------------------------------------------------- /bootloader.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013 Nordic Semiconductor. All Rights Reserved. 2 | * 3 | * The information contained herein is property of Nordic Semiconductor ASA. 4 | * Terms and conditions of usage are described in detail in NORDIC 5 | * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. 6 | * 7 | * Licensees are granted free, non-transferable use of the information. NO 8 | * WARRANTY of ANY KIND is provided. This heading must NOT be removed from 9 | * the file. 10 | * 11 | */ 12 | 13 | #include "bootloader.h" 14 | #include 15 | #include "bootloader_types.h" 16 | #include "bootloader_util.h" 17 | #include "bootloader_settings.h" 18 | #include "dfu.h" 19 | #include "dfu_transport.h" 20 | #include "nrf51.h" 21 | #include "app_error.h" 22 | #include "nrf_sdm.h" 23 | #include "nordic_common.h" 24 | #include "crc16.h" 25 | #include "pstorage.h" 26 | #include "app_scheduler.h" 27 | #include "nrf_delay.h" 28 | 29 | #define IRQ_ENABLED 0x01 /**< Field identifying if an interrupt is enabled. */ 30 | #define MAX_NUMBER_INTERRUPTS 32 /**< Maximum number of interrupts available. */ 31 | 32 | /**@brief Enumeration for specifying current bootloader status. 33 | */ 34 | typedef enum 35 | { 36 | BOOTLOADER_UPDATING, /**< Bootloader status for indicating that an update is in progress. */ 37 | BOOTLOADER_SETTINGS_SAVING, /**< Bootloader status for indicating that saving of bootloader settings is in progress. */ 38 | BOOTLOADER_COMPLETE, /**< Bootloader status for indicating that all operations for the update procedure has completed and it is safe to reset the system. */ 39 | BOOTLOADER_TIMEOUT, /**< Bootloader status field for indicating that a timeout has occured and current update process should be aborted. */ 40 | BOOTLOADER_RESET, /**< Bootloader status field for indicating that a reset has been requested and current update process should be aborted. */ 41 | } bootloader_status_t; 42 | 43 | static pstorage_handle_t m_bootsettings_handle; /**< Pstorage handle to use for registration and identifying the bootloader module on subsequent calls to the pstorage module for load and store of bootloader setting in flash. */ 44 | static bootloader_status_t m_update_status; /**< Current update status for the bootloader module to ensure correct behaviour when updating settings and when update completes. */ 45 | 46 | /**@brief Function for handling callbacks from pstorage module. 47 | * 48 | * @details Handles pstorage results for clear and storage operation. For detailed description of 49 | * the parameters provided with the callback, please refer to \ref pstorage_ntf_cb_t. 50 | */ 51 | static void pstorage_callback_handler(pstorage_handle_t * p_handle, 52 | uint8_t op_code, 53 | uint32_t result, 54 | uint8_t * p_data, 55 | uint32_t data_len) 56 | { 57 | // If we are in BOOTLOADER_SETTINGS_SAVING state and we receive an PSTORAGE_STORE_OP_CODE 58 | // response then settings has been saved and update has completed. 59 | if ((m_update_status == BOOTLOADER_SETTINGS_SAVING) && (op_code == PSTORAGE_STORE_OP_CODE)) 60 | { 61 | m_update_status = BOOTLOADER_COMPLETE; 62 | } 63 | 64 | APP_ERROR_CHECK(result); 65 | } 66 | 67 | 68 | /**@brief Function for waiting for events. 69 | * 70 | * @details This function will place the chip in low power mode while waiting for events from 71 | * the SoftDevice or other peripherals. When interrupted by an event, it will call the 72 | * @ref app_sched_execute function to process the received event. This function will return 73 | * when the final state of the firmware update is reached OR when a tear down is in 74 | * progress. 75 | */ 76 | static void wait_for_events(void) 77 | { 78 | for (;;) 79 | { 80 | // Wait in low power state for any events. 81 | uint32_t err_code = sd_app_evt_wait(); 82 | APP_ERROR_CHECK(err_code); 83 | 84 | // Event received. Process it from the scheduler. 85 | app_sched_execute(); 86 | 87 | if ((m_update_status == BOOTLOADER_COMPLETE) || 88 | (m_update_status == BOOTLOADER_TIMEOUT) || 89 | (m_update_status == BOOTLOADER_RESET)) 90 | { 91 | // When update has completed or a timeout/reset occured we will return. 92 | return; 93 | } 94 | } 95 | } 96 | 97 | 98 | bool bootloader_app_is_valid(uint32_t app_addr) 99 | { 100 | const bootloader_settings_t * p_bootloader_settings; 101 | 102 | // There exists an application in CODE region 1. 103 | if (*((uint32_t *)app_addr) == EMPTY_FLASH_MASK) 104 | { 105 | return false; 106 | } 107 | 108 | bool success = false; 109 | 110 | bootloader_util_settings_get(&p_bootloader_settings); 111 | 112 | // The application in CODE region 1 is flagged as valid during update. 113 | if (p_bootloader_settings->bank_0 == BANK_VALID_APP) 114 | { 115 | uint16_t image_crc = 0; 116 | 117 | // A stored crc value of 0 indicates that CRC checking is not used. 118 | if (p_bootloader_settings->bank_0_crc != 0) 119 | { 120 | image_crc = crc16_compute((uint8_t *)DFU_BANK_0_REGION_START, 121 | p_bootloader_settings->bank_0_size, 122 | NULL); 123 | } 124 | 125 | success = (image_crc == p_bootloader_settings->bank_0_crc); 126 | } 127 | 128 | return success; 129 | } 130 | 131 | 132 | static void bootloader_settings_save(bootloader_settings_t * p_settings) 133 | { 134 | uint32_t err_code = pstorage_clear(&m_bootsettings_handle, sizeof(bootloader_settings_t)); 135 | APP_ERROR_CHECK(err_code); 136 | 137 | err_code = pstorage_store(&m_bootsettings_handle, 138 | (uint8_t *)p_settings, 139 | sizeof(bootloader_settings_t), 140 | 0); 141 | APP_ERROR_CHECK(err_code); 142 | } 143 | 144 | 145 | void bootloader_dfu_update_process(dfu_update_status_t update_status) 146 | { 147 | static bootloader_settings_t settings; 148 | const bootloader_settings_t * p_bootloader_settings; 149 | 150 | bootloader_util_settings_get(&p_bootloader_settings); 151 | 152 | if (update_status.status_code == DFU_UPDATE_APP_COMPLETE) 153 | { 154 | settings.bank_0_crc = update_status.app_crc; 155 | settings.bank_0_size = update_status.app_size; 156 | settings.bank_0 = BANK_VALID_APP; 157 | settings.bank_1 = BANK_INVALID_APP; 158 | 159 | m_update_status = BOOTLOADER_SETTINGS_SAVING; 160 | bootloader_settings_save(&settings); 161 | } 162 | else if (update_status.status_code == DFU_UPDATE_SD_COMPLETE) 163 | { 164 | settings.bank_0_crc = update_status.app_crc; 165 | settings.bank_0_size = update_status.sd_size + 166 | update_status.bl_size + 167 | update_status.app_size; 168 | settings.bank_0 = BANK_VALID_SD; 169 | settings.bank_1 = BANK_INVALID_APP; 170 | settings.sd_image_size = update_status.sd_size; 171 | settings.bl_image_size = update_status.bl_size; 172 | settings.app_image_size = update_status.app_size; 173 | settings.sd_image_start = update_status.sd_image_start; 174 | 175 | m_update_status = BOOTLOADER_SETTINGS_SAVING; 176 | bootloader_settings_save(&settings); 177 | } 178 | else if (update_status.status_code == DFU_UPDATE_BOOT_COMPLETE) 179 | { 180 | settings.bank_0 = p_bootloader_settings->bank_0; 181 | settings.bank_0_crc = p_bootloader_settings->bank_0_crc; 182 | settings.bank_0_size = p_bootloader_settings->bank_0_size; 183 | settings.bank_1 = BANK_VALID_BOOT; 184 | settings.sd_image_size = update_status.sd_size; 185 | settings.bl_image_size = update_status.bl_size; 186 | settings.app_image_size = update_status.app_size; 187 | 188 | m_update_status = BOOTLOADER_SETTINGS_SAVING; 189 | bootloader_settings_save(&settings); 190 | } 191 | else if (update_status.status_code == DFU_UPDATE_SD_SWAPPED) 192 | { 193 | if (p_bootloader_settings->bank_0 == BANK_VALID_SD) 194 | { 195 | settings.bank_0_crc = 0; 196 | settings.bank_0_size = 0; 197 | settings.bank_0 = BANK_INVALID_APP; 198 | } 199 | // This handles cases where SoftDevice was not updated, hence bank0 keeps its settings. 200 | else 201 | { 202 | settings.bank_0 = p_bootloader_settings->bank_0; 203 | settings.bank_0_crc = p_bootloader_settings->bank_0_crc; 204 | settings.bank_0_size = p_bootloader_settings->bank_0_size; 205 | } 206 | 207 | settings.bank_1 = BANK_INVALID_APP; 208 | settings.sd_image_size = 0; 209 | settings.bl_image_size = 0; 210 | settings.app_image_size = 0; 211 | 212 | m_update_status = BOOTLOADER_SETTINGS_SAVING; 213 | bootloader_settings_save(&settings); 214 | } 215 | else if (update_status.status_code == DFU_TIMEOUT) 216 | { 217 | // Timeout has occurred. Close the connection with the DFU Controller. 218 | uint32_t err_code = dfu_transport_close(); 219 | APP_ERROR_CHECK(err_code); 220 | 221 | m_update_status = BOOTLOADER_TIMEOUT; 222 | } 223 | else if (update_status.status_code == DFU_BANK_0_ERASED) 224 | { 225 | settings.bank_0_crc = 0; 226 | settings.bank_0_size = 0; 227 | settings.bank_0 = BANK_INVALID_APP; 228 | settings.bank_1 = p_bootloader_settings->bank_1; 229 | 230 | bootloader_settings_save(&settings); 231 | } 232 | else if (update_status.status_code == DFU_RESET) 233 | { 234 | m_update_status = BOOTLOADER_RESET; 235 | } 236 | else 237 | { 238 | // No implementation needed. 239 | } 240 | } 241 | 242 | 243 | uint32_t bootloader_init(void) 244 | { 245 | uint32_t err_code; 246 | pstorage_module_param_t storage_params; 247 | 248 | storage_params.cb = pstorage_callback_handler; 249 | storage_params.block_size = sizeof(bootloader_settings_t); 250 | storage_params.block_count = 1; 251 | 252 | err_code = pstorage_init(); 253 | if (err_code != NRF_SUCCESS) 254 | { 255 | return err_code; 256 | } 257 | 258 | err_code = pstorage_register(&storage_params, &m_bootsettings_handle); 259 | 260 | return err_code; 261 | } 262 | 263 | 264 | uint32_t bootloader_dfu_start(void) 265 | { 266 | uint32_t err_code; 267 | 268 | // Clear swap if banked update is used. 269 | err_code = dfu_init(); 270 | if (err_code != NRF_SUCCESS) 271 | { 272 | return err_code; 273 | } 274 | 275 | err_code = dfu_transport_update_start(); 276 | 277 | wait_for_events(); 278 | 279 | return err_code; 280 | } 281 | 282 | 283 | /**@brief Function for disabling all interrupts before jumping from bootloader to application. 284 | */ 285 | static void interrupts_disable(void) 286 | { 287 | uint32_t interrupt_setting_mask; 288 | uint32_t irq = 0; // We start from first interrupt, i.e. interrupt 0. 289 | 290 | // Fetch the current interrupt settings. 291 | interrupt_setting_mask = NVIC->ISER[0]; 292 | 293 | for (; irq < MAX_NUMBER_INTERRUPTS; irq++) 294 | { 295 | if (interrupt_setting_mask & (IRQ_ENABLED << irq)) 296 | { 297 | // The interrupt was enabled, and hence disable it. 298 | NVIC_DisableIRQ((IRQn_Type)irq); 299 | } 300 | } 301 | } 302 | 303 | 304 | void bootloader_app_start(uint32_t app_addr) 305 | { 306 | // If the applications CRC has been checked and passed, the magic number will be written and we 307 | // can start the application safely. 308 | uint32_t err_code = sd_softdevice_disable(); 309 | APP_ERROR_CHECK(err_code); 310 | 311 | interrupts_disable(); 312 | 313 | err_code = sd_softdevice_vector_table_base_set(CODE_REGION_1_START); 314 | APP_ERROR_CHECK(err_code); 315 | 316 | bootloader_util_app_start(CODE_REGION_1_START); 317 | } 318 | 319 | 320 | bool bootloader_dfu_sd_in_progress(void) 321 | { 322 | const bootloader_settings_t * p_bootloader_settings; 323 | 324 | bootloader_util_settings_get(&p_bootloader_settings); 325 | 326 | if (p_bootloader_settings->bank_0 == BANK_VALID_SD || 327 | p_bootloader_settings->bank_1 == BANK_VALID_BOOT) 328 | { 329 | return true; 330 | } 331 | 332 | return false; 333 | } 334 | 335 | 336 | uint32_t bootloader_dfu_sd_update_continue(void) 337 | { 338 | uint32_t err_code; 339 | 340 | if ((dfu_sd_image_validate() == NRF_SUCCESS) && 341 | (dfu_bl_image_validate() == NRF_SUCCESS)) 342 | { 343 | return NRF_SUCCESS; 344 | } 345 | 346 | // Ensure that flash operations are not executed within the first 100 ms seconds to allow 347 | // a debugger to be attached. 348 | nrf_delay_ms(100); 349 | 350 | err_code = dfu_sd_image_swap(); 351 | APP_ERROR_CHECK(err_code); 352 | 353 | err_code = dfu_sd_image_validate(); 354 | APP_ERROR_CHECK(err_code); 355 | 356 | err_code = dfu_bl_image_swap(); 357 | APP_ERROR_CHECK(err_code); 358 | 359 | return err_code; 360 | } 361 | 362 | 363 | uint32_t bootloader_dfu_sd_update_finalize(void) 364 | { 365 | dfu_update_status_t update_status = {DFU_UPDATE_SD_SWAPPED, }; 366 | 367 | bootloader_dfu_update_process(update_status); 368 | 369 | wait_for_events(); 370 | 371 | return NRF_SUCCESS; 372 | } 373 | 374 | 375 | void bootloader_settings_get(bootloader_settings_t * const p_settings) 376 | { 377 | bootloader_settings_t bootloader_settings; 378 | 379 | (void) pstorage_load((uint8_t *)&bootloader_settings, 380 | &m_bootsettings_handle, 381 | sizeof(bootloader_settings_t), 382 | 0); 383 | 384 | p_settings->bank_0 = bootloader_settings.bank_0; 385 | p_settings->bank_0_crc = bootloader_settings.bank_0_crc; 386 | p_settings->bank_0_size = bootloader_settings.bank_0_size; 387 | p_settings->bank_1 = bootloader_settings.bank_1; 388 | p_settings->sd_image_size = bootloader_settings.sd_image_size; 389 | p_settings->bl_image_size = bootloader_settings.bl_image_size; 390 | p_settings->app_image_size = bootloader_settings.app_image_size; 391 | p_settings->sd_image_start = bootloader_settings.sd_image_start; 392 | } 393 | 394 | -------------------------------------------------------------------------------- /bootloader.sct: -------------------------------------------------------------------------------- 1 | LR_IROM1 0x0003C000 0x00004000 { ; load region size_region 2 | ER_IROM1 0x0003C000 0x00004000 { ; load address = execution address 3 | *.o (RESET, +First) 4 | *(InRoot$$Sections) 5 | .ANY (+RO) 6 | } 7 | RW_IRAM1 0x20002800 0x00001780 { ; RW data 8 | .ANY (+RW +ZI) 9 | } 10 | RW_IRAM2 0x20003F80 UNINIT 0x00000080 { 11 | dfu_ble_svc*.o (+ZI) 12 | .ANY (+RW +ZI) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /bootloader_settings_arm.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013 Nordic Semiconductor. All Rights Reserved. 2 | * 3 | * The information contained herein is property of Nordic Semiconductor ASA. 4 | * Terms and conditions of usage are described in detail in NORDIC 5 | * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. 6 | * 7 | * Licensees are granted free, non-transferable use of the information. NO 8 | * WARRANTY of ANY KIND is provided. This heading must NOT be removed from 9 | * the file. 10 | * 11 | */ 12 | 13 | #include "bootloader_settings.h" 14 | #include 15 | #include "dfu_types.h" 16 | 17 | uint8_t m_boot_settings[CODE_PAGE_SIZE] __attribute__((at(BOOTLOADER_SETTINGS_ADDRESS))) __attribute__((used)); /**< This variable reserves a codepage for bootloader specific settings, to ensure the compiler doesn't locate any code or variables at his location. */ 18 | uint32_t m_uicr_bootloader_start_address __attribute__((at(NRF_UICR_BOOT_START_ADDRESS))) = BOOTLOADER_REGION_START; /**< This variable ensures that the linker script will write the bootloader start address to the UICR register. This value will be written in the HEX file and thus written to UICR when the bootloader is flashed into the chip. */ 19 | 20 | 21 | void bootloader_util_settings_get(const bootloader_settings_t ** pp_bootloader_settings) 22 | { 23 | // Read only pointer to bootloader settings in flash. 24 | static bootloader_settings_t const * const p_bootloader_settings = 25 | (bootloader_settings_t *)&m_boot_settings[0]; 26 | 27 | *pp_bootloader_settings = p_bootloader_settings; 28 | } 29 | -------------------------------------------------------------------------------- /dfu_ble_svc.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2014 Nordic Semiconductor. All Rights Reserved. 2 | * 3 | * The information contained herein is property of Nordic Semiconductor ASA. 4 | * Terms and conditions of usage are described in detail in NORDIC 5 | * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. 6 | * 7 | * Licensees are granted free, non-transferable use of the information. NO 8 | * WARRANTY of ANY KIND is provided. This heading must NOT be removed from 9 | * the file. 10 | * 11 | */ 12 | 13 | #include "dfu_ble_svc.h" 14 | #include 15 | #include "nrf_error.h" 16 | #include "crc16.h" 17 | 18 | static dfu_ble_peer_data_t m_peer_data __attribute__((section("NoInit"), zero_init)); /**< This variable should be placed in a non initialized RAM section in order to be valid upon soft reset from application into bootloader. */ 19 | static uint16_t m_peer_data_crc __attribute__((section("NoInit"), zero_init)); /**< CRC variable to ensure the integrity of the peer data provided. */ 20 | 21 | 22 | /**@brief Function for setting the peer data from application in bootloader before reset. 23 | * 24 | * @param[in] p_peer_data Pointer to the peer data containing keys for the connection. 25 | * 26 | * @retval NRF_SUCCES The data was set succesfully. 27 | * @retval NRF_ERROR_NULL If a null pointer was passed as argument. 28 | */ 29 | static uint32_t dfu_ble_set_peer_data(dfu_ble_peer_data_t * p_peer_data) 30 | { 31 | if (p_peer_data == NULL) 32 | { 33 | return NRF_ERROR_NULL; 34 | } 35 | 36 | uint32_t src = (uint32_t)p_peer_data; 37 | uint32_t dst = (uint32_t)&m_peer_data; 38 | uint32_t len = dst - src; 39 | 40 | if (src == dst) 41 | { 42 | // Do nothing as source and destination are identical, just calculate crc below. 43 | } 44 | else if (len < sizeof(dfu_ble_peer_data_t)) 45 | { 46 | uint32_t i = 0; 47 | 48 | dst += sizeof(dfu_ble_peer_data_t); 49 | src += sizeof(dfu_ble_peer_data_t); 50 | 51 | // Copy byte wise backwards when facing overlapping structures. 52 | while (i++ <= sizeof(dfu_ble_peer_data_t)) 53 | { 54 | *((uint8_t *)dst--) = *((uint8_t *)src--); 55 | } 56 | } 57 | else 58 | { 59 | memcpy((void *)dst, (void *)src, sizeof(dfu_ble_peer_data_t)); 60 | } 61 | 62 | m_peer_data_crc = crc16_compute((uint8_t *)&m_peer_data, sizeof(m_peer_data), NULL); 63 | 64 | return NRF_SUCCESS; 65 | } 66 | 67 | 68 | /**@brief Function for handling second stage of SuperVisor Calls (SVC). 69 | * 70 | * @details The function will use svc_num to call the corresponding SVC function. 71 | * 72 | * @param[in] svc_num SVC number for function to be executed 73 | * @param[in] p_svc_args Argument list for the SVC. 74 | * 75 | * @return This function returns the error value of the SVC return. For further details, please 76 | * refer to the details of the SVC implementation itself. 77 | * @ref NRF_ERROR_SVC_HANDLER_MISSING is returned if no SVC handler is implemented for the 78 | * provided svc_num. 79 | */ 80 | void C_SVC_Handler(uint8_t svc_num, uint32_t * p_svc_args) 81 | { 82 | switch (svc_num) 83 | { 84 | case DFU_BLE_SVC_SET_PEER_DATA: 85 | p_svc_args[0] = dfu_ble_set_peer_data((dfu_ble_peer_data_t *)p_svc_args[0]); 86 | break; 87 | 88 | default: 89 | p_svc_args[0] = NRF_ERROR_SVC_HANDLER_MISSING; 90 | break; 91 | } 92 | 93 | return; 94 | } 95 | 96 | 97 | /**@brief Function for handling the first stage of SuperVisor Calls (SVC) in assembly. 98 | * 99 | * @details The function will use the link register (LR) to determine the stack (PSP or MSP) to be 100 | * used and then decode the SVC number afterwards. After decoding the SVC number then 101 | * @ref C_SVC_Handler is called for further processing of the SVC. 102 | */ 103 | __asm void SVC_Handler(void) 104 | { 105 | EXC_RETURN_CMD_PSP EQU 0xFFFFFFFD ; EXC_RETURN using PSP for ARM Cortex. If Link register contains this value it indicates the PSP was used before the SVC, otherwise the MSP was used. 106 | 107 | IMPORT C_SVC_Handler 108 | LDR R0, =EXC_RETURN_CMD_PSP ; Load the EXC_RETURN into R0 to be able to compare against LR to determine stack pointer used. 109 | CMP R0, LR ; Compare the link register with R0. If equal then PSP was used, otherwise MSP was used before SVC. 110 | BNE UseMSP ; Branch to code fetching SVC arguments using MSP. 111 | MRS R1, PSP ; Move PSP into R1. 112 | B Call_C_SVC_Handler ; Branch to Call_C_SVC_Handler below. 113 | UseMSP 114 | MRS R1, MSP ; MSP was used, therefore Move MSP into R1. 115 | Call_C_SVC_Handler 116 | LDR R0, [R1, #24] ; The arguments for the SVC was stacked. R1 contains Stack Pointer, the values stacked before SVC are R0, R1, R2, R3, R12, LR, PC (Return address), xPSR. 117 | ; R1 contains current SP so the PC of the stacked frame is at SP + 6 words (24 bytes). We load the PC into R0. 118 | SUBS R0, #2 ; The PC before the SVC is in R0. We subtract 2 to get the address prior to the instruction executed where the SVC number is located. 119 | LDRB R0, [R0] ; SVC instruction low octet: Load the byte at the address before the PC to fetch the SVC number. 120 | LDR R2, =C_SVC_Handler ; Load address of C implementation of SVC handler. 121 | BX R2 ; Branch to C implementation of SVC handler. R0 is now the SVC number, R1 is the StackPointer where the arguments (R0-R3) of the original SVC are located. 122 | ALIGN 123 | } 124 | 125 | 126 | uint32_t dfu_ble_get_peer_data(dfu_ble_peer_data_t * p_peer_data) 127 | { 128 | uint16_t crc = crc16_compute((uint8_t *)&m_peer_data, sizeof(m_peer_data), NULL); 129 | 130 | if (crc != m_peer_data_crc) 131 | { 132 | return NRF_ERROR_INVALID_DATA; 133 | } 134 | 135 | *p_peer_data = m_peer_data; 136 | 137 | // corrupt CRC to invalidate shared information. 138 | m_peer_data_crc++; 139 | 140 | return NRF_SUCCESS; 141 | } 142 | 143 | -------------------------------------------------------------------------------- /dfu_dual_bank.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013 Nordic Semiconductor. All Rights Reserved. 2 | * 3 | * The information contained herein is property of Nordic Semiconductor ASA. 4 | * Terms and conditions of usage are described in detail in NORDIC 5 | * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. 6 | * 7 | * Licensees are granted free, non-transferable use of the information. NO 8 | * WARRANTY of ANY KIND is provided. This heading must NOT be removed from 9 | * the file. 10 | * 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include "dfu.h" 17 | #include "dfu_types.h" 18 | #include "dfu_bank_internal.h" 19 | #include "nrf.h" 20 | #include "nrf51.h" 21 | #include "nrf51_bitfields.h" 22 | #include "app_util.h" 23 | #include "nrf_sdm.h" 24 | #include "app_error.h" 25 | #include "nrf_error.h" 26 | #include "app_timer.h" 27 | #include "app_error.h" 28 | #include "nordic_common.h" 29 | #include "bootloader.h" 30 | #include "bootloader_types.h" 31 | #include "pstorage.h" 32 | #include "nrf_mbr.h" 33 | #include "dfu_init.h" 34 | 35 | static dfu_state_t m_dfu_state; /**< Current DFU state. */ 36 | static uint32_t m_image_size; /**< Size of the image that will be transmitted. */ 37 | 38 | static dfu_start_packet_t m_start_packet; /**< Start packet received for this update procedure. Contains update mode and image sizes information to be used for image transfer. */ 39 | static uint8_t m_init_packet[64]; /**< Init packet, can hold CRC, Hash, Signed Hash and similar, for image validation, integrety check and authorization checking. */ 40 | static uint8_t m_init_packet_length; /**< Length of init packet received. */ 41 | static uint16_t m_image_crc; /**< Calculated CRC of the image received. */ 42 | 43 | static app_timer_id_t m_dfu_timer_id; /**< Application timer id. */ 44 | static bool m_dfu_timed_out = false; /**< Boolean flag value for tracking DFU timer timeout state. */ 45 | 46 | static pstorage_handle_t m_storage_handle_swap; /**< Pstorage handle for the swap area (bank 1). Bank used when updating an application or bootloader without SoftDevice. */ 47 | static pstorage_handle_t m_storage_handle_app; /**< Pstorage handle for the application area (bank 0). Bank used when updating a SoftDevice w/wo bootloader. Handle also used when swapping received application from bank 1 to bank 0. */ 48 | static pstorage_handle_t * mp_storage_handle_active; /**< Pointer to the pstorage handle for the active bank for receiving of data packets. */ 49 | 50 | static dfu_callback_t m_data_pkt_cb; /**< Callback from DFU Bank module for notification of asynchronous operation such as flash prepare. */ 51 | static dfu_bank_func_t m_functions; /**< Structure holding operations for the selected update process. */ 52 | 53 | 54 | /**@brief Function for handling callbacks from pstorage module. 55 | * 56 | * @details Handles pstorage results for clear and storage operation. For detailed description of 57 | * the parameters provided with the callback, please refer to \ref pstorage_ntf_cb_t. 58 | */ 59 | static void pstorage_callback_handler(pstorage_handle_t * p_handle, 60 | uint8_t op_code, 61 | uint32_t result, 62 | uint8_t * p_data, 63 | uint32_t data_len) 64 | { 65 | switch (op_code) 66 | { 67 | case PSTORAGE_STORE_OP_CODE: 68 | if ((m_dfu_state == DFU_STATE_RX_DATA_PKT) && (m_data_pkt_cb != NULL)) 69 | { 70 | m_data_pkt_cb(DATA_PACKET, result, p_data); 71 | } 72 | break; 73 | 74 | case PSTORAGE_CLEAR_OP_CODE: 75 | if (m_dfu_state == DFU_STATE_PREPARING) 76 | { 77 | m_functions.cleared(); 78 | m_dfu_state = DFU_STATE_RDY; 79 | if (m_data_pkt_cb != NULL) 80 | { 81 | m_data_pkt_cb(START_PACKET, result, p_data); 82 | } 83 | } 84 | break; 85 | 86 | default: 87 | break; 88 | } 89 | APP_ERROR_CHECK(result); 90 | } 91 | 92 | 93 | /**@brief Function for handling the DFU timeout. 94 | * 95 | * @param[in] p_context The timeout context. 96 | */ 97 | static void dfu_timeout_handler(void * p_context) 98 | { 99 | UNUSED_PARAMETER(p_context); 100 | dfu_update_status_t update_status; 101 | 102 | m_dfu_timed_out = true; 103 | update_status.status_code = DFU_TIMEOUT; 104 | 105 | bootloader_dfu_update_process(update_status); 106 | } 107 | 108 | 109 | /**@brief Function for restarting the DFU Timer. 110 | * 111 | * @details This function will stop and restart the DFU timer. This function will be called by the 112 | * functions handling any DFU packet received from the peer that is transferring a firmware 113 | * image. 114 | */ 115 | static uint32_t dfu_timer_restart(void) 116 | { 117 | if (m_dfu_timed_out) 118 | { 119 | // The DFU timer had already timed out. 120 | return NRF_ERROR_INVALID_STATE; 121 | } 122 | 123 | uint32_t err_code = app_timer_stop(m_dfu_timer_id); 124 | APP_ERROR_CHECK(err_code); 125 | 126 | err_code = app_timer_start(m_dfu_timer_id, DFU_TIMEOUT_INTERVAL, NULL); 127 | APP_ERROR_CHECK(err_code); 128 | 129 | return err_code; 130 | } 131 | 132 | 133 | /**@brief Function for preparing of flash before receiving SoftDevice image. 134 | * 135 | * @details This function will erase current application area to ensure sufficient amount of 136 | * storage for the SoftDevice image. Upon erase complete a callback will be done. 137 | * See \ref dfu_bank_prepare_t for further details. 138 | */ 139 | static void dfu_prepare_func_app_erase(uint32_t image_size) 140 | { 141 | uint32_t err_code; 142 | 143 | mp_storage_handle_active = &m_storage_handle_app; 144 | 145 | // Doing a SoftDevice update thus current application must be cleared to ensure enough space 146 | // for new SoftDevice. 147 | m_dfu_state = DFU_STATE_PREPARING; 148 | err_code = pstorage_raw_clear(&m_storage_handle_app, m_image_size); 149 | APP_ERROR_CHECK(err_code); 150 | } 151 | 152 | 153 | /**@brief Function for preparing swap before receiving application or bootloader image. 154 | * 155 | * @details This function will erase current swap area to ensure flash is ready for storage of the 156 | * Application or Bootloader image. Upon erase complete a callback will be done. 157 | * See \ref dfu_bank_prepare_t for further details. 158 | */ 159 | static void dfu_prepare_func_swap_erase(uint32_t image_size) 160 | { 161 | uint32_t err_code; 162 | 163 | mp_storage_handle_active = &m_storage_handle_swap; 164 | 165 | m_dfu_state = DFU_STATE_PREPARING; 166 | err_code = pstorage_raw_clear(&m_storage_handle_swap, DFU_IMAGE_MAX_SIZE_BANKED); 167 | APP_ERROR_CHECK(err_code); 168 | } 169 | 170 | 171 | /**@brief Function for handling behaviour when clear operation has completed. 172 | */ 173 | static void dfu_cleared_func_swap(void) 174 | { 175 | // Do nothing. 176 | } 177 | 178 | 179 | /**@brief Function for handling behaviour when clear operation has completed. 180 | */ 181 | static void dfu_cleared_func_app(void) 182 | { 183 | dfu_update_status_t update_status = {DFU_BANK_0_ERASED, }; 184 | bootloader_dfu_update_process(update_status); 185 | } 186 | 187 | 188 | /**@brief Function for calculating storage offset for receiving SoftDevice image. 189 | * 190 | * @details When a new SoftDevice is received it will be temporary stored in flash before moved to 191 | * address 0x0. In order to succesfully validate transfer and relocation it is important 192 | * that temporary image and final installed image does not ovwerlap hence an offset must 193 | * be calculated in case new image is larger than currently installed SoftDevice. 194 | */ 195 | uint32_t offset_calculate(uint32_t sd_image_size) 196 | { 197 | uint32_t offset = 0; 198 | 199 | if (m_start_packet.sd_image_size > DFU_BANK_0_REGION_START) 200 | { 201 | uint32_t page_mask = (CODE_PAGE_SIZE - 1); 202 | uint32_t diff = m_start_packet.sd_image_size - DFU_BANK_0_REGION_START; 203 | 204 | offset = diff & ~page_mask; 205 | 206 | // Align offset to next page if image size is not page sized. 207 | if ((diff & page_mask) > 0) 208 | { 209 | offset += CODE_PAGE_SIZE; 210 | } 211 | } 212 | 213 | return offset; 214 | } 215 | 216 | 217 | /**@brief Function for activating received SoftDevice image. 218 | * 219 | * @note This function will not move the SoftDevice image. 220 | * The bootloader settings will be marked as SoftDevice update complete and the swapping of 221 | * current SoftDevice will occur after system reset. 222 | * 223 | * @return NRF_SUCCESS on success. 224 | */ 225 | static uint32_t dfu_activate_sd(void) 226 | { 227 | dfu_update_status_t update_status; 228 | 229 | update_status.status_code = DFU_UPDATE_SD_COMPLETE; 230 | update_status.app_crc = m_image_crc; 231 | update_status.sd_image_start = DFU_BANK_0_REGION_START; 232 | update_status.sd_size = m_start_packet.sd_image_size; 233 | update_status.bl_size = m_start_packet.bl_image_size; 234 | update_status.app_size = m_start_packet.app_image_size; 235 | 236 | bootloader_dfu_update_process(update_status); 237 | 238 | return NRF_SUCCESS; 239 | } 240 | 241 | 242 | /**@brief Function for activating received Application image. 243 | * 244 | * @details This function will move the received application image fram swap (bank 1) to 245 | * application area (bank 0). 246 | * 247 | * @return NRF_SUCCESS on success. Error code otherwise. 248 | */ 249 | static uint32_t dfu_activate_app(void) 250 | { 251 | uint32_t err_code; 252 | 253 | // Erase BANK 0. 254 | err_code = pstorage_raw_clear(&m_storage_handle_app, m_start_packet.app_image_size); 255 | APP_ERROR_CHECK(err_code); 256 | 257 | err_code = pstorage_raw_store(&m_storage_handle_app, 258 | (uint8_t *)m_storage_handle_swap.block_id, 259 | m_start_packet.app_image_size, 260 | 0); 261 | 262 | if (err_code == NRF_SUCCESS) 263 | { 264 | dfu_update_status_t update_status; 265 | 266 | memset(&update_status, 0, sizeof(dfu_update_status_t )); 267 | update_status.status_code = DFU_UPDATE_APP_COMPLETE; 268 | update_status.app_crc = m_image_crc; 269 | update_status.app_size = m_start_packet.app_image_size; 270 | 271 | bootloader_dfu_update_process(update_status); 272 | } 273 | 274 | return err_code; 275 | } 276 | 277 | 278 | /**@brief Function for activating received Bootloader image. 279 | * 280 | * @note This function will not move the bootloader image. 281 | * The bootloader settings will be marked as Bootloader update complete and the swapping of 282 | * current bootloader will occur after system reset. 283 | * 284 | * @return NRF_SUCCESS on success. 285 | */ 286 | static uint32_t dfu_activate_bl(void) 287 | { 288 | dfu_update_status_t update_status; 289 | 290 | update_status.status_code = DFU_UPDATE_BOOT_COMPLETE; 291 | update_status.app_crc = m_image_crc; 292 | update_status.sd_size = m_start_packet.sd_image_size; 293 | update_status.bl_size = m_start_packet.bl_image_size; 294 | update_status.app_size = m_start_packet.app_image_size; 295 | 296 | bootloader_dfu_update_process(update_status); 297 | 298 | return NRF_SUCCESS; 299 | } 300 | 301 | 302 | uint32_t dfu_init(void) 303 | { 304 | uint32_t err_code; 305 | pstorage_module_param_t storage_module_param = {.cb = pstorage_callback_handler}; 306 | 307 | m_init_packet_length = 0; 308 | m_image_crc = 0; 309 | 310 | err_code = pstorage_raw_register(&storage_module_param, &m_storage_handle_app); 311 | if (err_code != NRF_SUCCESS) 312 | { 313 | m_dfu_state = DFU_STATE_INIT_ERROR; 314 | return err_code; 315 | } 316 | 317 | m_storage_handle_app.block_id = DFU_BANK_0_REGION_START; 318 | m_storage_handle_swap = m_storage_handle_app; 319 | m_storage_handle_swap.block_id = DFU_BANK_1_REGION_START; 320 | 321 | // Create the timer to monitor the activity by the peer doing the firmware update. 322 | err_code = app_timer_create(&m_dfu_timer_id, 323 | APP_TIMER_MODE_SINGLE_SHOT, 324 | dfu_timeout_handler); 325 | APP_ERROR_CHECK(err_code); 326 | 327 | // Start the DFU timer. 328 | err_code = app_timer_start(m_dfu_timer_id, DFU_TIMEOUT_INTERVAL, NULL); 329 | APP_ERROR_CHECK(err_code); 330 | 331 | m_data_received = 0; 332 | m_dfu_state = DFU_STATE_IDLE; 333 | 334 | return NRF_SUCCESS; 335 | } 336 | 337 | 338 | void dfu_register_callback(dfu_callback_t callback_handler) 339 | { 340 | m_data_pkt_cb = callback_handler; 341 | } 342 | 343 | 344 | uint32_t dfu_start_pkt_handle(dfu_update_packet_t * p_packet) 345 | { 346 | uint32_t err_code; 347 | 348 | m_start_packet = *(p_packet->params.start_packet); 349 | 350 | // Check that the requested update procedure is supported. 351 | // Currently the following combinations are allowed: 352 | // - Application 353 | // - SoftDevice 354 | // - Bootloader 355 | // - SoftDevice with Bootloader 356 | if (IS_UPDATING_APP(m_start_packet) && 357 | (IS_UPDATING_SD(m_start_packet) || IS_UPDATING_BL(m_start_packet))) 358 | { 359 | // App update is only supported independently. 360 | return NRF_ERROR_NOT_SUPPORTED; 361 | } 362 | 363 | if (!(IS_WORD_SIZED(m_start_packet.sd_image_size) && 364 | IS_WORD_SIZED(m_start_packet.bl_image_size) && 365 | IS_WORD_SIZED(m_start_packet.app_image_size))) 366 | { 367 | // Image_sizes are not a multiple of 4 (word size). 368 | return NRF_ERROR_NOT_SUPPORTED; 369 | } 370 | 371 | m_image_size = m_start_packet.sd_image_size + m_start_packet.bl_image_size + 372 | m_start_packet.app_image_size; 373 | 374 | if (m_start_packet.bl_image_size > DFU_BL_IMAGE_MAX_SIZE) 375 | { 376 | return NRF_ERROR_DATA_SIZE; 377 | } 378 | 379 | if (IS_UPDATING_SD(m_start_packet)) 380 | { 381 | if (m_image_size > (DFU_IMAGE_MAX_SIZE_FULL)) 382 | { 383 | return NRF_ERROR_DATA_SIZE; 384 | } 385 | m_functions.prepare = dfu_prepare_func_app_erase; 386 | m_functions.cleared = dfu_cleared_func_app; 387 | m_functions.activate = dfu_activate_sd; 388 | } 389 | else 390 | { 391 | if (m_image_size > DFU_IMAGE_MAX_SIZE_BANKED) 392 | { 393 | return NRF_ERROR_DATA_SIZE; 394 | } 395 | 396 | m_functions.prepare = dfu_prepare_func_swap_erase; 397 | m_functions.cleared = dfu_cleared_func_swap; 398 | if (IS_UPDATING_BL(m_start_packet)) 399 | { 400 | m_functions.activate = dfu_activate_bl; 401 | } 402 | else 403 | { 404 | m_functions.activate = dfu_activate_app; 405 | } 406 | } 407 | 408 | switch (m_dfu_state) 409 | { 410 | case DFU_STATE_IDLE: 411 | // Valid peer activity detected. Hence restart the DFU timer. 412 | err_code = dfu_timer_restart(); 413 | if (err_code != NRF_SUCCESS) 414 | { 415 | return err_code; 416 | } 417 | m_functions.prepare(m_image_size); 418 | 419 | break; 420 | 421 | default: 422 | err_code = NRF_ERROR_INVALID_STATE; 423 | break; 424 | } 425 | 426 | return err_code; 427 | } 428 | 429 | 430 | uint32_t dfu_data_pkt_handle(dfu_update_packet_t * p_packet) 431 | { 432 | uint32_t data_length; 433 | uint32_t err_code; 434 | uint32_t * p_data; 435 | 436 | if (p_packet == NULL) 437 | { 438 | return NRF_ERROR_NULL; 439 | } 440 | 441 | // Check pointer alignment. 442 | if (!is_word_aligned(p_packet->params.data_packet.p_data_packet)) 443 | { 444 | // The p_data_packet is not word aligned address. 445 | return NRF_ERROR_INVALID_ADDR; 446 | } 447 | 448 | switch (m_dfu_state) 449 | { 450 | case DFU_STATE_RX_INIT_PKT: 451 | return NRF_ERROR_INVALID_STATE; 452 | 453 | case DFU_STATE_RDY: 454 | m_dfu_state = DFU_STATE_RX_DATA_PKT; 455 | /* fall through */ 456 | 457 | case DFU_STATE_RX_DATA_PKT: 458 | data_length = p_packet->params.data_packet.packet_length * sizeof(uint32_t); 459 | 460 | if ((m_data_received + data_length) > m_image_size) 461 | { 462 | // The caller is trying to write more bytes into the flash than the size provided to 463 | // the dfu_image_size_set function. This is treated as a serious error condition and 464 | // an unrecoverable one. Hence point the variable mp_app_write_address to the top of 465 | // the flash area. This will ensure that all future application data packet writes 466 | // will be blocked because of the above check. 467 | m_data_received = 0xFFFFFFFF; 468 | 469 | return NRF_ERROR_DATA_SIZE; 470 | } 471 | 472 | // Valid peer activity detected. Hence restart the DFU timer. 473 | err_code = dfu_timer_restart(); 474 | if (err_code != NRF_SUCCESS) 475 | { 476 | return err_code; 477 | } 478 | 479 | p_data = (uint32_t *)p_packet->params.data_packet.p_data_packet; 480 | 481 | err_code = pstorage_raw_store(mp_storage_handle_active, 482 | (uint8_t *)p_data, 483 | data_length, 484 | m_data_received); 485 | if (err_code != NRF_SUCCESS) 486 | { 487 | return err_code; 488 | } 489 | 490 | m_data_received += data_length; 491 | 492 | if (m_data_received != m_image_size) 493 | { 494 | // The entire image is not received yet. More data is expected. 495 | err_code = NRF_ERROR_INVALID_LENGTH; 496 | } 497 | else 498 | { 499 | // The entire image has been received. Return NRF_SUCCESS. 500 | err_code = NRF_SUCCESS; 501 | } 502 | break; 503 | 504 | default: 505 | err_code = NRF_ERROR_INVALID_STATE; 506 | break; 507 | } 508 | 509 | return err_code; 510 | } 511 | 512 | 513 | uint32_t dfu_init_pkt_complete(void) 514 | { 515 | uint32_t err_code = NRF_ERROR_INVALID_STATE; 516 | 517 | // DFU initialization has been done and a start packet has been received. 518 | if (IMAGE_WRITE_IN_PROGRESS()) 519 | { 520 | // Image write is already in progress. Cannot handle an init packet now. 521 | return NRF_ERROR_INVALID_STATE; 522 | } 523 | 524 | if (m_dfu_state == DFU_STATE_RX_INIT_PKT) 525 | { 526 | err_code = dfu_init_prevalidate(m_init_packet, m_init_packet_length); 527 | if (err_code == NRF_SUCCESS) 528 | { 529 | m_dfu_state = DFU_STATE_RX_DATA_PKT; 530 | } 531 | else 532 | { 533 | m_init_packet_length = 0; 534 | } 535 | } 536 | return err_code; 537 | } 538 | 539 | 540 | uint32_t dfu_init_pkt_handle(dfu_update_packet_t * p_packet) 541 | { 542 | uint32_t err_code = NRF_SUCCESS; 543 | uint32_t length; 544 | 545 | switch (m_dfu_state) 546 | { 547 | case DFU_STATE_RDY: 548 | m_dfu_state = DFU_STATE_RX_INIT_PKT; 549 | // When receiving init packet in state ready just update and fall through this case. 550 | 551 | case DFU_STATE_RX_INIT_PKT: 552 | // DFU initialization has been done and a start packet has been received. 553 | if (IMAGE_WRITE_IN_PROGRESS()) 554 | { 555 | // Image write is already in progress. Cannot handle an init packet now. 556 | return NRF_ERROR_INVALID_STATE; 557 | } 558 | 559 | // Valid peer activity detected. Hence restart the DFU timer. 560 | err_code = dfu_timer_restart(); 561 | if (err_code != NRF_SUCCESS) 562 | { 563 | return err_code; 564 | } 565 | 566 | length = p_packet->params.data_packet.packet_length * sizeof(uint32_t); 567 | if ((m_init_packet_length + length) > sizeof(m_init_packet)) 568 | { 569 | return NRF_ERROR_INVALID_LENGTH; 570 | } 571 | 572 | memcpy(&m_init_packet[m_init_packet_length], 573 | &p_packet->params.data_packet.p_data_packet[0], 574 | length); 575 | m_init_packet_length += length; 576 | break; 577 | 578 | default: 579 | // Either the start packet was not received or dfu_init function was not called before. 580 | err_code = NRF_ERROR_INVALID_STATE; 581 | break; 582 | } 583 | 584 | return err_code; 585 | } 586 | 587 | 588 | uint32_t dfu_image_validate() 589 | { 590 | uint32_t err_code; 591 | 592 | switch (m_dfu_state) 593 | { 594 | case DFU_STATE_RX_DATA_PKT: 595 | // Check if the application image write has finished. 596 | if (m_data_received != m_image_size) 597 | { 598 | // Image not yet fully transfered by the peer or the peer has attempted to write 599 | // too much data. Hence the validation should fail. 600 | err_code = NRF_ERROR_INVALID_STATE; 601 | } 602 | else 603 | { 604 | m_dfu_state = DFU_STATE_VALIDATE; 605 | 606 | // Valid peer activity detected. Hence restart the DFU timer. 607 | err_code = dfu_timer_restart(); 608 | if (err_code == NRF_SUCCESS) 609 | { 610 | err_code = dfu_init_postvalidate((uint8_t *)mp_storage_handle_active->block_id, 611 | m_image_size); 612 | if (err_code != NRF_SUCCESS) 613 | { 614 | return err_code; 615 | } 616 | 617 | m_dfu_state = DFU_STATE_WAIT_4_ACTIVATE; 618 | } 619 | } 620 | break; 621 | 622 | default: 623 | err_code = NRF_ERROR_INVALID_STATE; 624 | break; 625 | } 626 | 627 | return err_code; 628 | } 629 | 630 | 631 | uint32_t dfu_image_activate() 632 | { 633 | uint32_t err_code; 634 | 635 | switch (m_dfu_state) 636 | { 637 | case DFU_STATE_WAIT_4_ACTIVATE: 638 | 639 | // Stop the DFU Timer because the peer activity need not be monitored any longer. 640 | err_code = app_timer_stop(m_dfu_timer_id); 641 | APP_ERROR_CHECK(err_code); 642 | 643 | err_code = m_functions.activate(); 644 | break; 645 | 646 | default: 647 | err_code = NRF_ERROR_INVALID_STATE; 648 | break; 649 | } 650 | 651 | return err_code; 652 | } 653 | 654 | 655 | void dfu_reset(void) 656 | { 657 | dfu_update_status_t update_status; 658 | 659 | update_status.status_code = DFU_RESET; 660 | 661 | bootloader_dfu_update_process(update_status); 662 | } 663 | 664 | 665 | static uint32_t dfu_compare_block(uint32_t * ptr1, uint32_t * ptr2, uint32_t len) 666 | { 667 | sd_mbr_command_t sd_mbr_cmd; 668 | 669 | sd_mbr_cmd.command = SD_MBR_COMMAND_COMPARE; 670 | sd_mbr_cmd.params.compare.ptr1 = ptr1; 671 | sd_mbr_cmd.params.compare.ptr2 = ptr2; 672 | sd_mbr_cmd.params.compare.len = len / sizeof(uint32_t); 673 | 674 | return sd_mbr_command(&sd_mbr_cmd); 675 | } 676 | 677 | 678 | static uint32_t dfu_copy_sd(uint32_t * src, uint32_t * dst, uint32_t len) 679 | { 680 | sd_mbr_command_t sd_mbr_cmd; 681 | 682 | sd_mbr_cmd.command = SD_MBR_COMMAND_COPY_SD; 683 | sd_mbr_cmd.params.copy_sd.src = src; 684 | sd_mbr_cmd.params.copy_sd.dst = dst; 685 | sd_mbr_cmd.params.copy_sd.len = len / sizeof(uint32_t); 686 | 687 | return sd_mbr_command(&sd_mbr_cmd); 688 | } 689 | 690 | 691 | static uint32_t dfu_sd_img_block_swap(uint32_t * src, 692 | uint32_t * dst, 693 | uint32_t len, 694 | uint32_t block_size) 695 | { 696 | // It is neccesarry to swap the new SoftDevice in 3 rounds to ensure correct copy of data 697 | // and verifucation of data in case power reset occurs during write to flash. 698 | // To ensure the robustness of swapping the images are compared backwards till start of 699 | // image swap. If the back is identical everything is swapped. 700 | uint32_t err_code = dfu_compare_block(src, dst, len); 701 | if (err_code == NRF_SUCCESS) 702 | { 703 | return err_code; 704 | } 705 | 706 | if ((uint32_t)dst > SOFTDEVICE_REGION_START) 707 | { 708 | err_code = dfu_sd_img_block_swap((uint32_t *)((uint32_t)src - block_size), 709 | (uint32_t *)((uint32_t)dst - block_size), 710 | block_size, 711 | block_size); 712 | if (err_code != NRF_SUCCESS) 713 | { 714 | return err_code; 715 | } 716 | } 717 | 718 | err_code = dfu_copy_sd(src, dst, len); 719 | if (err_code != NRF_SUCCESS) 720 | { 721 | return err_code; 722 | } 723 | return dfu_compare_block(src, dst, len); 724 | } 725 | 726 | 727 | uint32_t dfu_sd_image_swap(void) 728 | { 729 | bootloader_settings_t boot_settings; 730 | 731 | bootloader_settings_get(&boot_settings); 732 | 733 | if (boot_settings.sd_image_size == 0) 734 | { 735 | return NRF_SUCCESS; 736 | } 737 | 738 | if ((SOFTDEVICE_REGION_START + boot_settings.sd_image_size) > boot_settings.sd_image_start) 739 | { 740 | uint32_t err_code; 741 | uint32_t sd_start = SOFTDEVICE_REGION_START; 742 | uint32_t block_size = (boot_settings.sd_image_start - sd_start) / 2; 743 | uint32_t image_end = boot_settings.sd_image_start + boot_settings.sd_image_size; 744 | 745 | uint32_t img_block_start = boot_settings.sd_image_start + 2 * block_size; 746 | uint32_t sd_block_start = sd_start + 2 * block_size; 747 | 748 | if (SOFTDEVICE_INFORMATION->softdevice_size < boot_settings.sd_image_size) 749 | { 750 | // This will clear a page thus ensuring the old image is invalidated before swapping. 751 | err_code = dfu_copy_sd((uint32_t *)(sd_start + block_size), 752 | (uint32_t *)(sd_start + block_size), 753 | sizeof(uint32_t)); 754 | if (err_code != NRF_SUCCESS) 755 | { 756 | return err_code; 757 | } 758 | 759 | err_code = dfu_copy_sd((uint32_t *)sd_start, (uint32_t *)sd_start, sizeof(uint32_t)); 760 | if (err_code != NRF_SUCCESS) 761 | { 762 | return err_code; 763 | } 764 | } 765 | 766 | return dfu_sd_img_block_swap((uint32_t *)img_block_start, 767 | (uint32_t *)sd_block_start, 768 | image_end - img_block_start, 769 | block_size); 770 | } 771 | else 772 | { 773 | if (boot_settings.sd_image_size != 0) 774 | { 775 | return dfu_copy_sd((uint32_t *)boot_settings.sd_image_start, 776 | (uint32_t *)SOFTDEVICE_REGION_START, 777 | boot_settings.sd_image_size); 778 | } 779 | } 780 | 781 | return NRF_SUCCESS; 782 | } 783 | 784 | 785 | uint32_t dfu_bl_image_swap(void) 786 | { 787 | bootloader_settings_t bootloader_settings; 788 | sd_mbr_command_t sd_mbr_cmd; 789 | 790 | bootloader_settings_get(&bootloader_settings); 791 | 792 | if (bootloader_settings.bl_image_size != 0) 793 | { 794 | uint32_t bl_image_start = (bootloader_settings.sd_image_size == 0) ? 795 | DFU_BANK_1_REGION_START : 796 | bootloader_settings.sd_image_start + 797 | bootloader_settings.sd_image_size; 798 | 799 | sd_mbr_cmd.command = SD_MBR_COMMAND_COPY_BL; 800 | sd_mbr_cmd.params.copy_bl.bl_src = (uint32_t *)(bl_image_start); 801 | sd_mbr_cmd.params.copy_bl.bl_len = bootloader_settings.bl_image_size / sizeof(uint32_t); 802 | 803 | return sd_mbr_command(&sd_mbr_cmd); 804 | } 805 | return NRF_SUCCESS; 806 | } 807 | 808 | 809 | uint32_t dfu_bl_image_validate(void) 810 | { 811 | bootloader_settings_t bootloader_settings; 812 | sd_mbr_command_t sd_mbr_cmd; 813 | 814 | bootloader_settings_get(&bootloader_settings); 815 | 816 | if (bootloader_settings.bl_image_size != 0) 817 | { 818 | uint32_t bl_image_start = (bootloader_settings.sd_image_size == 0) ? 819 | DFU_BANK_1_REGION_START : 820 | bootloader_settings.sd_image_start + 821 | bootloader_settings.sd_image_size; 822 | 823 | sd_mbr_cmd.command = SD_MBR_COMMAND_COMPARE; 824 | sd_mbr_cmd.params.compare.ptr1 = (uint32_t *)BOOTLOADER_REGION_START; 825 | sd_mbr_cmd.params.compare.ptr2 = (uint32_t *)(bl_image_start); 826 | sd_mbr_cmd.params.compare.len = bootloader_settings.bl_image_size / sizeof(uint32_t); 827 | 828 | return sd_mbr_command(&sd_mbr_cmd); 829 | } 830 | return NRF_SUCCESS; 831 | } 832 | 833 | 834 | uint32_t dfu_sd_image_validate(void) 835 | { 836 | bootloader_settings_t bootloader_settings; 837 | sd_mbr_command_t sd_mbr_cmd; 838 | 839 | bootloader_settings_get(&bootloader_settings); 840 | 841 | if (bootloader_settings.sd_image_size == 0) 842 | { 843 | return NRF_SUCCESS; 844 | } 845 | 846 | if ((SOFTDEVICE_REGION_START + bootloader_settings.sd_image_size) > bootloader_settings.sd_image_start) 847 | { 848 | uint32_t sd_start = SOFTDEVICE_REGION_START; 849 | uint32_t block_size = (bootloader_settings.sd_image_start - sd_start) / 2; 850 | uint32_t image_end = bootloader_settings.sd_image_start + 851 | bootloader_settings.sd_image_size; 852 | 853 | uint32_t img_block_start = bootloader_settings.sd_image_start + 2 * block_size; 854 | uint32_t sd_block_start = sd_start + 2 * block_size; 855 | 856 | if (SOFTDEVICE_INFORMATION->softdevice_size < bootloader_settings.sd_image_size) 857 | { 858 | return NRF_ERROR_NULL; 859 | } 860 | 861 | return dfu_sd_img_block_swap((uint32_t *)img_block_start, 862 | (uint32_t *)sd_block_start, 863 | image_end - img_block_start, 864 | block_size); 865 | } 866 | 867 | sd_mbr_cmd.command = SD_MBR_COMMAND_COMPARE; 868 | sd_mbr_cmd.params.compare.ptr1 = (uint32_t *)SOFTDEVICE_REGION_START; 869 | sd_mbr_cmd.params.compare.ptr2 = (uint32_t *)bootloader_settings.sd_image_start; 870 | sd_mbr_cmd.params.compare.len = bootloader_settings.sd_image_size / sizeof(uint32_t); 871 | 872 | return sd_mbr_command(&sd_mbr_cmd); 873 | } 874 | -------------------------------------------------------------------------------- /include/bootloader_settings.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2014 Nordic Semiconductor. All Rights Reserved. 2 | * 3 | * The information contained herein is property of Nordic Semiconductor ASA. 4 | * Terms and conditions of usage are described in detail in NORDIC 5 | * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. 6 | * 7 | * Licensees are granted free, non-transferable use of the information. NO 8 | * WARRANTY of ANY KIND is provided. This heading must NOT be removed from 9 | * the file. 10 | * 11 | */ 12 | 13 | /**@file 14 | * 15 | * @defgroup nrf_bootloader_settings Bootloader settings API. 16 | * @{ 17 | * 18 | * @brief Bootloader settings module interface. 19 | */ 20 | 21 | #ifndef BOOTLOADER_SETTINGS_H__ 22 | #define BOOTLOADER_SETTINGS_H__ 23 | 24 | #include 25 | #include "bootloader_types.h" 26 | 27 | /**@brief Function for getting the bootloader settings. 28 | * 29 | * @param[out] pp_bootloader_settings Bootloader settings. 30 | */ 31 | void bootloader_util_settings_get(const bootloader_settings_t ** pp_bootloader_settings); 32 | 33 | #endif // BOOTLOADER_SETTINGS_H__ 34 | 35 | /**@} */ 36 | -------------------------------------------------------------------------------- /include/pstorage_platform.h: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013 Nordic Semiconductor. All Rights Reserved. 2 | * 3 | * The information contained herein is property of Nordic Semiconductor ASA. 4 | * Terms and conditions of usage are described in detail in NORDIC 5 | * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. 6 | * 7 | * Licensees are granted free, non-transferable use of the information. NO 8 | * WARRANTY of ANY KIND is provided. This heading must NOT be removed from 9 | * the file. 10 | * 11 | */ 12 | 13 | /** @cond To make doxygen skip this file */ 14 | 15 | /** @file 16 | * This header contains defines with respect persistent storage that are specific to 17 | * persistent storage implementation and application use case. 18 | */ 19 | #ifndef PSTORAGE_PL_H__ 20 | #define PSTORAGE_PL_H__ 21 | 22 | #include 23 | 24 | #define PSTORAGE_FLASH_PAGE_SIZE ((uint16_t)NRF_FICR->CODEPAGESIZE) /**< Size of one flash page. */ 25 | #define PSTORAGE_FLASH_EMPTY_MASK 0xFFFFFFFF /**< Bit mask that defines an empty address in flash. */ 26 | 27 | #define PSTORAGE_FLASH_PAGE_END NRF_FICR->CODESIZE 28 | 29 | 30 | #define PSTORAGE_MAX_APPLICATIONS 1 /**< Maximum number of applications that can be registered with the module, configurable based on system requirements. */ 31 | #define PSTORAGE_MIN_BLOCK_SIZE 0x0010 /**< Minimum size of block that can be registered with the module. Should be configured based on system requirements, recommendation is not have this value to be at least size of word. */ 32 | 33 | #define PSTORAGE_DATA_START_ADDR ((PSTORAGE_FLASH_PAGE_END - PSTORAGE_MAX_APPLICATIONS) \ 34 | * PSTORAGE_FLASH_PAGE_SIZE) /**< Start address for persistent data, configurable according to system requirements. */ 35 | #define PSTORAGE_DATA_END_ADDR (PSTORAGE_FLASH_PAGE_END * PSTORAGE_FLASH_PAGE_SIZE) /**< End address for persistent data, configurable according to system requirements. */ 36 | #define PSTORAGE_SWAP_ADDR PSTORAGE_DATA_END_ADDR 37 | 38 | #define PSTORAGE_MAX_BLOCK_SIZE PSTORAGE_FLASH_PAGE_SIZE /**< Maximum size of block that can be registered with the module. Should be configured based on system requirements. And should be greater than or equal to the minimum size. */ 39 | #define PSTORAGE_CMD_QUEUE_SIZE 10 /**< Maximum number of flash access commands that can be maintained by the module for all applications. Configurable. */ 40 | 41 | /**@breif Define this flag in case Raw access to persistent memory is to be enabled. Raw mode 42 | * unlike the data mode is for uses other than storing data from various mode. This mode is 43 | * employed when unpdating firmware or similar uses. Therefore, this mode shall be enabled 44 | * only for these special usecases and typically disabled. 45 | */ 46 | #define PSTORAGE_RAW_MODE_ENABLE 47 | 48 | /** Abstracts persistently memory block identifier. */ 49 | typedef uint32_t pstorage_block_t; 50 | 51 | typedef struct 52 | { 53 | uint32_t module_id; /**< Module ID.*/ 54 | pstorage_block_t block_id; /**< Block ID.*/ 55 | } pstorage_handle_t; 56 | 57 | typedef uint32_t pstorage_size_t; /** Size of length and offset fields. */ 58 | 59 | /**@brief Handles Flash Access Result Events. To be called in the system event dispatcher of the application. */ 60 | void pstorage_sys_event_handler (uint32_t sys_evt); 61 | 62 | #endif // PSTORAGE_PL_H__ 63 | 64 | /** @} */ 65 | /** @endcond */ 66 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2013 Nordic Semiconductor. All Rights Reserved. 2 | * 3 | * The information contained herein is property of Nordic Semiconductor ASA. 4 | * Terms and conditions of usage are described in detail in NORDIC 5 | * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT. 6 | * 7 | * Licensees are granted free, non-transferable use of the information. NO 8 | * WARRANTY of ANY KIND is provided. This heading must NOT be removed from 9 | * the file. 10 | * 11 | */ 12 | 13 | /**@file 14 | * 15 | * @defgroup ble_sdk_app_bootloader_main main.c 16 | * @{ 17 | * @ingroup dfu_bootloader_api 18 | * @brief Bootloader project main file. 19 | * 20 | * -# Receive start data packet. 21 | * -# Based on start packet, prepare NVM area to store received data. 22 | * -# Receive data packet. 23 | * -# Validate data packet. 24 | * -# Write Data packet to NVM. 25 | * -# If not finished - Wait for next packet. 26 | * -# Receive stop data packet. 27 | * -# Activate Image, boot application. 28 | * 29 | */ 30 | #include "dfu_transport.h" 31 | #include "bootloader.h" 32 | #include "bootloader_util.h" 33 | #include 34 | #include 35 | #include 36 | #include "nordic_common.h" 37 | #include "nrf.h" 38 | #include "nrf_soc.h" 39 | #include "app_error.h" 40 | #include "nrf_gpio.h" 41 | #include "nrf51_bitfields.h" 42 | #include "ble.h" 43 | #include "nrf51.h" 44 | #include "ble_hci.h" 45 | #include "app_scheduler.h" 46 | #include "app_timer_appsh.h" 47 | #include "nrf_error.h" 48 | // #include "bsp.h" 49 | #include "softdevice_handler_appsh.h" 50 | #include "pstorage_platform.h" 51 | #include "nrf_mbr.h" 52 | 53 | // #if BUTTONS_NUMBER < 1 54 | // #error "Not enough buttons on board" 55 | // #endif 56 | 57 | // #if LEDS_NUMBER < 1 58 | // #error "Not enough LEDs on board" 59 | // #endif 60 | 61 | #define IS_SRVC_CHANGED_CHARACT_PRESENT 1 /**< Include the service_changed characteristic. For DFU this should normally be the case. */ 62 | 63 | // #define BOOTLOADER_BUTTON BSP_BUTTON_3 /**< Button used to enter SW update mode. */ 64 | #define UPDATE_IN_PROGRESS_LED BSP_LED_2 /**< Led used to indicate that DFU is active. */ 65 | 66 | #define APP_TIMER_PRESCALER 0 /**< Value of the RTC1 PRESCALER register. */ 67 | #define APP_TIMER_MAX_TIMERS 3 /**< Maximum number of simultaneously created timers. */ 68 | #define APP_TIMER_OP_QUEUE_SIZE 4 /**< Size of timer operation queues. */ 69 | 70 | #define BUTTON_DETECTION_DELAY APP_TIMER_TICKS(50, APP_TIMER_PRESCALER) /**< Delay from a GPIOTE event until a button is reported as pushed (in number of timer ticks). */ 71 | 72 | #define SCHED_MAX_EVENT_DATA_SIZE MAX(APP_TIMER_SCHED_EVT_SIZE, 0) /**< Maximum size of scheduler events. */ 73 | 74 | #define SCHED_QUEUE_SIZE 20 /**< Maximum number of events in the scheduler queue. */ 75 | 76 | 77 | /**@brief Callback function for asserts in the SoftDevice. 78 | * 79 | * @details This function will be called in case of an assert in the SoftDevice. 80 | * 81 | * @warning This handler is an example only and does not fit a final product. You need to analyze 82 | * how your product is supposed to react in case of Assert. 83 | * @warning On assert from the SoftDevice, the system can only recover on reset. 84 | * 85 | * @param[in] line_num Line number of the failing ASSERT call. 86 | * @param[in] file_name File name of the failing ASSERT call. 87 | */ 88 | void assert_nrf_callback(uint16_t line_num, const uint8_t * p_file_name) 89 | { 90 | app_error_handler(0xDEADBEEF, line_num, p_file_name); 91 | } 92 | 93 | 94 | /**@brief Function for initialization of LEDs. 95 | */ 96 | static void leds_init(void) 97 | { 98 | // nrf_gpio_cfg_output(UPDATE_IN_PROGRESS_LED); 99 | // nrf_gpio_pin_set(UPDATE_IN_PROGRESS_LED); 100 | } 101 | 102 | 103 | /**@brief Function for initializing the timer handler module (app_timer). 104 | */ 105 | static void timers_init(void) 106 | { 107 | // Initialize timer module, making it use the scheduler. 108 | APP_TIMER_APPSH_INIT(APP_TIMER_PRESCALER, APP_TIMER_MAX_TIMERS, APP_TIMER_OP_QUEUE_SIZE, true); 109 | } 110 | 111 | 112 | /**@brief Function for initializing the button module. 113 | */ 114 | static void buttons_init(void) 115 | { 116 | // nrf_gpio_cfg_sense_input(BOOTLOADER_BUTTON, 117 | // BUTTON_PULL, 118 | // NRF_GPIO_PIN_SENSE_LOW); 119 | 120 | } 121 | 122 | 123 | /**@brief Function for dispatching a BLE stack event to all modules with a BLE stack event handler. 124 | * 125 | * @details This function is called from the scheduler in the main loop after a BLE stack 126 | * event has been received. 127 | * 128 | * @param[in] p_ble_evt Bluetooth stack event. 129 | */ 130 | static void sys_evt_dispatch(uint32_t event) 131 | { 132 | pstorage_sys_event_handler(event); 133 | } 134 | 135 | 136 | /**@brief Function for initializing the BLE stack. 137 | * 138 | * @details Initializes the SoftDevice and the BLE event interrupt. 139 | * 140 | * @param[in] init_softdevice true if SoftDevice should be initialized. The SoftDevice must only 141 | * be initialized if a chip reset has occured. Soft reset from 142 | * application must not reinitialize the SoftDevice. 143 | */ 144 | static void ble_stack_init(bool init_softdevice) 145 | { 146 | uint32_t err_code; 147 | sd_mbr_command_t com = {SD_MBR_COMMAND_INIT_SD, }; 148 | 149 | if (init_softdevice) 150 | { 151 | err_code = sd_mbr_command(&com); 152 | APP_ERROR_CHECK(err_code); 153 | } 154 | 155 | err_code = sd_softdevice_vector_table_base_set(BOOTLOADER_REGION_START); 156 | APP_ERROR_CHECK(err_code); 157 | 158 | #if defined(TARGET_DELTA_DFCM_NNN40) || defined(TARGET_HRM1017) || defined(TARGET_NRF51_MICROBIT) 159 | /* Those targets don't use an external clock */ 160 | SOFTDEVICE_HANDLER_APPSH_INIT(NRF_CLOCK_LFCLKSRC_RC_250_PPM_250MS_CALIBRATION, true); 161 | #else 162 | SOFTDEVICE_HANDLER_APPSH_INIT(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM, true); 163 | #endif 164 | 165 | // Enable BLE stack 166 | ble_enable_params_t ble_enable_params; 167 | memset(&ble_enable_params, 0, sizeof(ble_enable_params)); 168 | ble_enable_params.gatts_enable_params.service_changed = IS_SRVC_CHANGED_CHARACT_PRESENT; 169 | err_code = sd_ble_enable(&ble_enable_params); 170 | APP_ERROR_CHECK(err_code); 171 | 172 | err_code = softdevice_sys_evt_handler_set(sys_evt_dispatch); 173 | APP_ERROR_CHECK(err_code); 174 | } 175 | 176 | 177 | /**@brief Function for event scheduler initialization. 178 | */ 179 | static void scheduler_init(void) 180 | { 181 | APP_SCHED_INIT(SCHED_MAX_EVENT_DATA_SIZE, SCHED_QUEUE_SIZE); 182 | } 183 | 184 | 185 | /**@brief Function for bootloader main entry. 186 | */ 187 | int main(void) 188 | { 189 | uint32_t err_code; 190 | bool dfu_start = false; 191 | bool app_reset = (NRF_POWER->GPREGRET == BOOTLOADER_DFU_START); 192 | 193 | if (app_reset) 194 | { 195 | NRF_POWER->GPREGRET = 0; 196 | } 197 | 198 | leds_init(); 199 | 200 | // This check ensures that the defined fields in the bootloader corresponds with actual 201 | // setting in the nRF51 chip. 202 | APP_ERROR_CHECK_BOOL(*((uint32_t *)NRF_UICR_BOOT_START_ADDRESS) == BOOTLOADER_REGION_START); 203 | APP_ERROR_CHECK_BOOL(NRF_FICR->CODEPAGESIZE == CODE_PAGE_SIZE); 204 | 205 | // Initialize. 206 | timers_init(); 207 | buttons_init(); 208 | 209 | (void)bootloader_init(); 210 | 211 | if (bootloader_dfu_sd_in_progress()) 212 | { 213 | // nrf_gpio_pin_clear(UPDATE_IN_PROGRESS_LED); 214 | 215 | err_code = bootloader_dfu_sd_update_continue(); 216 | APP_ERROR_CHECK(err_code); 217 | 218 | ble_stack_init(!app_reset); 219 | scheduler_init(); 220 | 221 | err_code = bootloader_dfu_sd_update_finalize(); 222 | APP_ERROR_CHECK(err_code); 223 | 224 | // nrf_gpio_pin_set(UPDATE_IN_PROGRESS_LED); 225 | } 226 | else 227 | { 228 | // If stack is present then continue initialization of bootloader. 229 | ble_stack_init(!app_reset); 230 | scheduler_init(); 231 | } 232 | 233 | dfu_start = app_reset; 234 | // dfu_start |= ((nrf_gpio_pin_read(BOOTLOADER_BUTTON) == 0) ? true: false); 235 | 236 | if (dfu_start || (!bootloader_app_is_valid(DFU_BANK_0_REGION_START))) 237 | { 238 | // nrf_gpio_pin_clear(UPDATE_IN_PROGRESS_LED); 239 | 240 | // Initiate an update of the firmware. 241 | err_code = bootloader_dfu_start(); 242 | APP_ERROR_CHECK(err_code); 243 | 244 | // nrf_gpio_pin_set(UPDATE_IN_PROGRESS_LED); 245 | } 246 | 247 | if (bootloader_app_is_valid(DFU_BANK_0_REGION_START) && !bootloader_dfu_sd_in_progress()) 248 | { 249 | // Select a bank region to use as application region. 250 | // @note: Only applications running from DFU_BANK_0_REGION_START is supported. 251 | bootloader_app_start(DFU_BANK_0_REGION_START); 252 | } 253 | 254 | NVIC_SystemReset(); 255 | } 256 | -------------------------------------------------------------------------------- /startup/arm_startup_nrf51.s: -------------------------------------------------------------------------------- 1 | ; Copyright (c) 2013, Nordic Semiconductor ASA 2 | ; All rights reserved. 3 | ; 4 | ; Redistribution and use in source and binary forms, with or without 5 | ; modification, are permitted provided that the following conditions are met: 6 | ; 7 | ; * Redistributions of source code must retain the above copyright notice, this 8 | ; list of conditions and the following disclaimer. 9 | ; 10 | ; * Redistributions in binary form must reproduce the above copyright notice, 11 | ; this list of conditions and the following disclaimer in the documentation 12 | ; and/or other materials provided with the distribution. 13 | ; 14 | ; * Neither the name of Nordic Semiconductor ASA nor the names of its 15 | ; contributors may be used to endorse or promote products derived from 16 | ; this software without specific prior written permission. 17 | ; 18 | ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | ; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | ; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | ; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | ; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | ; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | ; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | ; CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | ; OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | ; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | ; NOTE: Template files (including this one) are application specific and therefore 30 | ; expected to be copied into the application project folder prior to its use! 31 | 32 | ; Description message 33 | 34 | Stack_Size EQU 2048 35 | AREA STACK, NOINIT, READWRITE, ALIGN=3 36 | Stack_Mem SPACE Stack_Size 37 | __initial_sp 38 | 39 | Heap_Size EQU 1024 40 | 41 | AREA HEAP, NOINIT, READWRITE, ALIGN=3 42 | __heap_base 43 | Heap_Mem SPACE Heap_Size 44 | __heap_limit 45 | 46 | PRESERVE8 47 | THUMB 48 | 49 | ; Vector Table Mapped to Address 0 at Reset 50 | 51 | AREA RESET, DATA, READONLY 52 | EXPORT __Vectors 53 | EXPORT __Vectors_End 54 | EXPORT __Vectors_Size 55 | 56 | __Vectors DCD __initial_sp ; Top of Stack 57 | DCD Reset_Handler ; Reset Handler 58 | DCD NMI_Handler ; NMI Handler 59 | DCD HardFault_Handler ; Hard Fault Handler 60 | DCD 0 ; Reserved 61 | DCD 0 ; Reserved 62 | DCD 0 ; Reserved 63 | DCD 0 ; Reserved 64 | DCD 0 ; Reserved 65 | DCD 0 ; Reserved 66 | DCD 0 ; Reserved 67 | DCD SVC_Handler ; SVCall Handler 68 | DCD 0 ; Reserved 69 | DCD 0 ; Reserved 70 | DCD PendSV_Handler ; PendSV Handler 71 | DCD SysTick_Handler ; SysTick Handler 72 | 73 | ; External Interrupts 74 | DCD POWER_CLOCK_IRQHandler ;POWER_CLOCK 75 | DCD RADIO_IRQHandler ;RADIO 76 | DCD UART0_IRQHandler ;UART0 77 | DCD SPI0_TWI0_IRQHandler ;SPI0_TWI0 78 | DCD SPI1_TWI1_IRQHandler ;SPI1_TWI1 79 | DCD 0 ;Reserved 80 | DCD GPIOTE_IRQHandler ;GPIOTE 81 | DCD ADC_IRQHandler ;ADC 82 | DCD TIMER0_IRQHandler ;TIMER0 83 | DCD TIMER1_IRQHandler ;TIMER1 84 | DCD TIMER2_IRQHandler ;TIMER2 85 | DCD RTC0_IRQHandler ;RTC0 86 | DCD TEMP_IRQHandler ;TEMP 87 | DCD RNG_IRQHandler ;RNG 88 | DCD ECB_IRQHandler ;ECB 89 | DCD CCM_AAR_IRQHandler ;CCM_AAR 90 | DCD WDT_IRQHandler ;WDT 91 | DCD RTC1_IRQHandler ;RTC1 92 | DCD QDEC_IRQHandler ;QDEC 93 | DCD LPCOMP_IRQHandler ;LPCOMP 94 | DCD SWI0_IRQHandler ;SWI0 95 | DCD SWI1_IRQHandler ;SWI1 96 | DCD SWI2_IRQHandler ;SWI2 97 | DCD SWI3_IRQHandler ;SWI3 98 | DCD SWI4_IRQHandler ;SWI4 99 | DCD SWI5_IRQHandler ;SWI5 100 | DCD 0 ;Reserved 101 | DCD 0 ;Reserved 102 | DCD 0 ;Reserved 103 | DCD 0 ;Reserved 104 | DCD 0 ;Reserved 105 | DCD 0 ;Reserved 106 | 107 | 108 | __Vectors_End 109 | 110 | __Vectors_Size EQU __Vectors_End - __Vectors 111 | 112 | AREA |.text|, CODE, READONLY 113 | 114 | ; Reset Handler 115 | 116 | NRF_POWER_RAMON_ADDRESS EQU 0x40000524 ; NRF_POWER->RAMON address 117 | NRF_POWER_RAMON_RAMxON_ONMODE_Msk EQU 0x3 ; All RAM blocks on in onmode bit mask 118 | 119 | Reset_Handler PROC 120 | EXPORT Reset_Handler [WEAK] 121 | IMPORT SystemInit 122 | IMPORT __main 123 | LDR R0, =NRF_POWER_RAMON_ADDRESS 124 | LDR R2, [R0] 125 | MOVS R1, #NRF_POWER_RAMON_RAMxON_ONMODE_Msk 126 | ORRS R2, R2, R1 127 | STR R2, [R0] 128 | LDR R0, =SystemInit 129 | BLX R0 130 | LDR R0, =__main 131 | BX R0 132 | ENDP 133 | 134 | ; Dummy Exception Handlers (infinite loops which can be modified) 135 | 136 | NMI_Handler PROC 137 | EXPORT NMI_Handler [WEAK] 138 | B . 139 | ENDP 140 | HardFault_Handler\ 141 | PROC 142 | EXPORT HardFault_Handler [WEAK] 143 | B . 144 | ENDP 145 | SVC_Handler PROC 146 | EXPORT SVC_Handler [WEAK] 147 | B . 148 | ENDP 149 | PendSV_Handler PROC 150 | EXPORT PendSV_Handler [WEAK] 151 | B . 152 | ENDP 153 | SysTick_Handler PROC 154 | EXPORT SysTick_Handler [WEAK] 155 | B . 156 | ENDP 157 | 158 | Default_Handler PROC 159 | 160 | EXPORT POWER_CLOCK_IRQHandler [WEAK] 161 | EXPORT RADIO_IRQHandler [WEAK] 162 | EXPORT UART0_IRQHandler [WEAK] 163 | EXPORT SPI0_TWI0_IRQHandler [WEAK] 164 | EXPORT SPI1_TWI1_IRQHandler [WEAK] 165 | EXPORT GPIOTE_IRQHandler [WEAK] 166 | EXPORT ADC_IRQHandler [WEAK] 167 | EXPORT TIMER0_IRQHandler [WEAK] 168 | EXPORT TIMER1_IRQHandler [WEAK] 169 | EXPORT TIMER2_IRQHandler [WEAK] 170 | EXPORT RTC0_IRQHandler [WEAK] 171 | EXPORT TEMP_IRQHandler [WEAK] 172 | EXPORT RNG_IRQHandler [WEAK] 173 | EXPORT ECB_IRQHandler [WEAK] 174 | EXPORT CCM_AAR_IRQHandler [WEAK] 175 | EXPORT WDT_IRQHandler [WEAK] 176 | EXPORT RTC1_IRQHandler [WEAK] 177 | EXPORT QDEC_IRQHandler [WEAK] 178 | EXPORT LPCOMP_IRQHandler [WEAK] 179 | EXPORT SWI0_IRQHandler [WEAK] 180 | EXPORT SWI1_IRQHandler [WEAK] 181 | EXPORT SWI2_IRQHandler [WEAK] 182 | EXPORT SWI3_IRQHandler [WEAK] 183 | EXPORT SWI4_IRQHandler [WEAK] 184 | EXPORT SWI5_IRQHandler [WEAK] 185 | POWER_CLOCK_IRQHandler 186 | RADIO_IRQHandler 187 | UART0_IRQHandler 188 | SPI0_TWI0_IRQHandler 189 | SPI1_TWI1_IRQHandler 190 | GPIOTE_IRQHandler 191 | ADC_IRQHandler 192 | TIMER0_IRQHandler 193 | TIMER1_IRQHandler 194 | TIMER2_IRQHandler 195 | RTC0_IRQHandler 196 | TEMP_IRQHandler 197 | RNG_IRQHandler 198 | ECB_IRQHandler 199 | CCM_AAR_IRQHandler 200 | WDT_IRQHandler 201 | RTC1_IRQHandler 202 | QDEC_IRQHandler 203 | LPCOMP_IRQHandler 204 | SWI0_IRQHandler 205 | SWI1_IRQHandler 206 | SWI2_IRQHandler 207 | SWI3_IRQHandler 208 | SWI4_IRQHandler 209 | SWI5_IRQHandler 210 | 211 | B . 212 | ENDP 213 | ALIGN 214 | 215 | ; User Initial Stack & Heap 216 | 217 | IF :DEF:__MICROLIB 218 | 219 | EXPORT __initial_sp 220 | EXPORT __heap_base 221 | EXPORT __heap_limit 222 | 223 | ELSE 224 | 225 | IMPORT __use_two_region_memory 226 | EXPORT __user_initial_stackheap 227 | __user_initial_stackheap 228 | 229 | LDR R0, = Heap_Mem 230 | LDR R1, = (Stack_Mem + Stack_Size) 231 | LDR R2, = (Heap_Mem + Heap_Size) 232 | LDR R3, = Stack_Mem 233 | BX LR 234 | 235 | ALIGN 236 | 237 | ENDIF 238 | 239 | END 240 | 241 | --------------------------------------------------------------------------------